23.10.2012 Views

DB2 UDB for AS/400 SQL Programming Concepts - FTP Directory ...

DB2 UDB for AS/400 SQL Programming Concepts - FTP Directory ...

DB2 UDB for AS/400 SQL Programming Concepts - FTP Directory ...

SHOW MORE
SHOW LESS
  • TAGS
  • statement
  • using
  • value
  • column
  • function
  • sqlcode
  • program
  • sqlstate
  • statements
  • example
  • programming
  • concepts
  • directory
  • as400bks.rochester.ibm.com

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

START NOW

<strong>AS</strong>/<strong>400</strong>e<br />

<strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong><br />

<strong>Concepts</strong><br />

Version 4<br />

���


<strong>AS</strong>/<strong>400</strong>e<br />

<strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong><br />

<strong>Concepts</strong><br />

Version 4<br />

���


© Copyright International Business Machines Corporation 2000. All rights reserved.<br />

US Government Users Restricted Rights – Use, duplication or disclosure restricted by GSA ADP Schedule Contract<br />

with IBM Corp.


Contents<br />

About <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong><br />

<strong>Programming</strong> <strong>Concepts</strong> . . . . . . . vii<br />

Who should read this book . . . . . . . . . vii<br />

Assumptions relating to examples of <strong>SQL</strong><br />

statements. . . . . . . . . . . . . . vii<br />

How to interpret syntax diagrams in this guide viii<br />

What’s new in the V4R5 version of the <strong>SQL</strong><br />

programming concepts in<strong>for</strong>mation . . . . . . ix<br />

Chapter 1. Introduction to <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong><br />

<strong>AS</strong>/<strong>400</strong> Structured Query Language . . . 1<br />

<strong>SQL</strong> concepts . . . . . . . . . . . . . . 1<br />

<strong>SQL</strong> relational database and system terminology . 3<br />

Types of <strong>SQL</strong> statements . . . . . . . . . 4<br />

<strong>SQL</strong> objects . . . . . . . . . . . . . . . 5<br />

Collections . . . . . . . . . . . . . . 6<br />

Tables, Rows, and Columns . . . . . . . . 6<br />

Aliases . . . . . . . . . . . . . . . 7<br />

Views. . . . . . . . . . . . . . . . 7<br />

Indexes . . . . . . . . . . . . . . . 8<br />

Constraints . . . . . . . . . . . . . . 8<br />

Triggers . . . . . . . . . . . . . . . 8<br />

Stored Procedures . . . . . . . . . . . 9<br />

User-defined functions . . . . . . . . . . 9<br />

User-defined type. . . . . . . . . . . . 9<br />

<strong>SQL</strong> Packages . . . . . . . . . . . . . 9<br />

Application program objects . . . . . . . . . 9<br />

User source file member . . . . . . . . . 11<br />

Output source file member . . . . . . . . 11<br />

Program . . . . . . . . . . . . . . 11<br />

<strong>SQL</strong> Package . . . . . . . . . . . . . 12<br />

Module. . . . . . . . . . . . . . . 12<br />

Service program . . . . . . . . . . . . 12<br />

Chapter 2. Getting Started with <strong>SQL</strong> . . 13<br />

Starting interactive <strong>SQL</strong> . . . . . . . . . . 13<br />

Creating an <strong>SQL</strong> collection . . . . . . . . . 13<br />

Example: Creating the <strong>SQL</strong> Collection<br />

(SAMPLECOLL). . . . . . . . . . . . 14<br />

Creating and using a table . . . . . . . . . 14<br />

Example: Creating a table (INVENTORY_LIST) 14<br />

Creating the Supplier Table (SUPPLIERS) . . . 16<br />

Using the LABEL ON statement . . . . . . . 16<br />

Inserting in<strong>for</strong>mation into a table . . . . . . . 18<br />

Example: Inserting in<strong>for</strong>mation into a table<br />

(INVENTORY_LIST) . . . . . . . . . . 18<br />

Getting in<strong>for</strong>mation from a single table . . . . . 20<br />

Getting in<strong>for</strong>mation from more than one table . . . 23<br />

Changing in<strong>for</strong>mation in a table . . . . . . . 25<br />

Example: Changing in<strong>for</strong>mation in a table . . . 25<br />

Deleting in<strong>for</strong>mation from a table . . . . . . . 28<br />

Example: Deleting in<strong>for</strong>mation from a table<br />

(INVENTORY_LIST) . . . . . . . . . . 28<br />

Creating and using a view . . . . . . . . . 28<br />

Example: Creating a view on a single table . . . 29<br />

Example: Creating a view combining data from<br />

more than one table . . . . . . . . . . 30<br />

Chapter 3. Basic <strong>Concepts</strong> and<br />

Techniques . . . . . . . . . . . . . 31<br />

Using basic <strong>SQL</strong> statements and clauses . . . . . 31<br />

Inserting rows using the INSERT statement. . . 31<br />

Changing data in a table using the UPDATE<br />

statement . . . . . . . . . . . . . . 33<br />

Removing rows from a table using the DELETE<br />

statement . . . . . . . . . . . . . . 34<br />

Querying data using the SELECT INTO<br />

statement . . . . . . . . . . . . . . 35<br />

Data retrieval errors . . . . . . . . . . 37<br />

The SELECT clause . . . . . . . . . . . 38<br />

Specifying a search condition using the WHERE<br />

clause . . . . . . . . . . . . . . . 38<br />

The GROUP BY clause . . . . . . . . . 41<br />

HAVING clause . . . . . . . . . . . . 42<br />

ORDER BY clause . . . . . . . . . . . 43<br />

Null Values to indicate absence of column values in<br />

a row . . . . . . . . . . . . . . . . 45<br />

Special registers in <strong>SQL</strong> statements . . . . . . 45<br />

Date, Time, and Timestamp data types . . . . . 47<br />

Specifying current date and time values . . . . 47<br />

Date/Time arithmetic . . . . . . . . . . 47<br />

Creating and using ALI<strong>AS</strong> names . . . . . . . 48<br />

Creating descriptive labels using the LABEL ON<br />

statement . . . . . . . . . . . . . . . 48<br />

Describing an <strong>SQL</strong> object using COMMENT ON . . 49<br />

Getting comments after running a COMMENT<br />

ON statement . . . . . . . . . . . . 49<br />

Sort sequences in <strong>SQL</strong> . . . . . . . . . . . 50<br />

Sort sequence used with ORDER BY and record<br />

selection . . . . . . . . . . . . . . 50<br />

ORDER BY . . . . . . . . . . . . . 51<br />

Record selection . . . . . . . . . . . . 52<br />

Sort sequence and views . . . . . . . . . 53<br />

Sort Sequence and the CREATE INDEX<br />

Statement . . . . . . . . . . . . . . 53<br />

Sort sequence and constraints . . . . . . . 54<br />

Chapter 4. Using a Cursor . . . . . . 55<br />

Types of cursors . . . . . . . . . . . . . 55<br />

Serial cursor . . . . . . . . . . . . . 55<br />

Scrollable cursor . . . . . . . . . . . . 55<br />

Example of using a cursor . . . . . . . . . 56<br />

Step 1: Define the cursor . . . . . . . . . 58<br />

Step 2: Open the cursor . . . . . . . . . 59<br />

Step 3: Specify what to do when end-of-data is<br />

reached. . . . . . . . . . . . . . . 59<br />

Step 4: Retrieve a row using a cursor . . . . . 60<br />

Step 5a: Update the current row . . . . . . 61<br />

Step 5b: Delete the current row . . . . . . . 61<br />

Step 6: Close the cursor . . . . . . . . . 62<br />

© Copyright IBM Corp. 2000 iii


Using the multiple-row FETCH statement . . . . 62<br />

Multiple-row FETCH using a host structure array 63<br />

Multiple-row FETCH using a row storage area 64<br />

Unit of work and open cursors . . . . . . . . 67<br />

Chapter 5. Advanced Coding<br />

Techniques . . . . . . . . . . . . . 69<br />

Advanced insert techniques . . . . . . . . . 69<br />

Inserting rows into a table using a<br />

Select-Statement . . . . . . . . . . . . 69<br />

Inserting multiple rows in a table with the<br />

blocked INSERT statement . . . . . . . . 70<br />

Advanced update techniques . . . . . . . . 70<br />

Preventing duplicate rows . . . . . . . . . 71<br />

Per<strong>for</strong>ming complex search conditions . . . . . 72<br />

Keywords <strong>for</strong> use in search conditions . . . . 72<br />

Joining data from more than one table . . . . . 75<br />

Inner Join . . . . . . . . . . . . . . 75<br />

Left Outer Join . . . . . . . . . . . . 76<br />

Exception Join . . . . . . . . . . . . 77<br />

Cross Join . . . . . . . . . . . . . . 78<br />

Multiple join types in one statement . . . . . 78<br />

Notes on joins . . . . . . . . . . . . 79<br />

Specifying itermediate join tables using table<br />

expressions . . . . . . . . . . . . . . 79<br />

Using the UNION keyword to combine subselects 80<br />

Specifying UNION ALL . . . . . . . . . 83<br />

Subqueries in SELECT statements . . . . . . . 84<br />

Correlation . . . . . . . . . . . . . 85<br />

Subqueries and search conditions . . . . . . 85<br />

How subqueries are used. . . . . . . . . 86<br />

Using subqueries with UPDATE and DELETE . . 88<br />

Notes on using subqueries . . . . . . . . 88<br />

Correlated subqueries . . . . . . . . . . 88<br />

Using correlated subqueries in an UPDATE<br />

statement . . . . . . . . . . . . . . 91<br />

Using correlated subqueries in a DELETE<br />

statement . . . . . . . . . . . . . . 91<br />

Notes on using correlated subqueries . . . . . 92<br />

Changing a table definition . . . . . . . . . 92<br />

Adding a column . . . . . . . . . . . 92<br />

Changing a column. . . . . . . . . . . 93<br />

Allowable conversions. . . . . . . . . . 93<br />

Deleting a column . . . . . . . . . . . 94<br />

Order of operations <strong>for</strong> ALTER TABLE statement 94<br />

Creating and using views. . . . . . . . . . 95<br />

Adding indexes . . . . . . . . . . . . . 96<br />

Catalogs in database design . . . . . . . . . 97<br />

Getting catalog in<strong>for</strong>mation about a table . . . 97<br />

Getting catalog in<strong>for</strong>mation about a column . . 97<br />

Chapter 6. Data Integrity . . . . . . . 99<br />

Adding and using check constraints . . . . . . 99<br />

Referential integrity . . . . . . . . . . . 99<br />

Adding or dropping referential constraints . . 100<br />

Removing referential constraints . . . . . . 102<br />

Inserting into tables with referential constraints 102<br />

Updating tables with referential constraints . . 103<br />

Deleting from tables with referential constraints 105<br />

Check pending . . . . . . . . . . . . 107<br />

iv <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5<br />

|<br />

|<br />

WITH CHECK OPTION on a View . . . . . . 108<br />

WITH C<strong>AS</strong>CADED CHECK OPTION . . . . 108<br />

WITH LOCAL CHECK OPTION . . . . . . 109<br />

<strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> trigger support . . . . . 111<br />

Trigger sample . . . . . . . . . . . . 112<br />

Chapter 7. Stored Procedures . . . . 117<br />

Creating a procedure . . . . . . . . . . . 117<br />

Defining an external procedure . . . . . . . 117<br />

Defining an <strong>SQL</strong> procedure. . . . . . . . . 118<br />

Invoking a stored procedure . . . . . . . . 124<br />

Using CALL Statement where procedure<br />

definition exists . . . . . . . . . . . 124<br />

Using Embedded CALL Statement where no<br />

procedure definition exists . . . . . . . . 125<br />

Using Embedded CALL statement with an<br />

<strong>SQL</strong>DA . . . . . . . . . . . . . . 125<br />

Using Dynamic CALL Statement where no<br />

CREATE PROCEDURE exists . . . . . . . 127<br />

Parameter passing conventions <strong>for</strong> stored<br />

procedures . . . . . . . . . . . . . . 128<br />

Indicator variables and stored procedures . . . . 132<br />

Returning a completion status to the calling<br />

program . . . . . . . . . . . . . . . 135<br />

Examples of CALL statements . . . . . . . . 136<br />

Example 1: ILE C and PL/I procedures called<br />

from ILE C applications . . . . . . . . . 137<br />

Considerations <strong>for</strong> stored procedures that are<br />

written in Java . . . . . . . . . . . . . 145<br />

Coding a Java stored procedure that uses the<br />

JAVA parameter . . . . . . . . . . . 145<br />

Coding a Java stored procedure using the<br />

<strong>DB2</strong>GENERAL parameter style . . . . . . . 146<br />

Restrictions on Java stored procedures . . . . 147<br />

Chapter 8. Using the Object-Relational<br />

Capabilities . . . . . . . . . . . . 149<br />

Why use the <strong>DB2</strong> object extensions? . . . . . . 149<br />

<strong>DB2</strong> approach to supporting objects . . . . . . 150<br />

Using Large Objects (LOBs) . . . . . . . . 150<br />

Understanding large object data types (BLOB,<br />

CLOB, DBCLOB) . . . . . . . . . . . 151<br />

Understanding large object locators . . . . . 151<br />

Example: Using a locator to work with a CLOB<br />

value . . . . . . . . . . . . . . . 152<br />

Indicator variables and LOB locators . . . . 155<br />

LOB file reference variables . . . . . . . 155<br />

Example: Extracting a document to a file . . . 156<br />

Example: Inserting data into a CLOB column 158<br />

Display layout of LOB columns . . . . . . 158<br />

Journal entry layout of LOB columns . . . . 159<br />

User-defined functions (UDF) . . . . . . . . 160<br />

Why use UDFs? . . . . . . . . . . . 160<br />

UDF concepts . . . . . . . . . . . . 162<br />

Implementing UDFs . . . . . . . . . . 164<br />

Registering UDFs . . . . . . . . . . . 165<br />

Examples: Registering UDFs . . . . . . . 165<br />

Using UDFs . . . . . . . . . . . . . 168<br />

User-defined distinct types (UDT) . . . . . . 173<br />

Why use UDTs? . . . . . . . . . . . 173


|<br />

|<br />

|<br />

|<br />

|<br />

|<br />

Defining a UDT . . . . . . . . . . . 174<br />

Resolving unqualified UDTs . . . . . . . 174<br />

Examples: Using CREATE DISTINCT TYPE . . 175<br />

Defining tables with UDTs . . . . . . . . 175<br />

Manipulating UDTs . . . . . . . . . . 176<br />

Examples of manipulating UDTs . . . . . . 176<br />

Synergy between UDTs, UDFs, and LOBs . . . . 181<br />

Combining UDTs, UDFs, and LOBs . . . . . 181<br />

Examples of complex applications . . . . . 181<br />

Using DataLinks . . . . . . . . . . . . 184<br />

NO LINK CONTROL . . . . . . . . . 185<br />

FILE LINK CONTROL (with File System<br />

Permissions). . . . . . . . . . . . . 185<br />

FILE LINK CONTROL (with Database<br />

Permissions). . . . . . . . . . . . . 185<br />

Commands used <strong>for</strong> working with DataLinks 186<br />

Chapter 9. Writing User-Defined<br />

Functions (UDFs). . . . . . . . . . 189<br />

UDF runtime environment . . . . . . . . . 189<br />

Length of time that the UDF runs . . . . . 189<br />

Threads considerations . . . . . . . . . 190<br />

Parallel processing. . . . . . . . . . . 190<br />

Writing function code . . . . . . . . . . 190<br />

Writing UDFs as <strong>SQL</strong> functions . . . . . . 190<br />

Writing UDFs as external functions . . . . . 191<br />

Examples of UDF code . . . . . . . . . . 196<br />

Example: Square of a number UDF . . . . . 196<br />

Example: Counter . . . . . . . . . . . 198<br />

Chapter 10. Dynamic <strong>SQL</strong><br />

Applications . . . . . . . . . . . . 199<br />

Designing and running a dynamic <strong>SQL</strong> application 201<br />

Processing non-SELECT statements . . . . . . 202<br />

CCSID of dynamic <strong>SQL</strong> statements . . . . . 202<br />

Using the PREPARE and EXECUTE statements 202<br />

Processing SELECT statements and using an<br />

<strong>SQL</strong>DA . . . . . . . . . . . . . . . 203<br />

Fixed-list SELECT statements . . . . . . . 203<br />

Varying-list Select-statements . . . . . . . 204<br />

<strong>SQL</strong> Descriptor Area (<strong>SQL</strong>DA) . . . . . . 205<br />

<strong>SQL</strong>DA <strong>for</strong>mat . . . . . . . . . . . . 206<br />

Example: Select-statement <strong>for</strong> allocating storage<br />

<strong>for</strong> <strong>SQL</strong>DA . . . . . . . . . . . . . 210<br />

Using a cursor . . . . . . . . . . . . 214<br />

Parameter markers . . . . . . . . . . 215<br />

Chapter 11. Use of dynamic <strong>SQL</strong><br />

through client interfaces . . . . . . 217<br />

Accessing data with Java . . . . . . . . . 217<br />

Accessing data with Domino . . . . . . . . 217<br />

Accessing data with Open Database Connectivity<br />

(ODBC) . . . . . . . . . . . . . . . 217<br />

Chapter 12. Using Interactive <strong>SQL</strong> . . 219<br />

Basic functions of interactive <strong>SQL</strong> . . . . . . 219<br />

Starting interactive <strong>SQL</strong> . . . . . . . . . 220<br />

Using statement entry function . . . . . . 221<br />

Prompting . . . . . . . . . . . . . 221<br />

Using the list selection function . . . . . . 224<br />

Session services description . . . . . . . 226<br />

Exiting interactive <strong>SQL</strong> . . . . . . . . . 228<br />

Using an existing <strong>SQL</strong> session . . . . . . . 228<br />

Recovering an <strong>SQL</strong> session . . . . . . . . 228<br />

Accessing remote databases with interactive<br />

<strong>SQL</strong> . . . . . . . . . . . . . . . 229<br />

Chapter 13. Using the <strong>SQL</strong> Statement<br />

Processor . . . . . . . . . . . . . 231<br />

Execution of statements after errors occur . . . . 232<br />

Commitment control in the <strong>SQL</strong> statement<br />

processor . . . . . . . . . . . . . . . 232<br />

Schemas in the <strong>SQL</strong> Statement Processor . . . . 232<br />

Source member listing <strong>for</strong> the <strong>SQL</strong> statement<br />

processor . . . . . . . . . . . . . . . 233<br />

Chapter 14. <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> Data<br />

Protection . . . . . . . . . . . . . 235<br />

Security <strong>for</strong> <strong>SQL</strong> objects . . . . . . . . . . 235<br />

Authorization ID . . . . . . . . . . . 236<br />

Views . . . . . . . . . . . . . . . 236<br />

Auditing . . . . . . . . . . . . . . 236<br />

Data integrity . . . . . . . . . . . . . 237<br />

Concurrency. . . . . . . . . . . . . 237<br />

Journaling . . . . . . . . . . . . . 239<br />

Commitment control . . . . . . . . . . 239<br />

Atomic operations . . . . . . . . . . . 243<br />

Constraints . . . . . . . . . . . . . 245<br />

Save/Restore . . . . . . . . . . . . 245<br />

Damage tolerance . . . . . . . . . . . 246<br />

Index recovery . . . . . . . . . . . . 246<br />

Catalog integrity . . . . . . . . . . . 247<br />

User auxiliary storage pool (<strong>AS</strong>P) . . . . . 247<br />

Chapter 15. Testing <strong>SQL</strong> Statements<br />

in Application Programs. . . . . . . 249<br />

Establishing a test environment . . . . . . . 249<br />

Designing a test data structure . . . . . . 249<br />

Testing your <strong>SQL</strong> application programs. . . . . 250<br />

Program debug phase . . . . . . . . . 250<br />

Per<strong>for</strong>mance verification phase . . . . . . 251<br />

Chapter 16. Solving Common<br />

Database Problems . . . . . . . . . 253<br />

Paging through retrieved data . . . . . . . . 253<br />

Retrieving in reverse order . . . . . . . . . 253<br />

Establishing position at the end of a table . . . . 253<br />

Adding data to the end of a table . . . . . . 254<br />

Updating data as it is retrieved from a table . . . 254<br />

Restrictions . . . . . . . . . . . . . 255<br />

Updating data previously retrieved . . . . . . 256<br />

Changing the table definition . . . . . . . . 256<br />

Chapter 17. Distributed Relational<br />

Database Function . . . . . . . . . 257<br />

<strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> distributed relational<br />

database support . . . . . . . . . . . . 257<br />

Contents v


<strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> distributed relational<br />

database example program . . . . . . . . . 258<br />

<strong>SQL</strong> package support. . . . . . . . . . . 259<br />

Valid <strong>SQL</strong> statements in an <strong>SQL</strong> package . . . 260<br />

Considerations <strong>for</strong> creating an <strong>SQL</strong> package . . 260<br />

CCSID considerations <strong>for</strong> <strong>SQL</strong>. . . . . . . . 263<br />

Connection management and activation groups 263<br />

Connections and conversations . . . . . . 263<br />

Source code <strong>for</strong> PGM1: . . . . . . . . . 264<br />

Source code <strong>for</strong> PGM2: . . . . . . . . . 265<br />

Source code <strong>for</strong> PGM3: . . . . . . . . . 265<br />

Multiple connections to the same relational<br />

database . . . . . . . . . . . . . . 267<br />

Implicit connection management <strong>for</strong> the default<br />

activation group . . . . . . . . . . . 267<br />

Implicit connection management <strong>for</strong> nondefault<br />

activation groups . . . . . . . . . . . 268<br />

Distributed support . . . . . . . . . . . 268<br />

Determining connection type . . . . . . . 269<br />

Connect and commitment control restrictions 272<br />

Determining connection status. . . . . . . 273<br />

Distributed unit of work connection<br />

considerations . . . . . . . . . . . . 274<br />

Ending connections . . . . . . . . . . 275<br />

Distributed unit of work. . . . . . . . . . 276<br />

Managing distributed unit of work connections 276<br />

Cursors and prepared statements. . . . . . 278<br />

Application requester driver programs . . . . . 279<br />

Problem handling . . . . . . . . . . . . 279<br />

Appendix A. <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong><br />

Sample Tables . . . . . . . . . . . 281<br />

vi <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5<br />

Department Table (CORPDATA.DEPARTMENT) 281<br />

DEPARTMENT. . . . . . . . . . . . 282<br />

Employee Table (CORPDATA.EMPLOYEE) . . . 282<br />

Employee to Project Activity Table<br />

(CORPDATA.EMP_ACT) . . . . . . . . . 283<br />

EMP_ACT . . . . . . . . . . . . . 284<br />

Project Table (CORPDATA.PROJECT) . . . . . 286<br />

PROJECT. . . . . . . . . . . . . . 286<br />

Class Schedule Table (CL_SCHED) . . . . . . 287<br />

In Tray Table (IN_TRAY) . . . . . . . . . 287<br />

Appendix B. <strong>SQL</strong>CODEs and<br />

<strong>SQL</strong>STATEs . . . . . . . . . . . . 289<br />

<strong>SQL</strong>CODE and <strong>SQL</strong>STATE Descriptions . . . . 291<br />

Positive <strong>SQL</strong>CODEs . . . . . . . . . . 291<br />

Negative <strong>SQL</strong>CODEs . . . . . . . . . . 293<br />

Appendix C. <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> CL<br />

Command Descriptions . . . . . . . 307<br />

CRT<strong>SQL</strong>PKG (Create Structured Query Language<br />

Package) Command . . . . . . . . . . . 307<br />

DLT<strong>SQL</strong>PKG (Delete Structured Query Language<br />

Package) Command . . . . . . . . . . . 311<br />

RUN<strong>SQL</strong>STM (Run Structured Query Language<br />

Statement) Command . . . . . . . . . . 312<br />

STR<strong>SQL</strong> (Start Structured Query Language)<br />

Command . . . . . . . . . . . . . . 323<br />

Bibliography. . . . . . . . . . . . 331<br />

Index . . . . . . . . . . . . . . . 333


About <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong><br />

Who should read this book<br />

This book explains basic <strong>SQL</strong> programming concepts that show programmers and<br />

database administrators:<br />

v How to use the <strong>DB2</strong> <strong>SQL</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> licensed program<br />

v How to access data in a database<br />

v How to prepare, run, and test an application program that contains <strong>SQL</strong><br />

statements.<br />

For more in<strong>for</strong>mation on <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> guidelines and examples <strong>for</strong><br />

implementation in an application programming environment, see the following<br />

books in the Database and Files Systems category of the <strong>AS</strong>/<strong>400</strong>e In<strong>for</strong>mation<br />

Center:<br />

v <strong>SQL</strong> Reference<br />

v <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>for</strong> Host Languages<br />

v <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> Database Per<strong>for</strong>mance and Query Optimization<br />

v <strong>SQL</strong> Call Level Interface (ODBC)<br />

In addition, in<strong>for</strong>mation on advanced database functions can be found in:<br />

v DATAB<strong>AS</strong>E 2/<strong>400</strong> Advanced Database Functions, GG24-4249.<br />

This guide should be used by application programmers and database<br />

administrators who are familiar with and can program with COBOL <strong>for</strong> <strong>AS</strong>/<strong>400</strong>,<br />

ILE COBOL <strong>for</strong> <strong>AS</strong>/<strong>400</strong>, <strong>AS</strong>/<strong>400</strong> PL/I, ILE C <strong>for</strong> <strong>AS</strong>/<strong>400</strong>, ILE C++, VisualAge C++<br />

<strong>for</strong> <strong>AS</strong>/<strong>400</strong>, REXX, RPG III (part of RPG <strong>for</strong> <strong>AS</strong>/<strong>400</strong>), or ILE RPG <strong>for</strong> <strong>AS</strong>/<strong>400</strong><br />

language and who can understand basic database applications.<br />

Assumptions relating to examples of <strong>SQL</strong> statements<br />

The examples of <strong>SQL</strong> statements shown in this guide are based on the sample<br />

tables in Appendix A, ″<strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> Sample Tables,″ and assume the<br />

following:<br />

v They are shown in the interactive <strong>SQL</strong> environment or they are written in ILE C<br />

or in COBOL. EXEC <strong>SQL</strong> and END-EXEC are used to delimit an <strong>SQL</strong> statement<br />

in a COBOL program. A description of how to use <strong>SQL</strong> statements in a COBOL<br />

program is provided in ″Coding <strong>SQL</strong> Statements in COBOL Applications.″ A<br />

description of how to use <strong>SQL</strong> statements in an ILE C program is provided in<br />

″Coding <strong>SQL</strong> Statements in C Applications.″<br />

v Each <strong>SQL</strong> example is shown on several lines, with each clause of the statement<br />

on a separate line.<br />

v <strong>SQL</strong> keywords are highlighted.<br />

v Table names provided in Appendix A, ″<strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> Sample Tables,″<br />

use the collection CORPDATA. Table names that are not found in Appendix A,<br />

″<strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> Sample Tables,″ should use collections you create.<br />

v Calculated columns are enclosed in parentheses, (), and brackets, [].<br />

v The <strong>SQL</strong> naming convention is used.<br />

© Copyright IBM Corp. 2000 vii


v The APOST and APOST<strong>SQL</strong> precompiler options are assumed although they are<br />

not the default options in COBOL. Character string literals within <strong>SQL</strong> and host<br />

language statements are delimited by apostrophes (’).<br />

v A sort sequence of *HEX is used, unless otherwise noted.<br />

v The complete syntax of the <strong>SQL</strong> statement is usually not shown in any one<br />

example. For the complete description and syntax of any of the statements<br />

described in this guide, see the <strong>SQL</strong> Reference<br />

Whenever the examples vary from these assumptions, it is stated.<br />

Because this guide is <strong>for</strong> the application programmer, most of the examples are<br />

shown as if they were written in an application program. However, many<br />

examples can be slightly changed and run interactively by using interactive <strong>SQL</strong>.<br />

The syntax of an <strong>SQL</strong> statement, when using interactive <strong>SQL</strong>, differs slightly from<br />

the <strong>for</strong>mat of the same statement when it is embedded in a program.<br />

How to interpret syntax diagrams in this guide<br />

Throughout this book, syntax is described using the structure defined as follows:<br />

v Read the syntax diagrams from left to right, from top to bottom, following the<br />

path of the line.<br />

The ►►─── symbol indicates the beginning of a statement.<br />

The ───► symbol indicates that the statement syntax is continued on the next<br />

line.<br />

The ►─── symbol indicates that a statement is continued from the previous line.<br />

The ───►◄ symbol indicates the end of a statement.<br />

Diagrams of syntactical units other than complete statements start with the ►───<br />

symbol and end with the ───► symbol.<br />

v Required items appear on the horizontal line (the main path).<br />

►► required_item ►◄<br />

v Optional items appear below the main path.<br />

►► required_item<br />

optional_item<br />

If an optional item appears above the main path, that item has no effect on the<br />

execution of the statement and is used only <strong>for</strong> readability.<br />

►► required_item<br />

optional_item<br />

v If you can choose from two or more items, they appear vertically, in a stack.<br />

If you must choose one of the items, one item of the stack appears on the main<br />

path.<br />

viii <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5<br />

►◄<br />

►◄


►► required_item required_choice1<br />

required_choice2<br />

If choosing one of the items is optional, the entire stack appears below the main<br />

path.<br />

►► required_item<br />

optional_choice1<br />

optional_choice2<br />

If one of the items is the default, it will appear above the main path and the<br />

remaining choices will be shown below.<br />

►► required_item<br />

default_choice<br />

optional_choice<br />

optional_choice<br />

v An arrow returning to the left, above the main line, indicates an item that can be<br />

repeated.<br />

►► required_item ▼ repeatable_item ►◄<br />

If the repeat arrow contains a comma, you must separate repeated items with a<br />

comma.<br />

►► required_item ▼<br />

,<br />

repeatable_item ►◄<br />

A repeat arrow above a stack indicates that you can repeat the items in the<br />

stack.<br />

v Keywords appear in uppercase (<strong>for</strong> example, FROM). They must be spelled exactly<br />

as shown. Variables appear in all lowercase letters (<strong>for</strong> example, column-name).<br />

They represent user-supplied names or values.<br />

v If punctuation marks, parentheses, arithmetic operators, or other such symbols<br />

are shown, you must enter them as part of the syntax.<br />

What’s new in the V4R5 version of the <strong>SQL</strong> programming concepts<br />

in<strong>for</strong>mation<br />

The two major changes to this in<strong>for</strong>mation <strong>for</strong> this release were:<br />

v Providing in<strong>for</strong>mation on the big integer (BIGINT) data type<br />

v Providing in<strong>for</strong>mation on using Java stored procedures.<br />

About <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> ix<br />

►◄<br />

►◄<br />

►◄


x <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


Chapter 1. Introduction to <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> Structured<br />

Query Language<br />

<strong>SQL</strong> concepts<br />

These topics describe the <strong>AS</strong>/<strong>400</strong>* system implementation of the Structured Query<br />

Language (<strong>SQL</strong>) using <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> and the <strong>DB2</strong> <strong>UDB</strong> Query Manager<br />

and <strong>SQL</strong> Development Kit Version 4 licensed program. <strong>SQL</strong> manages in<strong>for</strong>mation<br />

based on the relational model of data. <strong>SQL</strong> statements can be embedded in<br />

high-level languages, dynamically prepared and run, or run interactively.<br />

<strong>SQL</strong> consists of statements and clauses that describe what you want to do with the<br />

data in a database and under what conditions you want to do it.<br />

This topic describes the following:<br />

v “<strong>SQL</strong> concepts”<br />

v “<strong>SQL</strong> objects” on page 5<br />

v “Application program objects” on page 9<br />

<strong>SQL</strong> can access data in a remote relational database, using the IBM Distributed<br />

Relational Database Architecture* (DRDA*). This function is described in<br />

Chapter 17. Distributed Relational Database Function, of this guide. Further<br />

in<strong>for</strong>mation about DRDA is contained in the Distributed Database <strong>Programming</strong><br />

book.<br />

<strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> consists of the following main parts:<br />

v <strong>SQL</strong> run-time support<br />

<strong>SQL</strong> run-time parses <strong>SQL</strong> statements and runs any <strong>SQL</strong> statements. This support<br />

is that part of the Operating System/<strong>400</strong>* (OS/<strong>400</strong>) licensed program which<br />

allows applications that contain <strong>SQL</strong> statements to be run on systems where the<br />

<strong>DB2</strong> <strong>UDB</strong> Query Manager and <strong>SQL</strong> Development Kit licensed program is not<br />

installed.<br />

v <strong>SQL</strong> precompilers<br />

<strong>SQL</strong> precompilers support precompiling embedded <strong>SQL</strong> statements in host<br />

languages. The following languages are supported:<br />

– ILE C <strong>for</strong> <strong>AS</strong>/<strong>400</strong>*<br />

– ILE C++ <strong>for</strong> <strong>AS</strong>/<strong>400</strong><br />

– VisualAge C++ <strong>for</strong> <strong>AS</strong>/<strong>400</strong><br />

– ILE COBOL <strong>for</strong> <strong>AS</strong>/<strong>400</strong>*<br />

– COBOL <strong>for</strong> <strong>AS</strong>/<strong>400</strong>*<br />

– <strong>AS</strong>/<strong>400</strong> PL/I*<br />

– RPG III (part of RPG <strong>for</strong> <strong>AS</strong>/<strong>400</strong>*)<br />

– ILE RPG <strong>for</strong> <strong>AS</strong>/<strong>400</strong>*<br />

The <strong>SQL</strong> host language precompilers prepare an application program containing<br />

<strong>SQL</strong> statements. The host language compilers then compile the precompiled host<br />

source programs. For more in<strong>for</strong>mation on precompiling, see the topic Preparing<br />

and Running a Program with <strong>SQL</strong> Statements in the <strong>SQL</strong> <strong>Programming</strong> with Host<br />

© Copyright IBM Corp. 2000 1


Languages in<strong>for</strong>mation. The precompiler support is part of the <strong>DB2</strong> <strong>UDB</strong> Query<br />

Manager and <strong>SQL</strong> Development Kit licensed program.<br />

v <strong>SQL</strong> interactive interface<br />

<strong>SQL</strong> interactive interface allows you to create and run <strong>SQL</strong> statements. For more<br />

in<strong>for</strong>mation on interactive <strong>SQL</strong>, see Chapter 12. Using Interactive <strong>SQL</strong>.<br />

Interactive <strong>SQL</strong> is part of the <strong>DB2</strong> <strong>UDB</strong> Query Manager and <strong>SQL</strong> Development<br />

Kit licensed program.<br />

v Run <strong>SQL</strong> Statements CL command<br />

RUN<strong>SQL</strong>STM allows you to run a series of <strong>SQL</strong> statements, which are stored in<br />

a source file. The RUN<strong>SQL</strong>STM command is part of the <strong>DB2</strong> <strong>UDB</strong> Query<br />

Manager and <strong>SQL</strong> Development Kit licensed program. See Chapter 13. Using the<br />

<strong>SQL</strong> Statement Processor <strong>for</strong> more in<strong>for</strong>mation on the Run <strong>SQL</strong> Statements<br />

command.<br />

v <strong>DB2</strong> Query Manager <strong>for</strong> <strong>AS</strong>/<strong>400</strong><br />

<strong>DB2</strong> Query Manager <strong>for</strong> <strong>AS</strong>/<strong>400</strong> provides a prompt-driven interactive interface<br />

that allows you to create data, add data, maintain data, and run reports on the<br />

databases. Query Manager is part of the <strong>DB2</strong> <strong>UDB</strong> Query Manager and <strong>SQL</strong><br />

Development Kit licensed program. For more in<strong>for</strong>mation, refer to the Query<br />

Manager Use book.<br />

v <strong>SQL</strong> REXX Interface<br />

The <strong>SQL</strong> REXX interface allows you to run <strong>SQL</strong> statements in a REXX<br />

procedure. This interface is part of the <strong>DB2</strong> <strong>UDB</strong> Query Manager and <strong>SQL</strong><br />

Development Kit licensed program. For more in<strong>for</strong>mation on using <strong>SQL</strong><br />

statements in REXX procedures, see the topic Coding <strong>SQL</strong> Statements in REXX<br />

Applications in the <strong>SQL</strong> <strong>Programming</strong> with Host Languages in<strong>for</strong>mation.<br />

v <strong>SQL</strong> Call Level Interface<br />

<strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> supports the <strong>SQL</strong> Call Level Interface. This allows users of<br />

any of the ILE languages to access <strong>SQL</strong> functions directly through procedure<br />

calls to a service program provided by the system. Using the <strong>SQL</strong> Call Level<br />

Interface, one can per<strong>for</strong>m all the <strong>SQL</strong> functions without the need <strong>for</strong> a<br />

precompile. This is a standard set of procedure calls to prepare <strong>SQL</strong> statements,<br />

execute <strong>SQL</strong> statements, fetch rows of data, and even do advanced functions<br />

such as accessing the catalogs and binding program variables to output columns.<br />

For a complete description of all the available functions, and their syntax, see<br />

the <strong>SQL</strong> Call Level Interface (ODBC) book.<br />

v QSQPRCED API<br />

This Application Program Interface (API) provides an extended dynamic <strong>SQL</strong><br />

capability. <strong>SQL</strong> statements can be prepared into an <strong>SQL</strong> package and then<br />

executed using this API. Statements prepared into a package by this API persist<br />

until the package or statement is explicitly dropped. QSQPRCED is part of the<br />

OS/<strong>400</strong> licensed program. For more in<strong>for</strong>mation on the QSQPRCED API, see the<br />

OS/<strong>400</strong> API book.<br />

v QSQCHKS API<br />

This API syntax checks <strong>SQL</strong> statements. QSQCHKS is part of the OS/<strong>400</strong><br />

licensed program. For more in<strong>for</strong>mation on the QSQCHKS API, see the OS/<strong>400</strong><br />

API book.<br />

v <strong>DB2</strong> Multisystem<br />

This feature of the operating system allows your data to be distributed across<br />

multiple <strong>AS</strong>/<strong>400</strong> systems. For more in<strong>for</strong>mation on <strong>DB2</strong> Multisystem, see the<br />

<strong>DB2</strong> Multisystem book.<br />

v <strong>DB2</strong> <strong>UDB</strong> Symmetric Multiprocessing<br />

2 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


This feature of the operating system provides the query optimizer with<br />

additional methods <strong>for</strong> retrieving data that include parallel processing.<br />

Symmetric multiprocessing (SMP) is a <strong>for</strong>m of parallelism achieved on a single<br />

system where multiple processors (CPU and I/O processors) that share memory<br />

and disk resource work simultaneously towards achieving a single end result.<br />

This parallel processing means that the database manager can have more than<br />

one (or all) of the system processors working on a single query simultaneously.<br />

See the topic Controlling Parallel Processing in the Database Per<strong>for</strong>mance and<br />

Query Optimization in<strong>for</strong>mation <strong>for</strong> details on how to control parallel processing.<br />

<strong>SQL</strong> relational database and system terminology<br />

In the relational model of data, all data is perceived as existing in tables. <strong>DB2</strong> <strong>UDB</strong><br />

<strong>for</strong> <strong>AS</strong>/<strong>400</strong> objects are created and maintained as <strong>AS</strong>/<strong>400</strong> system objects. The<br />

following table shows the relationship between <strong>AS</strong>/<strong>400</strong> system terms and <strong>SQL</strong><br />

relational database terms. For more in<strong>for</strong>mation on database, see the Database<br />

<strong>Programming</strong> book.<br />

Table 1. Relationship of System Terms to <strong>SQL</strong> Terms<br />

System Terms <strong>SQL</strong> Terms<br />

Library. Groups related objects and allows Collection. Consists of a library, a journal, a<br />

you to find the objects by name.<br />

journal receiver, an <strong>SQL</strong> catalog, and<br />

optionally a data dictionary. A collection<br />

groups related objects and allows you to<br />

find the objects by name.<br />

Physical file. A set of records. Table. A set of columns and rows.<br />

Record. A set of fields. Row. The horizontal part of a table<br />

containing a serial set of columns.<br />

Field. One or more characters of related Column. The vertical part of a table of one<br />

in<strong>for</strong>mation of one data type.<br />

data type.<br />

Logical file. A subset of fields and records View. A subset of columns and rows of one<br />

of one or more physical files.<br />

or more tables.<br />

<strong>SQL</strong> Package. An object type that is used to Package. An object type that is used to run<br />

run <strong>SQL</strong> statements.<br />

<strong>SQL</strong> statements.<br />

User Profile Authorization name or Authorization ID.<br />

<strong>SQL</strong> and system naming conventions<br />

There are two naming conventions that can be used in <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong><br />

programming: system (*SYS) and <strong>SQL</strong> (*<strong>SQL</strong>). The naming convention used affects<br />

the method <strong>for</strong> qualifying file and table names and the terms used on the<br />

interactive <strong>SQL</strong> displays. The naming convention used is selected by a parameter<br />

on the <strong>SQL</strong> commands or, <strong>for</strong> REXX, selected through the SET OPTION statement.<br />

System naming (*SYS): In the system naming convention, files are qualified by<br />

library name in the <strong>for</strong>m:<br />

library/file<br />

If the table name is not explicitly qualified and a default collection name is<br />

specified <strong>for</strong> the default relational database collection (DFTRDBCOL) parameter of<br />

Chapter 1. Introduction to <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> Structured Query Language 3


the CRT<strong>SQL</strong>xxx 1 or the CRT<strong>SQL</strong>PKG commands, the default collection name is<br />

used. If the table name is not explicitly qualified and the default collection name is<br />

not specified, the qualification rules are:<br />

v The following CREATE statements resolve to unqualified objects as follows:<br />

– CREATE TABLE – The table is created in the current library (*CURLIB).<br />

– CREATE VIEW – The view is created in the first library referenced in the<br />

subselect.<br />

– CREATE INDEX – The index is created into the collection or library that<br />

contains the table on which the index is being built.<br />

– CREATE ALI<strong>AS</strong> – The alias is created into the collection or library that<br />

contains the table <strong>for</strong> which you defined the alias. If the table is not qualified<br />

or is not found, the alias is created in the current library (*CURLIB).<br />

v All other <strong>SQL</strong> statements cause <strong>SQL</strong> to search the library list (*LIBL) <strong>for</strong> the<br />

unqualified table.<br />

The default relational database collection (DFTRDBCOL) parameter applies only to<br />

static <strong>SQL</strong> statements.<br />

<strong>SQL</strong> naming (*<strong>SQL</strong>): In the <strong>SQL</strong> naming convention, tables are qualified by the<br />

collection name in the <strong>for</strong>m:<br />

collection.table<br />

If the table name is not explicitly qualified and the default collection name is<br />

specified in the default relational database collection (DFTRDBCOL) parameter of<br />

the CRT<strong>SQL</strong>xxx command, the default collection name is used. If the table name is<br />

not explicitly qualified and the default collection name is not specified, the rules<br />

are:<br />

v For static <strong>SQL</strong>, the default qualifier is the user profile of the program owner.<br />

v For dynamic <strong>SQL</strong> or interactive <strong>SQL</strong>, the default qualifier is the user profile of<br />

the job running the statement.<br />

Types of <strong>SQL</strong> statements<br />

There are four basic types of <strong>SQL</strong> statements: data definition language (DDL)<br />

statements, data manipulation language (DML) statements, dynamic <strong>SQL</strong><br />

statements, and miscellaneous statements. <strong>SQL</strong> statements can operate on objects<br />

that are created by <strong>SQL</strong> as well as <strong>AS</strong>/<strong>400</strong> externally described physical files and<br />

<strong>AS</strong>/<strong>400</strong> single-<strong>for</strong>mat logical files, whether or not they reside in an <strong>SQL</strong> collection.<br />

They do not refer to the IDDU dictionary definition <strong>for</strong> program-described files.<br />

Program-described files appear as a table with only a single column.<br />

1. The xxx in this command refers to the host language indicators: CI <strong>for</strong> the ILE C <strong>for</strong> <strong>AS</strong>/<strong>400</strong> language, CPPI <strong>for</strong> the ILE C++ <strong>for</strong><br />

<strong>AS</strong>/<strong>400</strong> language, CBL <strong>for</strong> the COBOL <strong>for</strong> <strong>AS</strong>/<strong>400</strong> language, CBLI <strong>for</strong> the ILE COBOL <strong>for</strong> <strong>AS</strong>/<strong>400</strong> language, PLI <strong>for</strong> the <strong>AS</strong>/<strong>400</strong><br />

PL/I language, RPG <strong>for</strong> the RPG <strong>for</strong> <strong>AS</strong>/<strong>400</strong> language, and RPGI <strong>for</strong> the ILE RPG <strong>for</strong> <strong>AS</strong>/<strong>400</strong> language. The CVT<strong>SQL</strong>CPP<br />

command is considered part of this group of commands even though it does not start with CRT.<br />

4 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


<strong>SQL</strong> objects<br />

<strong>SQL</strong> DDL Statements <strong>SQL</strong> DML Statements<br />

ALTER TABLE<br />

COMMENT ON<br />

CREATE ALI<strong>AS</strong><br />

CREATE COLLECTION<br />

CREATE DISTINCT TYPE<br />

CREATE FUNCTION<br />

CREATE INDEX<br />

CREATE PROCEDURE<br />

CREATE SCHEMA<br />

CREATE TABLE<br />

CREATE VIEW<br />

DROP ALI<strong>AS</strong><br />

DROP COLLECTION<br />

DROP DISTINCT TYPE<br />

DROP FUNCTION<br />

DROP INDEX<br />

DROP PACKAGE<br />

DROP PROCEDURE<br />

DROP SCHEMA<br />

DROP TABLE<br />

DROP VIEW<br />

GRANT DISTINCT TYPE<br />

GRANT FUNCTION<br />

GRANT PACKAGE<br />

GRANT PROCEDURE<br />

GRANT TABLE<br />

LABEL ON<br />

RENAME<br />

REVOKE DISTINCT TYPE<br />

REVOKE FUNCTION<br />

REVOKE PACKAGE<br />

REVOKE PROCEDURE<br />

REVOKE TABLE<br />

CLOSE<br />

COMMIT<br />

DECLARE CURSOR<br />

DELETE<br />

FETCH<br />

INSERT<br />

LOCK TABLE<br />

OPEN<br />

ROLLBACK<br />

SELECT INTO<br />

SET variable<br />

UPDATE<br />

VALUES INTO<br />

Dynamic <strong>SQL</strong> Statements Miscellaneous Statements<br />

DESCRIBE<br />

EXECUTE<br />

EXECUTE IMMEDIATE<br />

PREPARE<br />

BEGIN DECLARE SECTION<br />

CALL<br />

CONNECT<br />

DECLARE PROCEDURE<br />

DECLARE STATEMENT<br />

DECLARE VARIABLE<br />

DESCRIBE TABLE<br />

DISCONNECT<br />

END DECLARE SECTION<br />

FREE LOCATOR<br />

INCLUDE<br />

RELE<strong>AS</strong>E<br />

SET CONNECTION<br />

SET OPTION<br />

SET PATH<br />

SET RESULT SETS<br />

SET TRANSACTION<br />

WHENEVER<br />

<strong>SQL</strong> objects used on the <strong>AS</strong>/<strong>400</strong> system are collections, tables, aliases, views, <strong>SQL</strong><br />

packages, indexes, and catalogs. <strong>SQL</strong> creates and maintains these objects as <strong>AS</strong>/<strong>400</strong><br />

database objects. A brief description of these objects follows.<br />

Chapter 1. Introduction to <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> Structured Query Language 5


Collections<br />

A collection provides a logical grouping of <strong>SQL</strong> objects. A collection consists of a<br />

library, a journal, a journal receiver, a catalog, and optionally, a data dictionary.<br />

Tables, views, and system objects (such as programs) can be created, moved, or<br />

restored into any <strong>AS</strong>/<strong>400</strong> library. All <strong>AS</strong>/<strong>400</strong> files can be created or moved into an<br />

<strong>SQL</strong> collection if the <strong>SQL</strong> collection does not contain a data dictionary. If the <strong>SQL</strong><br />

collection contains a data dictionary then:<br />

v <strong>AS</strong>/<strong>400</strong> source physical files or nonsource physical files with one member can be<br />

created, moved, or restored into an <strong>SQL</strong> collection.<br />

v <strong>AS</strong>/<strong>400</strong> logical files cannot be placed in an <strong>SQL</strong> collection because they cannot<br />

be described in the data dictionary.<br />

You can create and own many collections.<br />

Data Dictionary<br />

A collection contains a data dictionary if it was created prior to Version 3 Release 1<br />

or if the WITH DATA DICTIONARY clause was specified on the CREATE<br />

COLLECTION or the CREATE SCHEMA statements. A data dictionary is a set of<br />

tables containing object definitions. If <strong>SQL</strong> created the dictionary, then it is<br />

automatically maintained by the system. You can work with data dictionaries by<br />

using the interactive data definition utility (IDDU), which is part of the OS/<strong>400</strong><br />

program. For more in<strong>for</strong>mation on IDDU, see the IDDU Use book.<br />

Journals and Journal Receivers<br />

A journal and journal receiver are used to record changes to tables and views in<br />

the database. The journal and journal receiver are then used in processing <strong>SQL</strong><br />

COMMIT and ROLLBACK statements. The journal and journal receiver can also be<br />

used as an audit trail or <strong>for</strong> <strong>for</strong>ward or backward recovery. For more in<strong>for</strong>mation<br />

on journaling, see the Backup and Recovery book.<br />

Catalogs<br />

An <strong>SQL</strong> catalog consists of a set of tables and views which describe tables, views,<br />

indexes, packages, procedures, files, and constraints. This in<strong>for</strong>mation is contained<br />

in a set of cross-reference tables in libraries QSYS and QSYS2. Library QSYS2 also<br />

contains a set of catalog views built over the QSYS catalog tables which describe<br />

in<strong>for</strong>mation about all the tables, views, indexes, packages, procedures, files, and<br />

constraints on the system. In each <strong>SQL</strong> collection there is a set of views built over<br />

the catalog tables which contains in<strong>for</strong>mation about the tables, views, indexes,<br />

packages, files, and constraints in the collection.<br />

A catalog is automatically created when you create a collection. You cannot drop or<br />

explicitly change the catalog.<br />

For more in<strong>for</strong>mation about <strong>SQL</strong> catalogs, see the <strong>SQL</strong> Reference book.<br />

Tables, Rows, and Columns<br />

A table is a two-dimensional arrangement of data consisting of rows and columns.<br />

The row is the horizontal part containing one or more columns. The column is the<br />

vertical part containing one or more rows of data of one data type. All data <strong>for</strong> a<br />

6 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


Aliases<br />

Views<br />

column must be of the same type. A table in <strong>SQL</strong> is a keyed or nonkeyed physical<br />

file. See the section on data types in the <strong>SQL</strong> Reference book <strong>for</strong> a description of<br />

data types.<br />

Data in a table can be distributed across <strong>AS</strong>/<strong>400</strong> systems. For more in<strong>for</strong>mation<br />

about distributed tables, see the <strong>DB2</strong> Multisystem book.<br />

The following is a sample <strong>SQL</strong> table:<br />

Rows<br />

PROJNO PROJNAME<br />

MA2100<br />

MA2110<br />

MA2112<br />

... ...<br />

An alias is an alternate name <strong>for</strong> a table or view. You can use an alias to refer to a<br />

table or view in those cases where an existing table or view can be referred to. For<br />

more in<strong>for</strong>mation on aliases, see the <strong>SQL</strong> Reference book.<br />

A view appears like a table to an application program; however, a view contains<br />

no data. It is created over one or more tables. A view can contain all the columns<br />

of given tables or some subset of them, and can contain all the rows of given tables<br />

or some subset of them. The columns can be arranged differently in a view than<br />

they are in the tables from which they are taken. A view in <strong>SQL</strong> is a special <strong>for</strong>m<br />

of a nonkeyed logical file.<br />

The following figure shows a view created from the preceding example of an <strong>SQL</strong><br />

table. Notice that the view is created only over the PROJNO and PROJNAME<br />

columns of the table and <strong>for</strong> rows MA2110 and MA2100.<br />

Rows<br />

Columns<br />

MA2113<br />

Columns<br />

MFG AUTOMATION<br />

MFG PROGRAMMING<br />

ROBOT DESIGN<br />

PROJNO PROJNAME<br />

PROD CONTROL PROG<br />

MA2100 MFG AUTOMATION<br />

MA2110 MFG PROGRAMMING<br />

RV2W574-0<br />

DEPTNO DEPTMGR PRSTAFF<br />

D11<br />

E21<br />

E01<br />

D11<br />

...<br />

000060<br />

000100<br />

000050<br />

000060<br />

...<br />

12<br />

3<br />

3<br />

3<br />

...<br />

RV2W573-0<br />

Chapter 1. Introduction to <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> Structured Query Language 7


Indexes<br />

Constraints<br />

Triggers<br />

An <strong>SQL</strong> index is a subset of the data in the columns of a table that are logically<br />

arranged in either ascending or descending order. Each index contains a separate<br />

arrangement. These arrangements are used <strong>for</strong> ordering (ORDER BY clause),<br />

grouping (GROUP BY clause), and joining. An <strong>SQL</strong> index is a keyed logical file.<br />

The index is used by the system <strong>for</strong> faster data retrieval. Creating an index is<br />

optional. You can create any number of indexes. You can create or drop an index at<br />

any time. The index is automatically maintained by the system. However, because<br />

the indexes are maintained by the system, a large number of indexes can adversely<br />

affect the per<strong>for</strong>mance of applications that change the table.<br />

Constraints are rules en<strong>for</strong>ced by the database manager. <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong><br />

supports the following constraints:<br />

v Unique constraints<br />

A unique constraint is the rule that the values of the key are valid only if they<br />

are unique. Unique constraints can be created using the CREATE TABLE and<br />

ALTER TABLE statements. 2<br />

Unique constraints are en<strong>for</strong>ced during the execution of INSERT and UPDATE<br />

statements. A PRIMARY KEY constraint is a <strong>for</strong>m of UNIQUE constraint. The<br />

difference is that a PRIMARY KEY cannot contain any nullable columns.<br />

v Referential constraints<br />

A referential constraint is the rule that the values of the <strong>for</strong>eign key are valid<br />

only if:<br />

– They appear as values of a parent key, or<br />

– Some component of the <strong>for</strong>eign key is null.<br />

Referential constraints are en<strong>for</strong>ced during the execution of INSERT, UPDATE,<br />

and DELETE statements.<br />

v Check constraints<br />

A check constraint is a rule that limits the values allowed in a column or group<br />

of columns. Check constraints can be added using the CREATE TABLE and<br />

ALTER TABLE statements. Check constraints are en<strong>for</strong>ced during the execution<br />

of INSERT and UPDATE statements. To satisfy the constraint, each row of data<br />

inserted or updated in the table must make the specified condition either TRUE<br />

or unknown (due to a null value).<br />

For more in<strong>for</strong>mation on constraints, see Chapter 6. Data Integrity.<br />

A trigger is a set of actions that are executed automatically whenever a specified<br />

event occurs to a specified base table. An event can be an insert, update, or delete<br />

operation. The trigger can be run either be<strong>for</strong>e or after the event. For more<br />

in<strong>for</strong>mation on triggers, see Chapter 6. Data Integrity in this book or see the<br />

Database <strong>Programming</strong> book.<br />

2. Although CREATE INDEX can create a unique index that also guarantees uniqueness, such an index is not a constraint.<br />

8 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


Stored Procedures<br />

A stored procedure is a program that can be called using the <strong>SQL</strong> CALL statement.<br />

<strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> supports external stored procedures and <strong>SQL</strong> procedures.<br />

External stored procedures can be any <strong>AS</strong>/<strong>400</strong> program or REXX procedure. They<br />

cannot be System/36 programs or procedures, or service programs. An <strong>SQL</strong><br />

procedure is defined entirely in <strong>SQL</strong> and can contain <strong>SQL</strong> statements including<br />

<strong>SQL</strong> control statements. For more in<strong>for</strong>mation on stored procedures, see Chapter 7.<br />

Stored Procedures.<br />

User-defined functions<br />

A user-defined function is a program that can be invoked like any built-in<br />

function. <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> supports external functions, <strong>SQL</strong> functions, and<br />

sourced functions. External functions can be any <strong>AS</strong>/<strong>400</strong> ILE program or service<br />

program. An <strong>SQL</strong> function is defined entirely in <strong>SQL</strong> and can contain <strong>SQL</strong><br />

statements, including <strong>SQL</strong> control statements. A sourced function is built over any<br />

built-in or any existing user-defined function. For more in<strong>for</strong>mation on<br />

user-defined functions, see “Chapter 9. Writing User-Defined Functions (UDFs)” on<br />

page 189.<br />

User-defined type<br />

A user-defined type is a distinct data type that users can define independently of<br />

those supplied by the database management system. Distinct data types map on a<br />

one-to-one basis to existing database types. For more in<strong>for</strong>mation on user-defined<br />

types, see “User-defined distinct types (UDT)” on page 173.<br />

<strong>SQL</strong> Packages<br />

Application program objects<br />

An <strong>SQL</strong> package is an object that contains the control structure produced when the<br />

<strong>SQL</strong> statements in an application program are bound to a remote relational<br />

database management system (DBMS). The DBMS uses the control structure to<br />

process <strong>SQL</strong> statements encountered while running the application program.<br />

<strong>SQL</strong> packages are created when a relational database name (RDB parameter) is<br />

specified on a Create <strong>SQL</strong> (CRT<strong>SQL</strong>xxx) command and a program object is created.<br />

Packages can also be created using the CRT<strong>SQL</strong>PKG command. For more<br />

in<strong>for</strong>mation about packages and distributed relational database function, see<br />

Chapter 17. Distributed Relational Database Function<br />

<strong>SQL</strong> packages can also be created using the QSQPRCED API. For more in<strong>for</strong>mation<br />

on QSQPRCED, see the OS/<strong>400</strong> API book.<br />

The process of creating a <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> application program may result in<br />

the creation of several objects. This section briefly describes the process of creating<br />

a <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> application. <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> supports both non-ILE<br />

and ILE precompilers. Application programs may be either distributed or<br />

nondistributed. Additional in<strong>for</strong>mation on creating <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong><br />

application programs is in the topic Preparing and Running a Program with <strong>SQL</strong><br />

Statements in the <strong>SQL</strong> <strong>Programming</strong> with Host Languages in<strong>for</strong>mation.<br />

Chapter 1. Introduction to <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> Structured Query Language 9


With <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> you may need to manage the following objects:<br />

v The original source<br />

v Optionally, the module object <strong>for</strong> ILE programs<br />

v The program or service program<br />

v The <strong>SQL</strong> package <strong>for</strong> distributed programs<br />

With a nondistributed non-ILE <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> program, you must manage<br />

only the original source and the resulting program. The following shows the<br />

objects involved and steps that happen during the precompile and compile<br />

processes <strong>for</strong> a nondistributed non-ILE <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> program:<br />

User<br />

Source<br />

File<br />

Member<br />

Precompile<br />

Temporary<br />

Source<br />

File<br />

Member<br />

Compile<br />

Processed<br />

<strong>SQL</strong><br />

Statements<br />

Program<br />

Access<br />

Plan<br />

RV2W565-1<br />

With a nondistributed ILE <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> program, you may need to<br />

manage the original source, the modules, and the resulting program or service<br />

program. The following shows the objects involved and steps that happen during<br />

the precompile and compile processes <strong>for</strong> a nondistributed ILE <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong><br />

<strong>AS</strong>/<strong>400</strong> program when OBJTYPE(*PGM) is specified on the precompile command:<br />

User<br />

Source<br />

File<br />

Member<br />

Precompile<br />

Temporary<br />

Source<br />

File<br />

Member<br />

Compile Module Bind Program<br />

Processed<br />

<strong>SQL</strong><br />

Statements<br />

Processed<br />

<strong>SQL</strong><br />

Statements<br />

Access<br />

Plan<br />

RV2W569-0<br />

With a distributed non-ILE <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> program, you must manage the<br />

original source, the resulting program, and the resulting package. The following<br />

shows the objects and steps that occur during the precompile and compile<br />

processes <strong>for</strong> a distributed non-ILE <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> program:<br />

User<br />

Source<br />

File<br />

Member<br />

Precompile<br />

Temporary<br />

Source<br />

File<br />

Member<br />

Compile<br />

Processed<br />

<strong>SQL</strong><br />

Statements<br />

Program<br />

Access<br />

Plan<br />

Create<br />

<strong>SQL</strong><br />

Package<br />

<strong>SQL</strong><br />

Package<br />

Access<br />

Plan<br />

RV2W566-2<br />

With a distributed ILE <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> program, you must manage the<br />

original source, module objects, the resulting program or service program, and the<br />

resulting packages. An <strong>SQL</strong> package can be created <strong>for</strong> each distributed module in<br />

a distributed ILE program or service program. The following shows the objects and<br />

10 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


steps that occur during the precompile and compile processes <strong>for</strong> a distributed ILE<br />

<strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> program:<br />

Note: The access plans associated with the <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> distributed<br />

program object are not created until the program is run locally.<br />

User source file member<br />

A source file member contains the programmer’s application language and <strong>SQL</strong><br />

statements. You can create and maintain the source file member by using the<br />

source entry utility (SEU), a part of the <strong>AS</strong>/<strong>400</strong> Application Development Tools<br />

licensed program.<br />

Output source file member<br />

Program<br />

User<br />

Source<br />

File<br />

Member<br />

Precompile<br />

Temporary<br />

Source<br />

File<br />

Member<br />

Processed<br />

<strong>SQL</strong><br />

Statements<br />

Compile Module Bind Program<br />

Create<br />

<strong>SQL</strong><br />

Package <strong>SQL</strong><br />

Package<br />

Processed<br />

<strong>SQL</strong><br />

Statements<br />

Access<br />

Plan<br />

Access<br />

Plan<br />

The <strong>SQL</strong> precompile creates an output source file member. By default, the<br />

precompile process (CRT<strong>SQL</strong>xxx commands) creates a temporary source file called<br />

Q<strong>SQL</strong>TEMP (Q<strong>SQL</strong>TEMP1 <strong>for</strong> CRT<strong>SQL</strong>RPGI) in library QTEMP. If the precompile<br />

process uses the QTEMP library, the system automatically deletes the file when the<br />

job completes. You can specify the output source file as a permanent file name on<br />

the precompile commands. A member with the same name as the program name is<br />

added to the output source file. This member contains the following items:<br />

v Calls to the <strong>SQL</strong> run-time support, which have replaced embedded <strong>SQL</strong><br />

statements<br />

v Parsed and syntax-checked <strong>SQL</strong> statements<br />

By default, the precompiler calls the host language compiler. For more in<strong>for</strong>mation<br />

on precompilers, see the topic Preparing and Running a Program with <strong>SQL</strong><br />

Statements in the <strong>SQL</strong> <strong>Programming</strong> with Host Languages in<strong>for</strong>mation.<br />

A program is the object which you can run that is created as a result of the<br />

compile process <strong>for</strong> non-ILE compiles or as a result of the bind process <strong>for</strong> ILE<br />

compiles.<br />

RV2W570-1<br />

An access plan is a set of internal structures and in<strong>for</strong>mation that tells <strong>SQL</strong> how to<br />

run an embedded <strong>SQL</strong> statement most effectively. It is created only when the<br />

program has successfully created. Access plans are not created during program<br />

creation <strong>for</strong> <strong>SQL</strong> statements if the statements:<br />

v Refer to a table or view that cannot be found<br />

v Refer to a table or view to which you are not authorized<br />

The access plans <strong>for</strong> such statements are created when the program is run. If, at<br />

that time, the table or view still cannot be found or you are still not authorized, a<br />

Chapter 1. Introduction to <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> Structured Query Language 11


negative <strong>SQL</strong>CODE is returned. Access plans are stored and maintained in the<br />

program object <strong>for</strong> nondistributed <strong>SQL</strong> programs and in the <strong>SQL</strong> package <strong>for</strong><br />

distributed <strong>SQL</strong> programs.<br />

<strong>SQL</strong> Package<br />

Module<br />

An <strong>SQL</strong> package contains the access plans <strong>for</strong> a distributed <strong>SQL</strong> program.<br />

An <strong>SQL</strong> package is an object that is created when:<br />

v A distributed <strong>SQL</strong> program is successfully created using the RDB parameter on<br />

CRT<strong>SQL</strong>xxx commands.<br />

v When the Create <strong>SQL</strong> Package (CRT<strong>SQL</strong>PKG) command is run.<br />

When a distributed <strong>SQL</strong> program is created, the name of the <strong>SQL</strong> package and an<br />

internal consistency token are saved in the program. These are used at run time to<br />

find the <strong>SQL</strong> package and to verify that the <strong>SQL</strong> package is correct <strong>for</strong> this<br />

program. Because the name of the <strong>SQL</strong> package is critical <strong>for</strong> running distributed<br />

<strong>SQL</strong> programs, an <strong>SQL</strong> package cannot be:<br />

v Moved<br />

v Renamed<br />

v Duplicated<br />

v Restored to a different library<br />

A module is an Integrated Language Environment (ILE) object that is created by<br />

compiling source code using the CRTxxxMOD command (or any of the<br />

CRTBNDxxx commands where xxx is C, CBL, CPP, or RPG). You can run a module<br />

only if you use the Create Program (CRTPGM) command to bind it into a<br />

program. You usually bind several modules together, but you can bind a module<br />

by itself. Modules contain in<strong>for</strong>mation about the <strong>SQL</strong> statements; however, the <strong>SQL</strong><br />

access plans are not created until the modules are bound into either a program or<br />

service program.<br />

Service program<br />

A service program is an Integrated Language Environment (ILE) object that<br />

provides a means of packaging externally supported callable routines (functions or<br />

procedures) into a separate object. Bound programs and other service programs<br />

can access these routines by resolving their imports to the exports provided by a<br />

service program. The connections to these services are made when the calling<br />

programs are created. This improves call per<strong>for</strong>mance to these routines without<br />

including the code in the calling program.<br />

12 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


Chapter 2. Getting Started with <strong>SQL</strong><br />

Starting interactive <strong>SQL</strong><br />

This chapter describes how to create and work with <strong>SQL</strong> collections, tables, and<br />

views using <strong>SQL</strong> statements.<br />

The syntax <strong>for</strong> each of the <strong>SQL</strong> statements used in this chapter is described in<br />

detail in the <strong>SQL</strong> Reference book. A description of how to use <strong>SQL</strong> statements and<br />

clauses in more complex situations is provided in Chapter 3. Basic <strong>Concepts</strong> and<br />

Techniques and Chapter 5. Advanced Coding Techniques.<br />

In this chapter, the examples use the interactive <strong>SQL</strong> interface to show the<br />

execution of <strong>SQL</strong> statements. Each <strong>SQL</strong> interface provides methods <strong>for</strong> using <strong>SQL</strong><br />

statements to define tables, views, and other objects, methods <strong>for</strong> updating the<br />

objects, and methods <strong>for</strong> reading data from the objects. Some tasks described here<br />

can also be done using Operations Navigator. In those cases, the in<strong>for</strong>mation about<br />

the task notes that it can be done using Operations Navigator.<br />

See the following topics <strong>for</strong> details:<br />

v “Starting interactive <strong>SQL</strong>”<br />

v “Creating an <strong>SQL</strong> collection”<br />

v “Creating and using a table” on page 14<br />

v “Using the LABEL ON statement” on page 16<br />

v “Inserting in<strong>for</strong>mation into a table” on page 18<br />

v “Getting in<strong>for</strong>mation from a single table” on page 20<br />

v “Getting in<strong>for</strong>mation from more than one table” on page 23<br />

v “Changing in<strong>for</strong>mation in a table” on page 25<br />

v “Deleting in<strong>for</strong>mation from a table” on page 28<br />

v “Creating and using a view” on page 28<br />

To start using interactive <strong>SQL</strong> <strong>for</strong> the following examples, type:<br />

STR<strong>SQL</strong> NAMING(*<strong>SQL</strong>)<br />

Creating an <strong>SQL</strong> collection<br />

and press Enter. When the Enter <strong>SQL</strong> Statements display appears, you are ready to<br />

start typing <strong>SQL</strong> Statements. For more in<strong>for</strong>mation on interactive <strong>SQL</strong> and the<br />

STR<strong>SQL</strong> command, see Chapter 12. Using Interactive <strong>SQL</strong>.<br />

If you are reusing an existing interactive <strong>SQL</strong> session, make sure that you set the<br />

naming mode to <strong>SQL</strong> naming. You can specify this on the F13 (Services) panel,<br />

option 1 (Change session attributes).<br />

An <strong>SQL</strong> collection is the basic object in which tables, views, indexes, and packages<br />

are placed. One way to create a collection (called a library) is by using Operations<br />

Navigator. Or you can use the <strong>SQL</strong> CREATE COLLECTION statement.<br />

© Copyright IBM Corp. 2000 13


For an example of creating a collection using interactive <strong>SQL</strong>, see “Example:<br />

Creating the <strong>SQL</strong> Collection (SAMPLECOLL)”.<br />

Example: Creating the <strong>SQL</strong> Collection (SAMPLECOLL)<br />

Creating and using a table<br />

You can create a sample collection, named SAMPLECOLL, by typing the following<br />

<strong>SQL</strong> statement on the Enter <strong>SQL</strong> Statements display and pressing Enter:<br />

Enter <strong>SQL</strong> Statements<br />

Type <strong>SQL</strong> statement, press Enter.<br />

Current connection is to relational database SYSTEM1<br />

===> CREATE COLLECTION SAMPLECOLL_________________________________________<br />

_____________________________________________________________________<br />

_____________________________________________________________________<br />

_____________________________________________________________________<br />

Bottom<br />

F3=Exit F4=Prompt F6=Insert line F9=Retrieve F10=Copy line<br />

F12=Cancel F13=Services F24=More keys<br />

Note: Running this statement causes several objects to be created and takes several<br />

seconds.<br />

After you have successfully created a collection, you can create tables, views, and<br />

indexes in it. Tables, views, and indexes can also be created in libraries instead of<br />

collections.<br />

You can create a table by using the <strong>SQL</strong> CREATE TABLE statement or by using<br />

Operations Navigator. The CREATE TABLE statement allows you to create a table,<br />

define the physical attributes of the columns in the table, and define constraints to<br />

restrict the values that are allowed in the table.<br />

For an example of creating a table using interactive <strong>SQL</strong>, see “Example: Creating a<br />

table (INVENTORY_LIST)”.<br />

When creating a table, you need to understand the concepts of null value and<br />

default value. A null value indicates the absence of a column value <strong>for</strong> a row. It is<br />

not the same as a value of zero or all blanks. It means ″unknown″. It is not equal<br />

to any value, not even to other null values. If a column does not allow the null<br />

value, a value must be assigned to the column, either a default value or a user<br />

supplied value.<br />

A default value is assigned to a column when a row is added to a table and no<br />

value is specified <strong>for</strong> that column. If a specific default value is not defined <strong>for</strong> a<br />

column, the system default value will be used. For more in<strong>for</strong>mation on the<br />

default values used by INSERT, see “Inserting rows using the INSERT statement”<br />

on page 31<br />

Example: Creating a table (INVENTORY_LIST)<br />

We are going to create a table to maintain in<strong>for</strong>mation about the current inventory<br />

of a business. It will have in<strong>for</strong>mation about the items kept in the inventory, their<br />

cost, quantity currently on hand, the last order date, and the number last ordered.<br />

The item number will be a required value. It cannot be null. The item name,<br />

14 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


quantity on hand, and order quantity will have user supplied default values. The<br />

last order date and quantity ordered will allow the null value.<br />

On the Enter <strong>SQL</strong> Statements display, type CREATE TABLE and press F4 (Prompt).<br />

The following display is shown (with the input areas not yet filled in):<br />

Type in<strong>for</strong>mation, press Enter.<br />

Specify CREATE TABLE Statement<br />

Table . . ....... INVENTORY_LIST______ Name<br />

Collection ...... SAMPLECOLL__ Name, F4 <strong>for</strong> list<br />

Nulls: 1=NULL, 2=NOT NULL, 3=NOT NULL WITH DEFAULT<br />

Column FOR Column Type Length Scale Nulls<br />

ITEM_NUMBER_______ ____________ CHAR___________ 6____ __ 2<br />

ITEM_NAME_________ ____________ VARCHAR________ 20___ __ 3<br />

UNIT_COST_________ ____________ DECIMAL________ 8____ 2_ 3<br />

QUANTITY_ON_HAND__ ____________ SMALLINT_______ _____ __ 1<br />

L<strong>AS</strong>T_ORDER_DATE___ ____________ DATE___________ _____ __ 1<br />

ORDER_QUANTITY____ ____________ SMALLINT_______ _____ __ 1<br />

__________________ ____________ _______________ _____ __ 3<br />

Bottom<br />

Table CONSTRAINT . . . .......... N Y=Yes, N=No<br />

Distributed Table . . .......... N Y=Yes, N=No<br />

F3=Exit F4=Prompt F5=Refresh F6=Insert line F10=Copy line<br />

F11=Display more attributes F12=Cancel F14=Delete line F24=More keys<br />

Type the table name and collection name of the table you are creating,<br />

INVENTORY_LIST in SAMPLECOLL, <strong>for</strong> the Table and Collection prompts. Each<br />

column you want to define <strong>for</strong> the table is represented by an entry in the list on<br />

the lower part of the display. For each column, type the name of the column, the<br />

data type of the column, its length and scale, and the null attribute.<br />

Press F11 to see more attributes that can be specified <strong>for</strong> the columns. This is<br />

where a default value may be specified.<br />

Type in<strong>for</strong>mation, press Enter.<br />

Specify CREATE TABLE Statement<br />

Table . . ....... INVENTORY_LIST______ Name<br />

Collection ...... SAMPLECOLL__ Name, F4 <strong>for</strong> list<br />

Data: 1=BIT, 2=SBCS, 3=MIXED, 4=CCSID<br />

Column Data Allocate CCSID CONSTRAINT Default<br />

ITEM NUMBER_______ _ _____ _____ N __________________<br />

ITEM NAME_________ _ _____ _____ N '***UNKNOWN***'___<br />

UNIT_COST_________ _ _____ _____ N __________________<br />

QUANTITY_ON_HAND__ _ _____ _____ N NULL______________<br />

L<strong>AS</strong>T_ORDER_DATE___ _ _____ _____ N __________________<br />

ORDER_QUANTITY____ _ _____ _____ N 20________________<br />

__________________ _ _____ _____ _ __________________<br />

Bottom<br />

Table CONSTRAINT . . . .......... N Y=Yes, N=No<br />

Distributed Table . . .......... N Y=Yes, N=No<br />

F3=Exit F4=Prompt F5=Refresh F6=Insert line F10=Copy line<br />

F11=Display more attributes F12=Cancel F14=Delete line F24=More keys<br />

Note: Another way of entering column definitions is to press F4 (Prompt) with<br />

your cursor on one of the column entries in the list. This will bring up a<br />

display that shows all of the attributes <strong>for</strong> defining a single column.<br />

Chapter 2. Getting Started with <strong>SQL</strong> 15


When all the values have been entered, press Enter to create the table. The Enter<br />

<strong>SQL</strong> Statements display will be shown again with a message indicating that the<br />

table has been created.<br />

You can directly key in this CREATE TABLE statement on the Enter <strong>SQL</strong><br />

Statements display as follows:<br />

CREATE TABLE SAMPLECOLL.INVENTORY_LIST<br />

(ITEM_NUMBER CHAR(6) NOT NULL,<br />

ITEM_NAME VARCHAR(20) NOT NULL WITH DEFAULT '***UNKNOWN***',<br />

UNIT_COST DECIMAL(8,2) NOT NULL WITH DEFAULT,<br />

QUANTITY_ON_HAND SMALLINT DEFAULT NULL,<br />

L<strong>AS</strong>T_ORDER_DATE DATE,<br />

ORDER_QUANTITY SMALLINT DEFAULT 20)<br />

Creating the Supplier Table (SUPPLIERS)<br />

Later in our examples, we will need a second table as well. This table will contain<br />

in<strong>for</strong>mation about suppliers of our inventory items, which items they supply, and<br />

the cost of the item from that supplier. To create it, either type it in directly on the<br />

Enter <strong>SQL</strong> Statements display or press F4 (Prompt) to use the interactive <strong>SQL</strong><br />

displays to create the definition.<br />

CREATE TABLE SAMPLECOLL.SUPPLIERS<br />

(SUPPLIER_NUMBER CHAR(4) NOT NULL,<br />

ITEM_NUMBER CHAR(6) NOT NULL,<br />

SUPPLIER_COST DECIMAL(8,2))<br />

Using the LABEL ON statement<br />

Normally, the column name is used as the column heading when showing the<br />

output of a SELECT statement in interactive <strong>SQL</strong>. By using the LABEL ON<br />

statement, you can create a more descriptive label <strong>for</strong> the column name. Since we<br />

are going to be running our examples in interactive <strong>SQL</strong>, we will use the LABEL<br />

ON statement to change the column headings. Even though the column names are<br />

descriptive, it will be easier to read if the column headings show each part of the<br />

name on a single line. It will also allow us to see more columns of our data on a<br />

single display.<br />

To change the labels <strong>for</strong> our columns, type LABEL ON COLUMN on the Enter <strong>SQL</strong><br />

Statements display and press F4 (Prompt). The following display will appear:<br />

16 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


Type choices, press Enter.<br />

Specify LABEL ON Statement<br />

Label on .... 2 1=Table or view<br />

2=Column<br />

3=Package<br />

4=Alias<br />

Table or view INVENTORY_LIST______ Name, F4 <strong>for</strong> list<br />

Collection . . SAMPLECOLL__ Name, F4 <strong>for</strong> list<br />

Option . .... 1 1=Column heading<br />

2=Text<br />

F3=Exit F4=Prompt F5=Refresh F12=Cancel F20=Display full names<br />

F21=Display statement<br />

Type in the name of the table and collection containing the columns <strong>for</strong> which you<br />

want to add labels and press Enter. The following display will be shown,<br />

prompting you <strong>for</strong> each of the columns in the table.<br />

Type in<strong>for</strong>mation, press Enter.<br />

Specify LABEL ON Statement<br />

Column Heading<br />

Column ....+....1....+....2....+....3....+....4....+....5....<br />

ITEM_NUMBER 'ITEM NUMBER'___________________________<br />

ITEM_NAME 'ITEM NAME'_____________________________<br />

UNIT_COST 'UNIT COST'_____________________________<br />

QUANTITY_ON_HAND 'QUANTITY ON HAND'_________<br />

L<strong>AS</strong>T_ORDER_DATE 'L<strong>AS</strong>T ORDER DATE'_________<br />

ORDER_QUANTITY 'NUMBER ORDERED'__________________________<br />

Bottom<br />

F3=Exit F5=Refresh F6=Insert line F10=Copy line F12=Cancel<br />

F14=Delete line F19=Display system column names F24=More keys<br />

Type the column headings <strong>for</strong> each of the columns. Column headings are defined<br />

in 20 character sections. Each section will be displayed on a different line when<br />

showing the output of a SELECT statement. The ruler across the top of the column<br />

heading entry area can be used to easily space the headings correctly. When the<br />

headings are typed, press Enter.<br />

The following message indicates that the LABEL ON statement was successful.<br />

LABEL ON <strong>for</strong> INVEN00001 in SAMPLECOLL completed.<br />

The table name in the message is the system table name <strong>for</strong> this table, not the<br />

name that was actually specified in the statement. <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> maintains<br />

Chapter 2. Getting Started with <strong>SQL</strong> 17


two names <strong>for</strong> tables with names longer than ten characters. For more in<strong>for</strong>mation<br />

on system table names, see the CREATE TABLE statement in the <strong>SQL</strong> Reference<br />

book.<br />

The LABEL ON statement can also be keyed in directly on the Enter <strong>SQL</strong><br />

statements display as follows:<br />

LABEL ON SAMPLECOLL/INVENTORY_LIST<br />

(ITEM_NUMBER IS 'ITEM NUMBER',<br />

ITEM_NAME IS 'ITEM NAME',<br />

UNIT_COST IS 'UNIT COST',<br />

QUANTITY_ON_HAND IS 'QUANTITY ON HAND',<br />

L<strong>AS</strong>T_ORDER_DATE IS 'L<strong>AS</strong>T ORDER DATE',<br />

ORDER_QUANTITY IS 'NUMBER ORDERED')<br />

Inserting in<strong>for</strong>mation into a table<br />

After you create a table, you can insert, or add, in<strong>for</strong>mation (data) into it by using<br />

Operations Navigator. Or you can use the <strong>SQL</strong> INSERT statement.<br />

For an example of inserting data into a table using interactive <strong>SQL</strong>, see “Example:<br />

Inserting in<strong>for</strong>mation into a table (INVENTORY_LIST)”.<br />

Example: Inserting in<strong>for</strong>mation into a table (INVENTORY_LIST)<br />

To work with interactive <strong>SQL</strong>, on the Enter <strong>SQL</strong> Statements display, type INSERT<br />

and press F4 (Prompt). The Specify INSERT Statement display will be shown.<br />

Type choices, press Enter.<br />

Specify INSERT Statement<br />

INTO table ....... INVENTORY_LIST______ Name, F4 <strong>for</strong> list<br />

Collection . . .... SAMPLECOLL__ Name, F4 <strong>for</strong> list<br />

Select columns to insert<br />

INTO . . ....... Y Y=Yes, N=No<br />

Insertion method . . . . 1 1=Input VALUES<br />

2=Subselect<br />

Type choices, press Enter.<br />

WITH isolation level . . 1 1=Current level, 2=NC (NONE)<br />

3=UR (CHG), 4=CS, 5=RS (ALL)<br />

6=RR<br />

F3=Exit F4=Prompt F5=Refresh F12=Cancel F20=Display full names<br />

F21=Display statement<br />

Type the table name and collection name in the input fields as shown. Change the<br />

Select columns to insert INTO prompt to Yes. Press Enter to see the display where<br />

the columns you want to insert values into can be selected.<br />

18 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


Specify INSERT Statement<br />

Type sequence numbers (1-999) to make selections, press Enter.<br />

Seq Column Type Length Scale<br />

1__ ITEM_NUMBER CHARACTER 6<br />

2__ ITEM_NAME VARCHAR 20<br />

3__ UNIT_COST DECIMAL 8 2<br />

4__ QUANTITY_ON_HAND SMALLINT 4<br />

___ L<strong>AS</strong>T_ORDER_DATE DATE<br />

___ ORDER_QUANTITY SMALLINT 4<br />

F3=Exit F5=Refresh F12=Cancel F19=Display system column names<br />

F20=Display entire name F21=Display statement<br />

Bottom<br />

In this example, we only want to insert into four of the columns. We will let the<br />

other columns have their default value inserted. The sequence numbers on this<br />

display indicate the order that the columns and values will be listed in the INSERT<br />

statement. Press Enter to show the display where values <strong>for</strong> the selected columns<br />

can be typed.<br />

Type values to insert, press Enter.<br />

Specify INSERT Statement<br />

Column Value<br />

ITEM_NUMBER '153047'_____________________________________________<br />

ITEM_NAME 'Pencils, red'_______________________________________<br />

UNIT_COST 10.00________________________________________________<br />

QUANTITY_ON_HAND 25___________________________________________________<br />

Bottom<br />

F3=Exit F5=Refresh F6=Insert line F10=Copy line F11=Display type<br />

F12=Cancel F14=Delete line F15=Split line F24=More keys<br />

Note: To see the data type and length <strong>for</strong> each of the columns in the insert list,<br />

press F11 (Display type). This will show a different view of the insert values<br />

display, providing in<strong>for</strong>mation about the column definition.<br />

Type the values to be inserted <strong>for</strong> all of the columns and press Enter. A row<br />

containing these values will be added to the table. The values <strong>for</strong> the columns that<br />

were not specified will have a default value inserted. For L<strong>AS</strong>T_ORDER_DATE it<br />

will be the null value since no default was provided and the column allows the<br />

null value. For ORDER_QUANTITY it will be 20, the value specified as the default<br />

value on the CREATE TABLE statement.<br />

You can type the INSERT statement on the Enter <strong>SQL</strong> Statements display as:<br />

INSERT INTO SAMPLECOLL.INVENTORY_LIST<br />

(ITEM_NUMBER,<br />

ITEM_NAME,<br />

UNIT_COST,<br />

QUANTITY_ON_HAND)<br />

Chapter 2. Getting Started with <strong>SQL</strong> 19


VALUES('153047',<br />

'Pencils, red',<br />

10.00,<br />

25)<br />

To add the next row to the table, press F9 (Retrieve) on the Enter <strong>SQL</strong> Statements<br />

display. This will copy the previous INSERT statement to the typing area. You can<br />

either type over the values from the previous INSERT statement or press F4<br />

(Prompt) to use the Interactive <strong>SQL</strong> displays to enter data.<br />

Continue using the INSERT statement to add the following rows to the table.<br />

Values not shown in the chart below should not be inserted so that the default will<br />

be used. In the INSERT statement column list, specify only the column names <strong>for</strong><br />

which you want to insert a value. For example, to insert the third row, you would<br />

specify only ITEM_NUMBER and UNIT_COST <strong>for</strong> the column names and only the<br />

two values <strong>for</strong> these columns in the VALUES list.<br />

ITEM_NUMBER ITEM_NAME UNIT_COST QUANTITY_ON_HAND<br />

153047 Pencils, red 10.00 25<br />

229740 Lined tablets 1.50 120<br />

544931 5.00<br />

303476 Paper clips 2.00 100<br />

559343 Envelopes, legal 3.00 500<br />

291124 Envelopes, standard<br />

775298 Chairs, secretary 225.00 6<br />

073956 Pens, black 20.00 25<br />

Add the following rows to the SAMPLECOLL.SUPPLIERS table.<br />

SUPPLIER_NUMBER ITEM_NUMBER SUPPLIER_COST<br />

1234 153047 10.00<br />

1234 229740 1.00<br />

1234 303476 3.00<br />

9988 153047 8.00<br />

9988 559343 3.00<br />

2424 153047 9.00<br />

2424 303476 2.50<br />

5546 775298 225.00<br />

3366 303476 1.50<br />

3366 073956 17.00<br />

The sample collection now contains two tables with several rows of data in each.<br />

Getting in<strong>for</strong>mation from a single table<br />

Now that we have inserted all the in<strong>for</strong>mation into our tables, we need to be able<br />

to look at it again. In <strong>SQL</strong>, this is done with the SELECT statement. The SELECT<br />

statement is the most complex of all <strong>SQL</strong> statements. This statement is composed<br />

of three main clauses:<br />

1. The SELECT clause, which specifies those columns containing the desired data.<br />

20 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


2. The FROM clause, which specifies the table or tables containing the columns<br />

with the desired data.<br />

3. The WHERE clause, which supplies conditions that determine which rows of<br />

data are retrieved.<br />

In addition to the three main clauses, there are several other clauses described in<br />

“Using basic <strong>SQL</strong> statements and clauses” on page 31, and in the <strong>SQL</strong> Reference<br />

book, which affect the final <strong>for</strong>m of returned data.<br />

To see the values we inserted into the INVENTORY_LIST table, type SELECT and<br />

press F4 (prompt). The following display will be shown:<br />

Specify SELECT Statement<br />

Type SELECT statement in<strong>for</strong>mation. Press F4 <strong>for</strong> a list.<br />

FROM tables ........ SAMPLECOLL.INVENTORY_LIST____________________<br />

SELECT columns . . . .... *____________________________________________<br />

WHERE conditions . . . . . . _____________________________________________<br />

GROUP BY columns . . .... _____________________________________________<br />

HAVING conditions . . . . . _____________________________________________<br />

ORDER BY columns . . .... _____________________________________________<br />

FOR UPDATE OF columns . . . _____________________________________________<br />

Type choices, press Enter.<br />

DISTINCT rows in result table ......... N Y=Yes, N=No<br />

UNION with another SELECT ........... N Y=Yes, N=No<br />

Specify additional options ........... N Y=Yes, N=No<br />

Bottom<br />

F3=Exit F4=Prompt F5=Refresh F6=Insert line F9=Specify subquery<br />

F10=Copy line F12=Cancel F14=Delete line F15=Split line F24=More keys<br />

Type the table name in the FROM tables field on the display. To select all columns<br />

from the table, type * <strong>for</strong> the SELECT columns field on the display. Press Enter and<br />

the statement will run to select all of the data <strong>for</strong> all of the columns in the table.<br />

The following output will be shown:<br />

Display Data<br />

Data width . . . . . . : 71<br />

Position to line ..... Shift to column ......<br />

....+....1....+....2....+....3....+....4....+....5....+....6....+....7.<br />

ITEM ITEM UNIT QUANTITY L<strong>AS</strong>T NUMBER<br />

NUMBER NAME COST ON ORDER ORDERED<br />

HAND DATE<br />

153047 Pencils, red 10.00 25 - 20<br />

229740 Lined tablets 1.50 120 - 20<br />

544931 ***UNKNOWN*** 5.00 - - 20<br />

303476 Paper clips 2.00 100 - 20<br />

559343 Envelopes, legal 3.00 500 - 20<br />

291124 Envelopes, standard .00 - - 20<br />

775298 Chairs, secretary 225.00 6 - 20<br />

073956 Pens, black 20.00 25 - 20<br />

******** End of data ********<br />

F3=Exit F12=Cancel F19=Left F20=Right F21=Split<br />

The column headings that were defined using the LABEL ON statement are<br />

shown. The ITEM_NAME <strong>for</strong> the third entry has the default value that was<br />

specified in the CREATE TABLE statement. The QUANTITY_ON_HAND column<br />

has a null value <strong>for</strong> the rows where no value was inserted. The<br />

L<strong>AS</strong>T_ORDER_DATE column contains all null values since that column is not in<br />

Chapter 2. Getting Started with <strong>SQL</strong> 21


any of the INSERT statements and the column was not defined to have a default<br />

value. Similarly, the ORDER_QUANTITY column contains the default value <strong>for</strong> all<br />

rows.<br />

This statement could be entered on the Enter <strong>SQL</strong> Statements display as:<br />

SELECT *<br />

FROM SAMPLECOLL.INVENTORY_LIST<br />

To limit the number of columns returned by the SELECT statement, the columns<br />

you want to see must be specified. To restrict the number of output rows returned,<br />

the WHERE clause is used. To see only the items that cost more than 10 dollars,<br />

and only have the values <strong>for</strong> the columns ITEM_NUMBER, UNIT_COST, and<br />

ITEM_NAME returned, type SELECT and press F4 (Prompt). The Specify SELECT<br />

Statement display will be shown.<br />

Specify SELECT Statement<br />

Type SELECT statement in<strong>for</strong>mation. Press F4 <strong>for</strong> a list.<br />

FROM tables ........ SAMPLECOLL.INVENTORY_LIST____________________<br />

SELECT columns . . . . . . . ITEM_NUMBER, UNIT_COST, ITEM_NAME____________<br />

WHERE conditions . . . . . . UNIT_COST > 10.00____________________________<br />

GROUP BY columns . . . . . . _____________________________________________<br />

HAVING conditions . . . . . _____________________________________________<br />

ORDER BY columns . . . . . . _____________________________________________<br />

FOR UPDATE OF columns . . . _____________________________________________<br />

Type choices, press Enter.<br />

DISTINCT rows in result table ......... N Y=Yes, N=No<br />

UNION with another SELECT ........... N Y=Yes, N=No<br />

Specify additional options ........... N Y=Yes, N=No<br />

Bottom<br />

F3=Exit F4=Prompt F5=Refresh F6=Insert line F9=Specify subquery<br />

F10=Copy line F12=Cancel F14=Delete line F15=Split line F24=More keys<br />

Although only one line is initially shown <strong>for</strong> each prompt on the Specify SELECT<br />

Statement display, F6 (Insert line) can be used to add more lines to any of the<br />

input areas in the top part of the display. This could be used if more columns were<br />

to be entered in the SELECT columns list, or a longer, more complex WHERE<br />

condition were needed.<br />

Fill in the display as shown above. When Enter is pressed, the SELECT statement<br />

is run. The following output will be seen:<br />

Display Data<br />

Data width ......: 41<br />

Position to line . . . . . Shift to column . . . . . .<br />

....+....1....+....2....+....3....+....4.<br />

ITEM UNIT ITEM<br />

NUMBER COST NAME<br />

775298 225.00 Chairs, secretary<br />

073956 20.00 Pens, black<br />

******** End of data ********<br />

F3=Exit F12=Cancel F19=Left F20=Right F21=Split<br />

The only rows returned are those whose data values compare with the condition<br />

specified in the WHERE clause. Furthermore, the only data values returned are<br />

from the columns you explicitly specified in the SELECT clause. Data values of<br />

columns other than those explicitly identified are not returned.<br />

22 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


This statement could have been entered on the Enter <strong>SQL</strong> Statements display as:<br />

SELECT ITEM_NUMBER, UNIT_COST, ITEM_NAME<br />

FROM SAMPLECOLL.INVENTORY_LIST<br />

WHERE UNIT_COST > 10.00<br />

Getting in<strong>for</strong>mation from more than one table<br />

<strong>SQL</strong> allows you to get in<strong>for</strong>mation from columns contained in more than one table.<br />

This operation is called a join operation. (For a more detailed description of the<br />

join operation, see “Joining data from more than one table” on page 75). In <strong>SQL</strong>, a<br />

join operation is specified by placing the names of those tables you want to join<br />

together into the same FROM clause of a SELECT statement.<br />

Suppose you want to see a list of all the suppliers and the item numbers and item<br />

names <strong>for</strong> their supplied items. The item name is not in the SUPPLIERS table. It is<br />

in the INVENTORY_LIST table. Using the common column, ITEM_NUMBER, we<br />

can see all three of the columns as if they were from a single table.<br />

Whenever the same column name exists in two or more tables being joined, the<br />

column name must be qualified by the table name to specify which column is<br />

really being referenced. In this SELECT statement, the column name<br />

ITEM_NUMBER is defined in both tables so the column name needs to be<br />

qualified by the table name. If the columns had different names, there would be no<br />

confusion so qualification would not be needed.<br />

To per<strong>for</strong>m this join, the following SELECT statement can be used. Enter it by<br />

typing it directly on the Enter <strong>SQL</strong> Statements display or by prompting. If using<br />

prompting, both table names need to be typed on the FROM tables input line.<br />

SELECT SUPPLIER_NUMBER, SAMPLECOLL.INVENTORY_LIST.ITEM_NUMBER, ITEM_NAME<br />

FROM SAMPLECOLL.SUPPLIERS, SAMPLECOLL.INVENTORY_LIST<br />

WHERE SAMPLECOLL.SUPPLIERS.ITEM_NUMBER<br />

= SAMPLECOLL.INVENTORY_LIST.ITEM_NUMBER<br />

Another way to enter the same statement is to use a correlation name. A<br />

correlation name provides another name <strong>for</strong> a table name to use in a statement. A<br />

correlation name must be used when the table names are the same. It can be<br />

specified following each table name in the FROM list. The previous statement<br />

could be rewritten as:<br />

SELECT SUPPLIER_NUMBER, Y.ITEM_NUMBER, ITEM_NAME<br />

FROM SAMPLECOLL.SUPPLIERS X, SAMPLECOLL.INVENTORY_LIST Y<br />

WHERE X.ITEM_NUMBER = Y.ITEM_NUMBER<br />

In this example, SAMPLECOLL.SUPPLIERS is given a correlation name of X and<br />

SAMPLECOLL.INVENTORY_LIST is given a correlation name of Y. The names X<br />

and Y are then used to qualify the ITEM_NUMBER column name.<br />

For more in<strong>for</strong>mation on correlation names, see the <strong>SQL</strong> Reference book.<br />

Running this example returns the following output:<br />

Chapter 2. Getting Started with <strong>SQL</strong> 23


Display Data<br />

Data width ......: 45<br />

Position to line . . . . . Shift to column . . . . . .<br />

....+....1....+....2....+....3....+....4....+<br />

SUPPLIER_NUMBER ITEM ITEM<br />

NUMBER NAME<br />

1234 153047 Pencils, red<br />

9988 153047 Pencils, red<br />

2424 153047 Pencils, red<br />

1234 229740 Lined tablets<br />

1234 303476 Paper clips<br />

2424 303476 Paper clips<br />

3366 303476 Paper clips<br />

9988 559343 Envelopes, legal<br />

5546 775298 Chairs, secretary<br />

3366 073956 Pens, black<br />

******** End of data ********<br />

F3=Exit F12=Cancel F19=Left F20=Right F21=Split<br />

The data values in the result table represent a composite of the data values<br />

contained in the two tables INVENTORY_LIST and SUPPLIERS. This result table<br />

contains the supplier number from the SUPPLIER table and the item number and<br />

item name from the INVENTORY_LIST table. Any item numbers that do not<br />

appear in the SUPPLIER table are not shown in this result table. The results are not<br />

guaranteed to be in any order unless the ORDER BY clause is specified <strong>for</strong> the<br />

SELECT statement. Since we did not change any column headings <strong>for</strong> the<br />

SUPPLIER table, the SUPPLIER_NUMBER column name is used as the column<br />

heading.<br />

The following is an example of using ORDER BY to guarantee the order of the<br />

rows. The statement will first order the result table by the SUPPLIER_NUMBER<br />

column. Rows with the same value <strong>for</strong> SUPPLIER_NUMBER will be ordered by<br />

their ITEM_NUMBER.<br />

SELECT SUPPLIER_NUMBER, Y.ITEM_NUMBER, ITEM_NAME<br />

FROM SAMPLECOLL.SUPPLIERS X, SAMPLECOLL.INVENTORY_LIST Y<br />

WHERE X.ITEM_NUMBER = Y.ITEM_NUMBER<br />

ORDER BY SUPPLIER_NUMBER, Y.ITEM_NUMBER<br />

Running the previous statement would produce the following output.<br />

24 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


Display Data<br />

Data width ......: 45<br />

Position to line ..... Shift to column ......<br />

....+....1....+....2....+....3....+....4....+<br />

SUPPLIER_NUMBER ITEM ITEM<br />

NUMBER NAME<br />

1234 153047 Pencils, red<br />

1234 229740 Lined tablets<br />

1234 303476 Paper clips<br />

2424 153047 Pencils, red<br />

2424 303476 Paper clips<br />

3366 073956 Pens, black<br />

3366 303476 Paper clips<br />

5546 775298 Chairs, secretary<br />

9988 153047 Pencils, red<br />

9988 559343 Envelopes, legal<br />

******** End of data ********<br />

Changing in<strong>for</strong>mation in a table<br />

F3=Exit F12=Cancel F19=Left F20=Right F21=Split<br />

You can use the <strong>SQL</strong> UPDATE statement to change the data values in some or all<br />

of the columns of a table. You may also use Operations Navigator to accomplish<br />

this task.<br />

For an example of changing in<strong>for</strong>mation in a table using interactive <strong>SQL</strong>, see<br />

“Example: Changing in<strong>for</strong>mation in a table”.<br />

If you want to limit the number of rows being changed during a single statement<br />

execution, use the WHERE clause with the UPDATE statement. For more<br />

in<strong>for</strong>mation see, “Changing data in a table using the UPDATE statement” on<br />

page 33. If you do not specify the WHERE clause, all of the rows in the specified<br />

table are changed. However, if you use the WHERE clause, the system changes<br />

only the rows satisfying the conditions that you specify. For more in<strong>for</strong>mation, see<br />

“Specifying a search condition using the WHERE clause” on page 38.<br />

Example: Changing in<strong>for</strong>mation in a table<br />

Suppose we want to use interactive <strong>SQL</strong> and are placing an order <strong>for</strong> more paper<br />

clips today. To update the L<strong>AS</strong>T_ORDER_DATE and ORDER_QUANTITY <strong>for</strong> item<br />

number 303476, type UPDATE and press F4 (Prompt). The Specify UPDATE<br />

Statement display will be shown.<br />

Chapter 2. Getting Started with <strong>SQL</strong> 25


Type choices, press Enter.<br />

Specify UPDATE Statement<br />

Table . . . . . . . . INVENTORY_LIST______ Name, F4 <strong>for</strong> list<br />

Collection . . . . . SAMPLECOLL__ Name, F4 <strong>for</strong> list<br />

Correlation ..... ____________________ Name<br />

F3=Exit F4=Prompt F5=Refresh F12=Cancel F20=Display full names<br />

F21=Display statement<br />

After typing the table name and collection name, press Enter. The display will be<br />

shown again with the list of columns in the table.<br />

Type choices, press Enter.<br />

Specify UPDATE Statement<br />

Table . . . . . . . . INVENTORY_LIST______ Name, F4 <strong>for</strong> list<br />

Collection . . . . . SAMPLECOLL__ Name, F4 <strong>for</strong> list<br />

Correlation ..... ____________________ Name<br />

Type in<strong>for</strong>mation, press Enter.<br />

Column Value<br />

ITEM_NUMBER _____________________________________________________<br />

ITEM_NAME _____________________________________________________<br />

UNIT_COST _____________________________________________________<br />

QUANTITY_ON_HAND _____________________________________________________<br />

L<strong>AS</strong>T_ORDER_DATE CURRENT DATE_________________________________________<br />

ORDER_QUANTITY 50___________________________________________________<br />

F3=Exit F4=Prompt F5=Refresh F6=Insert line F10=Copy line<br />

F11=Display type F12=Cancel F14=Delete line F24=More keys<br />

Bottom<br />

Specifying CURRENT DATE <strong>for</strong> a value will change the date in all the selected<br />

rows to be today’s date.<br />

After typing the values to be updated <strong>for</strong> the table, press Enter to see the display<br />

on which the WHERE condition can be specified. If a WHERE condition is not<br />

specified, all the rows in the table will be updated using the values from the<br />

previous display.<br />

26 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


Specify UPDATE Statement<br />

Type WHERE conditions, press Enter. Press F4 <strong>for</strong> a list.<br />

ITEM_NUMBER = '303476'________________________________________________<br />

______________________________________________________________________<br />

Type choices, press Enter.<br />

Bottom<br />

WITH isolation level . . . 1 1=Current level, 2=NC (NONE)<br />

3=UR (CHG), 4=CS, 5=RS (ALL)<br />

6=RR<br />

F3=Exit F4=Prompt F5=Refresh F6=Insert line F9=Specify subquery<br />

F10=Copy line F12=Cancel F14=Delete line F15=Split line F24=More keys<br />

After typing the condition, press Enter to per<strong>for</strong>m the update on the table. A<br />

message will indicate that the function is complete.<br />

This statement could have been typed on the Enter <strong>SQL</strong> Statements display as:<br />

UPDATE SAMPLECOLL.INVENTORY_LIST<br />

SET L<strong>AS</strong>T_ORDER_DATE = CURRENT DATE,<br />

ORDER_QUANTITY = 50<br />

WHERE ITEM_NUMBER = '303476'<br />

Running a SELECT statement to get all the rows from the table (SELECT * FROM<br />

SAMPLECOLL.INVENTORY_LIST), returns the following result:<br />

Display Data<br />

Data width ......: 71<br />

Position to line ..... Shift to column ......<br />

....+....1....+....2....+....3....+....4....+....5....+....6....+....7.<br />

ITEM ITEM UNIT QUANTITY L<strong>AS</strong>T NUMBER<br />

NUMBER NAME COST ON ORDER ORDERED<br />

HAND DATE<br />

153047 Pencils, red 10.00 25 - 20<br />

229740 Lined tablets 1.50 120 - 20<br />

544931 ***UNKNOWN*** 5.00 - - 20<br />

303476 Paper clips 2.00 100 05/30/94 50<br />

559343 Envelopes, legal 3.00 500 - 20<br />

291124 Envelopes, standard .00 - - 20<br />

775298 Chairs, secretary 225.00 6 - 20<br />

073956 Pens, black 20.00 25 - 20<br />

******** End of data ********<br />

Bottom<br />

F3=Exit F12=Cancel F19=Left F20=Right F21=Split<br />

Only the entry <strong>for</strong> Paper clips was changed. The L<strong>AS</strong>T_ORDER_DATE was changed<br />

to be the current date. This date is always the date the update is run. The<br />

NUMBER_ORDERED shows its updated value.<br />

Chapter 2. Getting Started with <strong>SQL</strong> 27


Deleting in<strong>for</strong>mation from a table<br />

You can delete data from a table by using Operations Navigator. Or, using the <strong>SQL</strong><br />

DELETE statement, you can delete entire rows from a table when they no longer<br />

contain needed in<strong>for</strong>mation. You can use the WHERE clause with the DELETE<br />

statement to identify rows to be deleted during a single statement execution. For<br />

more in<strong>for</strong>mation, see “Removing rows from a table using the DELETE statement”<br />

on page 34.<br />

For an example of deleting in<strong>for</strong>mation in a table using interactive <strong>SQL</strong>, see<br />

“Example: Deleting in<strong>for</strong>mation from a table (INVENTORY_LIST)”.<br />

Example: Deleting in<strong>for</strong>mation from a table (INVENTORY_LIST)<br />

Creating and using a view<br />

If we want to remove all the rows in our table that have the null value <strong>for</strong> the<br />

QUANTITY_ON_HAND column, you could enter the following statement on the<br />

Enter <strong>SQL</strong> Statements display:<br />

DELETE<br />

FROM SAMPLECOLL.INVENTORY_LIST<br />

WHERE QUANTITY_ON_HAND IS NULL<br />

To check a column <strong>for</strong> the null value, the IS NULL comparison is used. Running<br />

another SELECT statement after the delete has completed will return the following<br />

result table:<br />

Display Data<br />

Data width ......: 71<br />

Position to line . . . . . Shift to column . . . . . .<br />

....+....1....+....2....+....3....+....4....+....5....+....6....+....7.<br />

ITEM ITEM UNIT QUANTITY L<strong>AS</strong>T NUMBER<br />

NUMBER NAME COST ON ORDER ORDERED<br />

HAND DATE<br />

153047 Pencils, red 10.00 25 - 20<br />

229740 Lined tablets 1.50 120 - 20<br />

303476 Paper clips 2.00 100 05/30/94 50<br />

559343 Envelopes, legal 3.00 500 - 20<br />

775298 Chairs, secretary 225.00 6 - 20<br />

073956 Pens, black 20.00 25 - 20<br />

******** End of data ********<br />

Bottom<br />

F3=Exit F12=Cancel F19=Left F20=Right F21=Split<br />

The rows with a null value <strong>for</strong> QUANTITY_ON_HAND were deleted.<br />

You may find that no single table contains all the in<strong>for</strong>mation you need. You may<br />

also want to give users access to only part of the data in a table. Views provide a<br />

way to subset the table so that you deal with only the data you need. A view<br />

reduces complexity and, at the same time, restricts access.<br />

You can create a view using Operations Navigator. Or you can use the <strong>SQL</strong><br />

CREATE VIEW statement. Using the CREATE VIEW statement, defining a view on<br />

a table is like creating a new table containing just the columns and rows you want.<br />

When your application uses a view, it cannot access rows or columns of the table<br />

that are not included in the view. However, rows that do not match the selection<br />

28 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


criteria may still be inserted through a view if the <strong>SQL</strong> WITH CHECK OPTION is<br />

not used. See Chapter 6. Data Integrity <strong>for</strong> more in<strong>for</strong>mation on using WITH<br />

CHECK OPTION.<br />

For examples of creating a view using interactive <strong>SQL</strong>, see the following:<br />

v “Example: Creating a view on a single table”<br />

v “Example: Creating a view combining data from more than one table” on<br />

page 30<br />

In order to create a view you must have the proper authority to the tables or<br />

physical files on which the view is based. See the CREATE VIEW statement in the<br />

<strong>SQL</strong> Reference <strong>for</strong> a list of authorities needed.<br />

If you do not specify column names in the view definition, the column names will<br />

be the same as those <strong>for</strong> the table on which the view is based.<br />

You can make changes to a table through a view even if the view has a different<br />

number of columns or rows than the table. For INSERT, columns in the table that<br />

are not in the view must have a default value.<br />

You can use the view as though it were a table, even though the view is totally<br />

dependent on one or more tables <strong>for</strong> data. The view has no data of its own and<br />

there<strong>for</strong>e requires no storage <strong>for</strong> the data. Because a view is derived from a table<br />

that exists in storage, when you update the view data, you are really updating<br />

data in the table. There<strong>for</strong>e, views are automatically kept up-to-date as the tables<br />

they depend on are updated.<br />

See “Creating and using views” on page 95 <strong>for</strong> additional in<strong>for</strong>mation.<br />

Example: Creating a view on a single table<br />

The following example shows how to create a view on a single table. The view is<br />

built on the INVENTORY_LIST table. The table has six columns, but the view uses<br />

only three of the columns: ITEM_NUMBER, L<strong>AS</strong>T_ORDER_DATE, and<br />

QUANTITY_ON_HAND. The order of the columns in the SELECT clause is the<br />

order in which they will appear in the view. The view will contain only the rows<br />

<strong>for</strong> items that were ordered in the last two weeks. The CREATE VIEW statement<br />

looks like this:<br />

CREATE VIEW SAMPLECOLL.RECENT_ORDERS <strong>AS</strong><br />

SELECT ITEM_NUMBER, L<strong>AS</strong>T_ORDER_DATE, QUANTITY_ON_HAND<br />

FROM SAMPLECOLL.INVENTORY_LIST<br />

WHERE L<strong>AS</strong>T_ORDER_DATE > CURRENT DATE - 14 DAYS<br />

In the example above, the columns in the view have the same name as the<br />

columns in the table because no column list follows the view name. The collection<br />

that the view is created into does not need to be the same collection as the table it<br />

is built over. Any collection or library could be used. The following display is the<br />

result of running the <strong>SQL</strong> statement:<br />

SELECT * FROM SAMPLECOLL.RECENT_ORDERS<br />

Chapter 2. Getting Started with <strong>SQL</strong> 29


Display Data<br />

Data width ......: 26<br />

Position to line . . . . . Shift to column . . . . . .<br />

....+....1....+....2....+.<br />

ITEM L<strong>AS</strong>T QUANTITY<br />

NUMBER ORDER ON<br />

DATE HAND<br />

303476 05/30/94 100<br />

******** End of data ********<br />

Bottom<br />

F3=Exit F12=Cancel F19=Left F20=Right F21=Split<br />

The only row selected by the view is the row that we updated to have the current<br />

date. All other dates in our table still have the null value so they are not returned.<br />

Example: Creating a view combining data from more than one<br />

table<br />

You can create a view that combines data from two or more tables by naming<br />

more than one table in the FROM clause. In the following example, the<br />

INVENTORY_LIST table contains a column of item numbers called<br />

ITEM_NUMBER, and a column with the cost of the item, UNIT_COST. These are<br />

joined with the ITEM_NUMBER column and the SUPPLIER_COST column of the<br />

SUPPLIERS table. A WHERE clause is used to limit the number of rows returned.<br />

The view will only contain those item numbers <strong>for</strong> suppliers that can supply an<br />

item at lower cost than the current unit cost.<br />

The CREATE VIEW statement looks like this:<br />

CREATE VIEW SAMPLECOLL.LOWER_COST <strong>AS</strong><br />

SELECT SUPPLIER_NUMBER, A.ITEM_NUMBER, UNIT_COST, SUPPLIER_COST<br />

FROM SAMPLECOLL.INVENTORY_LIST A, SAMPLECOLL.SUPPLIERS B<br />

WHERE A.ITEM_NUMBER = B.ITEM_NUMBER<br />

AND UNIT_COST > SUPPLIER_COST<br />

The following table is the result of running the <strong>SQL</strong> statement:<br />

SELECT * FROM SAMPLECOLL.LOWER_COST<br />

Display Data<br />

Data width ......: 51<br />

Position to line . . . . . Shift to column . . . . . .<br />

....+....1....+....2....+....3....+....4....+....5.<br />

SUPPLIER_NUMBER ITEM UNIT SUPPLIER_COST<br />

NUMBER COST<br />

9988 153047 10.00 8.00<br />

2424 153047 10.00 9.00<br />

1234 229740 1.50 1.00<br />

3366 303476 2.00 1.50<br />

3366 073956 20.00 17.00<br />

******** End of data ********<br />

Bottom<br />

F3=Exit F12=Cancel F19=Left F20=Right F21=Split<br />

The rows that can be seen through this view are only those rows that have a<br />

supplier cost that is less than the unit cost.<br />

30 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


Chapter 3. Basic <strong>Concepts</strong> and Techniques<br />

This chapter explains some of the concepts used in <strong>SQL</strong> statements. It discusses<br />

many of the common statements and clauses in <strong>SQL</strong>. The examples in this chapter<br />

refer to the tables shown in Appendix A. <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> Sample Tables.<br />

Using basic <strong>SQL</strong> statements and clauses<br />

This section shows the basic <strong>SQL</strong> statements and clauses that retrieve, update,<br />

delete, and insert data into tables and views. The <strong>SQL</strong> statements used are<br />

SELECT, UPDATE, DELETE, and INSERT. FETCH statements can be used in an<br />

application program to access data as well. This statement is covered in Chapter 4.<br />

Examples using these <strong>SQL</strong> statements are supplied to help you develop <strong>SQL</strong><br />

applications. Detailed syntax and parameter descriptions <strong>for</strong> <strong>SQL</strong> statements are<br />

given in the <strong>SQL</strong> Reference book.<br />

You can write <strong>SQL</strong> statements on one line or on many lines. The rules <strong>for</strong> the<br />

continuation of lines are the same as those of the host language (the language the<br />

program is written in).<br />

Notes:<br />

1. The <strong>SQL</strong> statements described in this section can be run on <strong>SQL</strong> tables and<br />

views, and database physical and logical files. The tables, views, and files can<br />

be either in an <strong>SQL</strong> collection or in a library.<br />

2. Character strings specified in an <strong>SQL</strong> statement (such as those used with<br />

WHERE or VALUES clauses) are case sensitive; that is, uppercase characters<br />

must be entered in uppercase and lowercase characters must be entered in<br />

lowercase.<br />

WHERE ADMRDEPT='a00' (does not return a result)<br />

WHERE ADMRDEPT='A00' (returns a valid department number)<br />

Comparisons may not be case sensitive if a shared-weight sort sequence is<br />

being used where uppercase and lowercase characters are treated as the same<br />

character.<br />

Inserting rows using the INSERT statement<br />

You can use the INSERT statement to add new rows to a table or view in one of<br />

the following ways:<br />

v Specifying values in the INSERT statement <strong>for</strong> columns of the single row to be<br />

added.<br />

v Specifying the blocked <strong>for</strong>m of the INSERT statement to add multiple rows.<br />

“Inserting multiple rows in a table with the blocked INSERT statement” on<br />

page 70 explains how to use the blocked <strong>for</strong>m of the INSERT statement to add<br />

multiple rows to a table.<br />

v Including a select-statement in the INSERT statement to tell <strong>SQL</strong> what data <strong>for</strong><br />

the new row is contained in another table or view. “Inserting rows into a table<br />

using a Select-Statement” on page 69 explains how to use the select-statement<br />

within an INSERT statement to add zero, one, or many rows to a table.<br />

© Copyright IBM Corp. 2000 31


Note: Because views are built on tables and actually contain no data, working with<br />

views can be confusing. See “Creating and using views” on page 95 <strong>for</strong> more<br />

in<strong>for</strong>mation on inserting data by using a view.<br />

For every row you insert, you must supply a value <strong>for</strong> each column defined with<br />

the NOT NULL attribute if that column does not have a default value. The INSERT<br />

statement <strong>for</strong> adding a row to a table or view may look like this:<br />

INSERT INTO table-name<br />

(column1, column2, ... )<br />

VALUES (value-<strong>for</strong>-column1, value-<strong>for</strong>-column2, ... )<br />

The INTO clause names the columns <strong>for</strong> which you specify values. The VALUES<br />

clause specifies a value <strong>for</strong> each column named in the INTO clause.<br />

You must provide a value in the VALUES clause <strong>for</strong> each column named in an<br />

INSERT statement’s column list. The column name list can be omitted if all<br />

columns in the table have a value provided in the VALUES clause. If a column has<br />

a default value, the keyword DEFAULT may be used as a value on the VALUES<br />

clause.<br />

It is a good idea to name all columns into which you are inserting values because:<br />

v Your INSERT statement is more descriptive.<br />

v You can verify that you are giving the values in the proper order based on the<br />

column names.<br />

v You have better data independence. The order in which the columns are defined<br />

in the table does not affect your INSERT statement.<br />

If the column is defined to allow null values or to have a default, you do not need<br />

to name it in the column name list or specify a value <strong>for</strong> it. The default value is<br />

used. If the column is defined to have a default value, the default value is placed<br />

in the column. If DEFAULT was specified <strong>for</strong> the column definition without an<br />

explicit default value, <strong>SQL</strong> places the default value <strong>for</strong> that data type in the<br />

column. If the column does not have a default value defined <strong>for</strong> it, but is defined<br />

to allow the null value (NOT NULL was not specified in the column definition),<br />

<strong>SQL</strong> places the null value in the column.<br />

v For numeric columns, the default value is 0.<br />

v For fixed length character or graphic columns, the default is blanks.<br />

v For varying length character or graphic columns or LOB columns, the default is<br />

a zero length string.<br />

v For date, time, and timestamp columns, the default value is the current date,<br />

time, or timestamp. When inserting a block of records, the default date/time<br />

value is extracted from the system when the block is written. This means that<br />

the column will be assigned the same default value <strong>for</strong> each row in the block.<br />

v For DataLink columns, the default value corresponds to DLVALUE(’’,’URL’,’’).<br />

v For distinct-type columns, the default value is the default value of the<br />

corresponding source type.<br />

When your program attempts to insert a row that duplicates another row already<br />

in the table, an error might occur. Multiple null values may or may not be<br />

considered duplicate values, depending on the option used when the index was<br />

created.<br />

v If the table has a primary key, unique key, or unique index, the row is not<br />

inserted. Instead, <strong>SQL</strong> returns an <strong>SQL</strong>CODE of −803.<br />

32 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


v If the table does not have a primary key, unique key, or unique index, the row<br />

can be inserted without error.<br />

If <strong>SQL</strong> finds an error while running the INSERT statement, it stops inserting data.<br />

If you specify COMMIT(*ALL), COMMIT(*CS), COMMIT(*CHG), or<br />

COMMIT(*RR), no rows are inserted. Rows already inserted by this statement, in<br />

the case of INSERT with a select-statement or blocked insert, are deleted. If you<br />

specify COMMIT(*NONE), any rows already inserted are not deleted.<br />

A table created by <strong>SQL</strong> is created with the Reuse Deleted Records parameter of<br />

*YES. This allows the database manager to reuse any rows in the table that were<br />

marked as deleted. The CHGPF command can be used to change the attribute to<br />

*NO. This causes INSERT to always add rows to the end of the table.<br />

The order in which rows are inserted does not guarantee the order in which they<br />

will be retrieved.<br />

If the row is inserted without error, the <strong>SQL</strong>ERRD(3) field of the <strong>SQL</strong>CA has a<br />

value of 1.<br />

Note: For blocked INSERT or <strong>for</strong> INSERT with select-statement, more than one<br />

row can be inserted. The number of rows inserted is reflected in<br />

<strong>SQL</strong>ERRD(3).<br />

Changing data in a table using the UPDATE statement<br />

To change the data in a table, use the UPDATE statement. With the UPDATE<br />

statement, you can change the value of one or more columns in each row that<br />

satisfies the search condition of the WHERE clause. The result of the UPDATE<br />

statement is one or more changed column values in zero or more rows of a table<br />

(depending on how many rows satisfy the search condition specified in the<br />

WHERE clause). The UPDATE statement looks like this:<br />

UPDATE table-name<br />

SET column-1 = value-1,<br />

column-2 = value-2, ...<br />

WHERE search-condition ...<br />

For example, suppose an employee was relocated. To update several items of the<br />

employee’s data in the CORPDATA.EMPLOYEE table to reflect the move, you can<br />

specify:<br />

UPDATE CORPDATA.EMPLOYEE<br />

SET JOB = :PGM-CODE,<br />

PHONENO = :PGM-PHONE<br />

WHERE EMPNO = :PGM-SERIAL<br />

Use the SET clause to specify a new value <strong>for</strong> each column you want to update.<br />

The SET clause names the columns you want updated and provides the values you<br />

want them changed to. The value you specify can be:<br />

A column name. Replace the column’s current value with the contents of<br />

another column in the same row.<br />

A constant. Replace the column’s current value with the value provided in the<br />

SET clause.<br />

A null value. Replace the column’s current value with the null value, using the<br />

keyword NULL. The column must be defined as capable of containing a null<br />

value when the table was created, or an error occurs.<br />

Chapter 3. Basic <strong>Concepts</strong> and Techniques 33


A host variable. Replace the column’s current value with the contents of a host<br />

variable.<br />

A special register. Replace the column’s current value with a special register<br />

value; <strong>for</strong> example, USER.<br />

An expression. Replace the column’s current value with the value that results<br />

from an expression. The expression can contain any of the values in this list.<br />

A scalar subselect. Replace the column’s current value with the value that the<br />

subquery returns.<br />

The DEFAULT keyword. Replace the column’s current value with the default<br />

value of the column. The column must have a default value defined <strong>for</strong> it or<br />

allow the NULL value, or an error occurs.<br />

The following is an example of a statement that uses many different values:<br />

UPDATE WORKTABLE<br />

SET COL1 = '<strong>AS</strong>C',<br />

COL2 = NULL,<br />

COL3 = :FIELD3,<br />

COL4 = CURRENT TIME,<br />

COL5 = AMT - 6.00,<br />

COL6 = COL7<br />

WHERE EMPNO = :PGM-SERIAL<br />

To identify the rows to be updated, use the WHERE clause:<br />

v To update a single row, use a WHERE clause that selects only one row.<br />

v To update several rows, use a WHERE clause that selects only the rows you<br />

want to update.<br />

You can omit the WHERE clause. If you do, <strong>SQL</strong> updates each row in the table or<br />

view with the values you supply.<br />

If the database manager finds an error while running your UPDATE statement, it<br />

stops updating and returns a negative <strong>SQL</strong>CODE. If you specify COMMIT(*ALL),<br />

COMMIT(*CS), COMMIT(*CHG), or COMMIT(*RR), no rows in the table are<br />

changed (rows already changed by this statement, if any, are restored to their<br />

previous values). If COMMIT(*NONE) is specified, any rows already changed are<br />

not restored to previous values.<br />

If the database manager cannot find any rows that satisfy the search condition, an<br />

<strong>SQL</strong>CODE of +100 is returned.<br />

Note: UPDATE with a WHERE clause may have updated more than one row. The<br />

number of rows updated is reflected in <strong>SQL</strong>ERRD(3).<br />

Removing rows from a table using the DELETE statement<br />

To remove rows from a table, use the DELETE statement. When you DELETE a<br />

row, you remove the entire row. DELETE does not remove specific columns from<br />

the row. The result of the DELETE statement is the removal of zero or more rows<br />

of a table (depending on how many rows satisfy the search condition specified in<br />

the WHERE clause). If you omit the WHERE clause from a DELETE statement,<br />

<strong>SQL</strong> removes all the rows of the table. The DELETE statement looks like this:<br />

DELETE FROM table-name<br />

WHERE search-condition ...<br />

34 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


For example, suppose department D11 was moved to another place. You want to<br />

delete each row in the CORPDATA.EMPLOYEE table with a WORKDEPT value of<br />

D11 as follows:<br />

DELETE FROM CORPDATA.EMPLOYEE<br />

WHERE WORKDEPT = 'D11'<br />

The WHERE clause tells <strong>SQL</strong> which rows you want to delete from the table. <strong>SQL</strong><br />

deletes all the rows that satisfy the search condition from the base table. You can<br />

omit the WHERE clause, but it is best to include one, because a DELETE statement<br />

without a WHERE clause deletes all the rows from the table or view. To delete a<br />

table definition as well as the table contents, issue the DROP statement (described<br />

in the <strong>SQL</strong> Reference book).<br />

If <strong>SQL</strong> finds an error while running your DELETE statement, it stops deleting data<br />

and returns a negative <strong>SQL</strong>CODE. If you specify COMMIT(*ALL), COMMIT(*CS),<br />

COMMIT(*CHG), or COMMIT(*RR), no rows in the table are deleted (rows already<br />

deleted by this statement, if any, are restored to their previous values). If<br />

COMMIT(*NONE) is specified, any rows already deleted are not restored to their<br />

previous values.<br />

If <strong>SQL</strong> cannot find any rows that satisfy the search condition, an <strong>SQL</strong>CODE of<br />

+100 is returned.<br />

Note: DELETE with WHERE clause may have deleted more than one row. The<br />

number of rows deleted is reflected in <strong>SQL</strong>ERRD(3).<br />

Querying data using the SELECT INTO statement<br />

You can use a variety of statements and clauses to query your data. One way to do<br />

this is to use the SELECT INTO statement in a program to retrieve a specific row<br />

(<strong>for</strong> example, the row <strong>for</strong> an employee). Furthermore, in this example, a variety of<br />

clauses are used to gather data in a specific way. You can use the “Specifying a<br />

search condition using the WHERE clause” on page 38, “The GROUP BY clause”<br />

on page 41, “HAVING clause” on page 42, and “ORDER BY clause” on page 43 to<br />

tailor your query to gather data in a specific manner.<br />

The <strong>for</strong>mat and syntax shown here are very basic. SELECT INTO statements can<br />

be more varied than the examples presented in this chapter. A SELECT INTO<br />

statement can include the following:<br />

1. The name of each column you want<br />

2. The name of each host variable used to contain retrieved data<br />

3. The name of the table or view that contains the data<br />

4. A search condition to uniquely identify the row that contains the in<strong>for</strong>mation<br />

you want<br />

5. The name of each column used to group your data<br />

6. A search condition that uniquely identifies a group that contains the<br />

in<strong>for</strong>mation you want<br />

7. The order of the results so a specific row among duplicates can be returned.<br />

A SELECT INTO statement looks like this:<br />

SELECT column names<br />

INTO host variables<br />

FROM table or view name<br />

Chapter 3. Basic <strong>Concepts</strong> and Techniques 35


WHERE search condition<br />

GROUP BY column names<br />

HAVING search condition<br />

ORDER BY column-name<br />

The SELECT, INTO, and FROM clauses must be specified. The other clauses are<br />

optional.<br />

The INTO clause names the host variables (variables in your program used to<br />

contain retrieved column values). The value of the first column specified in the<br />

SELECT clause is put into the first host variable named in the INTO clause; the<br />

second value is put into the second host variable, and so on.<br />

The result table <strong>for</strong> a SELECT INTO should contain just one row. For example,<br />

each row in the CORPDATA.EMPLOYEE table has a unique EMPNO (employee<br />

number) column. The result of a SELECT INTO statement <strong>for</strong> this table if the<br />

WHERE clause contains an equal comparison on the EMPNO column, would be<br />

exactly one row (or no rows). Finding more than one row is an error, but one row<br />

is still returned. You can control which row will be returned in this error condition<br />

by specifying the ORDER BY clause. If you use the ORDER BY clause, the first row<br />

in the result table is returned.<br />

If you want more than one row to be the result of a select-statement, use a<br />

DECLARE CURSOR statement to select the rows, followed by a FETCH statement<br />

to move the column values into host variables one or many rows at a time. Using<br />

cursors is described in “Chapter 4. Using a Cursor” on page 55.<br />

The FROM clause names the table (or view) that contains the data you are<br />

interested in.<br />

For example, assume that each department listed in the<br />

CORPDATA.DEPARTMENT table has a unique department number. You want to<br />

retrieve the department name and manager number from the<br />

CORPDATA.DEPARTMENT table <strong>for</strong> department C01. To do this, your program<br />

can set PGM-DEPT to the value C01 and issue:<br />

SELECT DEPTNAME, MGRNO<br />

INTO :PGM-DEPTNAME, :PGM-MGRNO<br />

FROM CORPDATA.DEPARTMENT<br />

WHERE DEPTNO = :PGM-DEPT<br />

When the statement is run, the result is one row:<br />

PGM-DEPTNAME<br />

PGM-<br />

MGRNO<br />

INFORMATION CENTER 000030<br />

These values are assigned to the host variables PGM-DEPTNAME and<br />

PGM-MGRNO.<br />

If <strong>SQL</strong> is unable to find a row that satisfies the search condition, an <strong>SQL</strong>CODE of<br />

+100 is returned.<br />

If <strong>SQL</strong> finds errors while running your select-statement, a negative <strong>SQL</strong>CODE is<br />

returned. If <strong>SQL</strong> finds more host variables than results, +326 is returned.<br />

36 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


You can retrieve data from a view in exactly the same way you retrieve data from<br />

a table. However, there are several restrictions when you attempt to update, insert,<br />

or delete data in a view. These restrictions are described in “Creating and using<br />

views” on page 95.<br />

Data retrieval errors<br />

If <strong>SQL</strong> finds that a retrieved character or graphic column is too long to be placed<br />

in a host variable, <strong>SQL</strong> does the following:<br />

v Truncates the data while assigning the value to the host variable.<br />

v Sets <strong>SQL</strong>WARN0 and <strong>SQL</strong>WARN1 in the <strong>SQL</strong>CA to the value 'W'.<br />

v Sets the indicator variable, if provided, to the length of the value be<strong>for</strong>e<br />

truncation.<br />

If <strong>SQL</strong> finds a data mapping error while running a statement, one of two things<br />

occurs:<br />

v If the error occurs on an expression in the SELECT list and an indicator variable<br />

is provided <strong>for</strong> the expression in error:<br />

– <strong>SQL</strong> returns a −2 <strong>for</strong> the indicator variable corresponding to the expression in<br />

error.<br />

– <strong>SQL</strong> returns all valid data <strong>for</strong> that row.<br />

– <strong>SQL</strong> returns a positive <strong>SQL</strong>CODE.<br />

v If an indicator variable is not provided, <strong>SQL</strong> returns the corresponding negative<br />

<strong>SQL</strong>CODE in the <strong>SQL</strong>CA.<br />

Data mapping errors include:<br />

v +138 - Argument of the substringing function is not valid.<br />

v +180 - Syntax <strong>for</strong> a string representation of a date, time, or timestamp is not<br />

valid.<br />

v +181 - String representation of a date, time, or timestamp is not a valid value.<br />

v +183 - Invalid result from a date/time expression. The resulting date or<br />

timestamp is not within the valid range of dates or timestamps.<br />

v +191 - MIXED data is not properly <strong>for</strong>med.<br />

v +304 - Numeric conversion error (<strong>for</strong> example, overflow, underflow, or division<br />

by zero).<br />

v +331 - Characters cannot be converted.<br />

v +420 - Character in the C<strong>AS</strong>T argument is not valid.<br />

v +802 - Data conversion or data mapping error.<br />

For data mapping errors, the <strong>SQL</strong>CA reports only the last error detected. The<br />

indicator variable corresponding to each result column having an error is set to −2.<br />

If the full-select contains DISTINCT in the select list and a column in the select list<br />

contains numeric data that is not valid, the data is considered equal to a null value<br />

if the query is completed as a sort. If an existing index is used, the data is not<br />

considered equal to a null.<br />

The impact of data mapping errors on the ORDER BY clause depends on the<br />

situation:<br />

v If the data mapping error occurs while data is being assigned to a host variable<br />

in a SELECT INTO or FETCH statement, and that same expression is used in the<br />

Chapter 3. Basic <strong>Concepts</strong> and Techniques 37


ORDER BY clause, the result record is ordered based on the value of the<br />

expression. It is not ordered as if it were a null (higher than all other values).<br />

This is because the expression was evaluated be<strong>for</strong>e the assignment to the host<br />

variable is attempted.<br />

v If the data mapping error occurs while an expression in the select-list is being<br />

evaluated and the same expression is used in the ORDER BY clause, the result<br />

column is normally ordered as if it were a null value (higher than all other<br />

values). If the ORDER BY clause is implemented by using a sort, the result<br />

column is ordered as if it were a null value. If the ORDER BY clause is<br />

implemented by using an existing index, in the following cases, the result<br />

column is ordered based on the actual value of the expression in the index:<br />

– The expression is a date column with a date <strong>for</strong>mat of *MDY, *DMY, *YMD,<br />

or *JUL, and a date conversion error occurs because the date is not within the<br />

valid range <strong>for</strong> dates.<br />

– The expression is a character column and a character could not be converted.<br />

– The expression is a decimal column and a numeric value that is not valid is<br />

detected.<br />

The SELECT clause<br />

With the SELECT clause (the first part of a select-statement), you specify the name<br />

of each column you want to retrieve. For example:<br />

SELECT EMPNO, L<strong>AS</strong>TNAME, WORKDEPT<br />

.<br />

You can specify that only one column be retrieved, or as many as 8000 columns.<br />

The value of each column you name is retrieved in the order specified in the<br />

SELECT clause.<br />

If you want to retrieve all columns (in the same order as they appear in the row),<br />

use an asterisk (*) instead of naming the columns:<br />

SELECT *<br />

.<br />

When using the select-statement in an application program, list the column names<br />

to give your program more data independence. There are two reasons <strong>for</strong> this:<br />

1. When you look at the source code statement, you can easily see the one-to-one<br />

correspondence between the column names in the SELECT clause and the host<br />

variables named in the INTO clause.<br />

2. If a column is added to a table or view you access and you use “SELECT * ...,”<br />

and you create the program again from source, the INTO clause does not have<br />

a matching host variable named <strong>for</strong> the new column. The extra column causes<br />

you to get a warning (not an error) in the <strong>SQL</strong>CA (<strong>SQL</strong>WARN4 will contain a<br />

“W”).<br />

Specifying a search condition using the WHERE clause<br />

The WHERE clause specifies a search condition that identifies the row or rows you<br />

want to retrieve, update, or delete. The number of rows you process with an <strong>SQL</strong><br />

statement then depends on the number of rows that satisfy the WHERE clause<br />

38 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


search condition. A search condition consists of one or more predicates. A<br />

predicate specifies a test that you want <strong>SQL</strong> to apply to a specified row or rows of<br />

a table.<br />

In the following example, WORKDEPT = 'C01' is a predicate, WORKDEPT and<br />

'C01' are expressions, and the equal sign (=) is a comparison operator. Note that<br />

character values are enclosed in apostrophes ('); numeric values are not. This<br />

applies to all constant values wherever they are coded within an <strong>SQL</strong> statement.<br />

For example, to specify that you are interested in the rows where the department<br />

number is C01, you would say:<br />

... WHERE WORKDEPT = 'C01'<br />

In this case, the search condition consists of one predicate: WORKDEPT = 'C01'.<br />

If the search condition contains character or UCS-2 graphic column predicates, the<br />

sort sequence that is in effect when the query is run is applied to those predicates.<br />

See “Sort sequences in <strong>SQL</strong>” on page 50 <strong>for</strong> more in<strong>for</strong>mation on sort sequence<br />

and selection.<br />

Expressions in the WHERE Clause<br />

An expression in a WHERE clause names or specifies something you want to<br />

compare to something else. Each expression, when evaluated by <strong>SQL</strong>, is a character<br />

string, date/time/timestamp, or a numeric value. The expressions you specify can<br />

be:<br />

v A column name names a column. For example:<br />

... WHERE EMPNO = '000200'<br />

EMPNO names a column that is defined as a 6-byte character value. Equality<br />

comparisons (that is, X = Y or X Y) can be per<strong>for</strong>med on character data.<br />

Other types of comparisons can also be evaluated <strong>for</strong> character data.<br />

However, you cannot compare character strings to numbers. You also cannot<br />

per<strong>for</strong>m arithmetic operations on character data (even though EMPNO is a<br />

character string that appears to be a number). You can add and subtract<br />

date/time values.<br />

v An expression identifies two values that are added (+), subtracted (−),<br />

multiplied (*), divided (/), have exponentiation (**), or concatenated (CONCAT<br />

or ||) to result in a value. The operands of an expression can be:<br />

A constant (that is, a literal value)<br />

A column<br />

A host variable<br />

A value returned from a function<br />

A special register<br />

Another expression<br />

For example:<br />

... WHERE INTEGER(PRENDATE - PRSTDATE) > 100<br />

When the order of evaluation is not specified by parentheses, the expression is<br />

evaluated in the following order:<br />

1. Prefix operators<br />

2. Exponentiation<br />

Chapter 3. Basic <strong>Concepts</strong> and Techniques 39


3. Multiplication, division, and concatenation<br />

4. Addition and subtraction<br />

Operators on the same precedence level are applied from left to right.<br />

v A constant specifies a literal value <strong>for</strong> the expression. For example:<br />

... WHERE <strong>400</strong>00 < SALARY<br />

SALARY names a column that is defined as an 9-digit packed decimal value<br />

(DECIMAL(9,2)). It is compared to the numeric constant <strong>400</strong>00.<br />

v A host variable identifies a variable in an application program. For example:<br />

... WHERE EMPNO = :EMP<br />

v A special register identifies a special value generated by the database manager.<br />

For example:<br />

... WHERE L<strong>AS</strong>TNAME = USER<br />

v The NULL value specifies the condition of having an unknown value.<br />

... WHERE DUE_DATE IS NULL<br />

A search condition need not be limited to two column names or constants<br />

separated by arithmetic or comparison operators. You can develop a complex<br />

search condition that specifies several predicates separated by AND and OR. No<br />

matter how complex the search condition, it supplies a TRUE or FALSE value<br />

when evaluated against a row. There is also an unknown truth value, which is<br />

effectively false. That is, if the value of a row is null, this null value is not returned<br />

as a result of a search because it is not less than, equal to, or greater than the value<br />

specified in the search condition. More complex search conditions and predicates<br />

are described in “Per<strong>for</strong>ming complex search conditions” on page 72.<br />

To fully understand the WHERE clause, you need to know how <strong>SQL</strong> evaluates<br />

search conditions and predicates, and compares the values of expressions. This<br />

topic is discussed in the <strong>SQL</strong> Reference book.<br />

Comparison operators<br />

<strong>SQL</strong> supports the following comparison operators:<br />

= Equal to<br />

or ¬= or != Not equal to<br />

< Less than<br />

> Greater than<br />

or !> Less than or equal to (or not greater than)<br />

>=or¬< or !< Greater than or equal to (or not less than)<br />

NOT Keyword<br />

You can precede a predicate with the NOT keyword to specify that you want the<br />

opposite of the predicate’s value (that is, TRUE if the predicate is FALSE, or vice<br />

versa). NOT applies only to the predicate it precedes, not to all predicates in the<br />

WHERE clause. For example, to indicate that you are interested in all employees<br />

except those working in department C01, you could say:<br />

... WHERE NOT WORKDEPT = 'C01'<br />

which is equivalent to:<br />

... WHERE WORKDEPT 'C01'<br />

40 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


The GROUP BY clause<br />

Without a GROUP BY clause, the application of <strong>SQL</strong> column functions returns one<br />

row. When GROUP BY is used, the function is applied to each group, thereby<br />

returning as many rows as there are groups.<br />

The GROUP BY clause allows you to find the characteristics of groups of rows<br />

rather than individual rows. When you specify a GROUP BY clause, <strong>SQL</strong> divides<br />

the selected rows into groups such that the rows of each group have matching<br />

values in one or more columns or expressions. Next, <strong>SQL</strong> processes each group to<br />

produce a single-row result <strong>for</strong> the group. You can specify one or more columns or<br />

expressions in the GROUP BY clause to group the rows. The items you specify in<br />

the SELECT statement are properties of each group of rows, not properties of<br />

individual rows in a table or view.<br />

For example, the CORPDATA.EMPLOYEE table has several sets of rows, and each<br />

set consists of rows describing members of a specific department. To find the<br />

average salary of people in each department, you could issue:<br />

The <strong>SQL</strong> statement: Results in:<br />

fetch WORK-DEPT AVG-SALARY<br />

1 A00<br />

42833<br />

2 B01<br />

41250<br />

... ...<br />

...<br />

RV2W551-1<br />

The result is several rows, one <strong>for</strong> each department.<br />

Notes:<br />

1. Grouping the rows does not mean ordering them. Grouping puts each selected<br />

row in a group, which <strong>SQL</strong> then processes to derive characteristics of the<br />

group. Ordering the rows puts all the rows in the results table in ascending or<br />

descending collating sequence. ( “ORDER BY clause” on page 43 describes how<br />

to do this.)<br />

2. If there are null values in the column you specify in the GROUP BY clause, a<br />

single-row result is produced <strong>for</strong> the data in the rows with null values.<br />

3. If the grouping occurs over character or UCS-2 graphic columns, the sort<br />

sequence in effect when the query is run is applied to the grouping. See “Sort<br />

sequences in <strong>SQL</strong>” on page 50 <strong>for</strong> more in<strong>for</strong>mation on sort sequence and<br />

selection.<br />

When you use GROUP BY, you list the columns or expressions you want <strong>SQL</strong> to<br />

use to group the rows. For example, suppose you want a list of the number of<br />

people working on each major project described in the CORPDATA.PROJECT<br />

table. You could issue:<br />

Chapter 3. Basic <strong>Concepts</strong> and Techniques 41


The <strong>SQL</strong> statement: Results in:<br />

The result is a list of the company’s current major projects and the number of<br />

people working on each project.<br />

You can also specify that you want the rows grouped by more than one column or<br />

expression. For example, you could issue a select-statement to find the average<br />

salary <strong>for</strong> men and women in each department, using the CORPDATA.EMPLOYEE<br />

table. To do this, you could issue:<br />

The <strong>SQL</strong> statement: Results in:<br />

Because you did not include a WHERE clause in this example, <strong>SQL</strong> examines and<br />

process all rows in the CORPDATA.EMPLOYEE table. The rows are grouped first<br />

by department number and next (within each department) by sex be<strong>for</strong>e <strong>SQL</strong><br />

derives the average SALARY value <strong>for</strong> each group.<br />

HAVING clause<br />

fetch SUM-PR MAJ-PROJ<br />

1 6 AD3100<br />

2 5 AD3110<br />

3 10 MA2100<br />

... ... ...<br />

RV2W552-3<br />

fetch DEPT SEX AVG-WAGES<br />

1 A00 F 52750<br />

2 A00 M 37875<br />

3 B01 M 41250<br />

4 C01 F 30156<br />

... ... ... ...<br />

RV2W553-1<br />

You can use the HAVING clause to specify a search condition <strong>for</strong> the groups<br />

selected based on a GROUP BY clause. The HAVING clause says that you want<br />

only those groups that satisfy the condition in that clause. There<strong>for</strong>e, the search<br />

condition you specify in the HAVING clause must test properties of each group<br />

rather than properties of individual rows in the group.<br />

The HAVING clause follows the GROUP BY clause and can contain the same kind<br />

of search condition you can specify in a WHERE clause. In addition, you can<br />

specify column functions in a HAVING clause. For example, suppose you wanted<br />

to retrieve the average salary of women in each department. To do this, you would<br />

use the AVG column function and group the resulting rows by WORKDEPT and<br />

specify a WHERE clause of SEX = 'F'.<br />

42 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


To specify that you want this data only when all the female employees in the<br />

selected department have an education level equal to or greater than 16 (a college<br />

graduate), use the HAVING clause. The HAVING clause tests a property of the<br />

group. In this case, the test is on MIN(EDLEVEL), which is a group property:<br />

The <strong>SQL</strong> statement: Results in:<br />

You can use multiple predicates in a HAVING clause by connecting them with<br />

AND and OR, and you can use NOT <strong>for</strong> any predicate of a search condition.<br />

Note: If you intend to update a column or delete a row, you cannot include a<br />

GROUP BY or HAVING clause in the SELECT statement within a DECLARE<br />

CURSOR statement. (The DECLARE CURSOR statement is described in<br />

“Chapter 4. Using a Cursor” on page 55.)<br />

Predicates with arguments that are not column functions can be coded in either<br />

WHERE or HAVING clauses. It is usually more efficient to code the selection<br />

criteria in the WHERE clause. It is processed during the initial phase of the query<br />

processing. The HAVING selection is per<strong>for</strong>med in post processing of the result<br />

table.<br />

If the search condition contains predicates involving character or UCS-2 graphic<br />

columns, the sort sequence in effect when the query is run is applied to those<br />

predicates. See “Sort sequences in <strong>SQL</strong>” on page 50 <strong>for</strong> more in<strong>for</strong>mation on sort<br />

sequence and selection.<br />

ORDER BY clause<br />

fetch DEPT AVG-WAGES MIN-EDUC<br />

1<br />

2<br />

3<br />

A00<br />

C01<br />

D11<br />

52750<br />

30156<br />

24476<br />

You can specify that you want selected rows retrieved in a particular order, sorted<br />

by ascending or descending collating sequence of a column’s value, with the<br />

ORDER BY clause. You can use an ORDER BY clause as you would a GROUP BY<br />

clause: specify the columns or expressions you want <strong>SQL</strong> to use when retrieving<br />

the rows in a collated sequence.<br />

For example, to retrieve the names and department numbers of female employees<br />

listed in the alphanumeric order of their department numbers, you could use this<br />

select-statement:<br />

18<br />

16<br />

17<br />

RV2W554-3<br />

Chapter 3. Basic <strong>Concepts</strong> and Techniques 43


The <strong>SQL</strong> statement: Results in:<br />

Notes:<br />

1. All columns named in the ORDER BY clause must also be named in the<br />

SELECT list.<br />

2. Null values are ordered as the highest value.<br />

To order by a column function, or something other than a column name, you can<br />

specify an <strong>AS</strong> clause in the select-list. To order by an expression, you can either<br />

specify the exact same expression in the ORDER BY clause, or you can specify an<br />

<strong>AS</strong> clause in the select-list.<br />

The <strong>AS</strong> clause names the result column. This name can be specified in the ORDER<br />

BY clause. To order by a name specified in the <strong>AS</strong> clause:<br />

v The name must be unique in the select-list.<br />

v The name must not be qualified.<br />

For example, to retrieve the full name of employees listed in alphabetic order, you<br />

could use this select-statement:<br />

SELECT L<strong>AS</strong>TNAME CONCAT FIRSTNAME <strong>AS</strong> FULLNAME ...<br />

ORDER BY FULLNAME<br />

This select-statement could optionally be written as:<br />

SELECT L<strong>AS</strong>TNAME CONCAT FIRSTNAME<br />

ORDER BY L<strong>AS</strong>TNAME CONCAT FIRSTNAME<br />

fetch PGM-NAME3 DEPT<br />

1<br />

2<br />

3<br />

4<br />

5<br />

6<br />

7<br />

8<br />

9<br />

10<br />

11<br />

12<br />

13<br />

HA<strong>AS</strong><br />

KWAN<br />

QUINTANA<br />

NICHOLLS<br />

PIANKA<br />

SCOUTTEN<br />

LUTZ<br />

PUL<strong>AS</strong>KI<br />

JOHNSON<br />

PEREZ<br />

HENDERSON<br />

SCHNEIDER<br />

SETRIGHT<br />

A00<br />

C01<br />

C01<br />

C01<br />

D11<br />

D11<br />

D11<br />

D21<br />

D21<br />

D21<br />

E11<br />

E11<br />

E11<br />

RV2W555-3<br />

Instead of naming the columns to order the results, you can use a number. For<br />

example, ORDER BY 3 specifies that you want the results ordered by the third<br />

column of the results table, as specified by the select-statement. Use a number to<br />

order the rows of the results table when the sequencing value is not a named<br />

column.<br />

You can also specify whether you want <strong>SQL</strong> to collate the rows in ascending (<strong>AS</strong>C)<br />

or descending (DESC) sequence. An ascending collating sequence is the default. In<br />

the above select-statement, <strong>SQL</strong> first returns the row with the lowest department<br />

44 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


number (alphabetically and numerically), followed by rows with higher<br />

department numbers. To order the rows in descending collating sequence based on<br />

the department number, specify:<br />

... ORDER BY WORKDEPT DESC<br />

As with GROUP BY, you can specify a secondary ordering sequence (or several<br />

levels of ordering sequences) as well as a primary one. In the example above, you<br />

might want the rows ordered first by department number, and within each<br />

department, ordered by employee name. To do this, specify:<br />

... ORDER BY WORKDEPT, L<strong>AS</strong>TNAME<br />

If character columns or UCS-2 graphic columns are used in the ORDER BY clause,<br />

ordering <strong>for</strong> these columns is based on the sort sequence in effect when the query<br />

is run. See “Sort sequences in <strong>SQL</strong>” on page 50 <strong>for</strong> more in<strong>for</strong>mation on sort<br />

sequence and its affect on ordering.<br />

Null Values to indicate absence of column values in a row<br />

A null value indicates the absence of a column value in a row. A null value is not<br />

the same as zero or all blanks. A null value is the same as “unknown”. Null values<br />

can be used as a condition in the WHERE and HAVING clauses, and as a<br />

mathematical argument. For example, a WHERE clause can specify a column that,<br />

<strong>for</strong> some rows, contains a null value. Normally, a comparison predicate using a<br />

column that contains null values does not select a row that has a null value <strong>for</strong> the<br />

column. This is because a null value is neither less than, equal to, nor greater than<br />

the value specified in the condition. To select the values <strong>for</strong> all rows that contain a<br />

null value <strong>for</strong> the manager number, you could specify:<br />

SELECT DEPTNO, DEPTNAME, ADMRDEPT<br />

FROM CORPDATA.DEPARTMENT<br />

WHERE MGRNO IS NULL<br />

The result would be:<br />

DEPTNO DEPTNAME ADMRDEPT<br />

D01 DEVELOPMENT<br />

CENTER<br />

A00<br />

To get the rows that do not have a null value <strong>for</strong> the manager number, you could<br />

change the WHERE clause like this:<br />

WHERE MGRNO IS NOT NULL<br />

For more in<strong>for</strong>mation on the use of null values, see the <strong>SQL</strong> Reference book.<br />

Special registers in <strong>SQL</strong> statements<br />

You can specify certain “special registers” in <strong>SQL</strong> statements. For locally run <strong>SQL</strong><br />

statements, the special registers and their contents are shown in the following<br />

table:<br />

Special Registers Contents<br />

CURRENT DATE<br />

CURRENT_DATE<br />

The current date.<br />

Chapter 3. Basic <strong>Concepts</strong> and Techniques 45


Special Registers Contents<br />

CURRENT TIME<br />

CURRENT_TIME<br />

The current time.<br />

CURRENT TIMESTAMP<br />

The current date and time in timestamp<br />

CURRENT_TIMESTAMP<br />

<strong>for</strong>mat.<br />

CURRENT TIMEZONE<br />

A duration of time that links local time to<br />

CURRENT_TIMEZONE<br />

Universal Coordinated Time (UTC) using the<br />

<strong>for</strong>mula:<br />

local time - CURRENT TIMEZONE = UTC<br />

CURRENT SERVER<br />

CURRENT_SERVER<br />

It is taken from the system value<br />

QUTCOFFSET.<br />

The name of the relational database as<br />

contained in the relational database directory<br />

table in the relational database directory.<br />

USER The run-time authorization identifier (user<br />

profile) of the job.<br />

CURRENT PATH<br />

CURRENT_PATH<br />

CURRENT FUNCTION PATH<br />

The <strong>SQL</strong> path used to resolve unqualified<br />

data type names, procedure names, and<br />

function names.<br />

If a single statement contains more than one reference to any of CURRENT DATE,<br />

CURRENT TIME, or CURRENT TIMESTAMP special registers, or the CURDATE,<br />

CURTIME, or NOW scalar functions, all values are based on a single clock reading.<br />

For remotely run <strong>SQL</strong> statements, the special registers and their contents are shown<br />

in the following table:<br />

Special Registers Contents<br />

CURRENT DATE<br />

CURRENT_DATE<br />

CURRENT TIME<br />

CURRENT_TIME<br />

CURRENT TIMESTAMP<br />

CURRENT_TIMESTAMP<br />

CURRENT TIMEZONE<br />

CURRENT_TIMEZONE<br />

CURRENT SERVER<br />

CURRENT_SERVER<br />

The current date and time at the remote<br />

system, not the local system.<br />

A duration of time that links the remote<br />

system time to UTC.<br />

The name of the relational database as<br />

contained in the relational database directory<br />

table in the relational database directory.<br />

USER The run-time authorization identifier of the<br />

server job on the remote system.<br />

CURRENT PATH<br />

The current path value at the remote system.<br />

CURRENT_PATH<br />

CURRENT FUNCTION PATH<br />

When a query over a distributed table references a special register, the contents of<br />

the special register on the system that requests the query are used. For more<br />

in<strong>for</strong>mation on distributed tables, see <strong>DB2</strong> Multisystembook.<br />

46 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


Date, Time, and Timestamp data types<br />

Date, time, and timestamp are data types represented in an internal <strong>for</strong>m not seen<br />

by the <strong>SQL</strong> user. Date, time, and timestamp can be represented by character string<br />

values and assigned to character string variables. The database manager recognizes<br />

the following as date, time, and timestamp values:<br />

v A value returned by the DATE, TIME, or TIMESTAMP scalar functions.<br />

v A value returned by the CURRENT DATE, CURRENT TIME, or CURRENT<br />

TIMESTAMP special registers.<br />

v A character string when it is an operand of an arithmetic expression or a<br />

comparison and the other operand is a date, time, or timestamp. For example, in<br />

the predicate:<br />

... WHERE HIREDATE < '1950-01-01'<br />

if HIREDATE is a date column, the character string ’1950-01-01’ is interpreted as<br />

a date.<br />

v A character string variable or constant used to set a date, time, or timestamp<br />

column in either the SET clause of an UPDATE statement, or the VALUES clause<br />

of an INSERT statement.<br />

For more in<strong>for</strong>mation on character string <strong>for</strong>mats of date, time, and timestamp<br />

values, see Chapter 2 of the <strong>SQL</strong> Reference book .<br />

Specifying current date and time values<br />

You can specify a current date, time, or timestamp in an expression by specifying<br />

one of three special registers: CURRENT DATE, CURRENT TIME, or CURRENT<br />

TIMESTAMP. The value of each is based on a time-of-day clock reading obtained<br />

during the running of the statement. Multiple references to CURRENT DATE,<br />

CURRENT TIME, or CURRENT TIMESTAMP within the same <strong>SQL</strong> statement use<br />

the same value. The following statement returns the age (in years) of each<br />

employee in the EMPLOYEE table when the statement is run:<br />

SELECT YEAR(CURRENT DATE - BIRTHDATE)<br />

FROM CORPDATA.EMPLOYEE<br />

The CURRENT TIMEZONE special register allows a local time to be converted to<br />

Universal Coordinated Time (UTC). For example, if you have a table named<br />

DATETIME, containing a time column type with a name of STARTT, and you want<br />

to convert STARTT to UTC, you can use the following statement:<br />

SELECT STARTT - CURRENT TIMEZONE<br />

FROM DATETIME<br />

Date/Time arithmetic<br />

Addition and subtraction are the only arithmetic operators applicable to date, time,<br />

and timestamp values. You can increment and decrement a date, time, or<br />

timestamp by a duration; or subtract a date from a date, a time from a time, or a<br />

timestamp from a timestamp. For a detailed description of date and time<br />

arithmetic, see Chapter 2 of the <strong>SQL</strong> Reference book.<br />

Chapter 3. Basic <strong>Concepts</strong> and Techniques 47


Creating and using ALI<strong>AS</strong> names<br />

When you refer to an existing table or view to an <strong>AS</strong>/<strong>400</strong> physical file that consists<br />

of multiple members, you can avoid using file overrides by creating an alias. You<br />

can use the <strong>SQL</strong> CREATE ALI<strong>AS</strong> statement to do this. Or you can use Operations<br />

Navigator.<br />

You can create an alias <strong>for</strong><br />

v A table or view<br />

v A member of a table<br />

A table alias defines a name <strong>for</strong> the file, including the specific member name. You<br />

can use this alias name in an <strong>SQL</strong> statement in the same way that you would use a<br />

table name. Unlike overrides, alias names are objects that exist until they are<br />

dropped.<br />

For example, if there is a multiple member file MYLIB.MYFILE with members<br />

MBR1 and MBR2, an alias can be created <strong>for</strong> the second member so that <strong>SQL</strong> can<br />

easily refer to it.<br />

CREATE ALI<strong>AS</strong> MYLIB.MYMBR2_ALI<strong>AS</strong> FOR MYLIB.MYFILE (MBR2)<br />

When alias MYLIB.MYMBR2_ALI<strong>AS</strong> is specified on the following insert statement,<br />

the values are inserted into member MBR2 in MYLIB.MYFILE.<br />

INSERT INTO MYLIB.MYMBR2_ALI<strong>AS</strong> VALUES('ABC', 6)<br />

Alias names can also be specified on DDL statements. Assume that alias<br />

MYLIB.MYALI<strong>AS</strong> exists and is an alias <strong>for</strong> table MYLIB.MYTABLE. The following<br />

DROP statement will drop table MYLIB.MYTABLE.<br />

DROP TABLE MYLIB.MYALI<strong>AS</strong><br />

If you really want to drop the alias name instead, specify the ALI<strong>AS</strong> keyword on<br />

the drop statement:<br />

DROP ALI<strong>AS</strong> MYLIB.MYALI<strong>AS</strong><br />

Creating descriptive labels using the LABEL ON statement<br />

Sometimes the table name, column name, view name, alias name, or <strong>SQL</strong> package<br />

name does not clearly define data that is shown on an interactive display of the<br />

table. By using the LABEL ON statement, you can create a more descriptive label<br />

<strong>for</strong> the table name, column name, view name, alias name, or <strong>SQL</strong> package name.<br />

These labels can be seen in the <strong>SQL</strong> catalog in the LABEL column.<br />

The LABEL ON statement looks like this:<br />

LABEL ON<br />

TABLE CORPDATA.DEPARTMENT IS 'Department Structure Table'<br />

LABEL ON<br />

COLUMN CORPDATA.DEPARTMENT.ADMRDEPT IS 'Reports to Dept.'<br />

After these statements are run, the table named DEPARTMENT displays the text<br />

description as Department Structure Table and the column named ADMRDEPT<br />

displays the heading Reports to Dept. The label <strong>for</strong> tables, views, <strong>SQL</strong> packages, and<br />

48 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


column text cannot be more than 50 characters and the label <strong>for</strong> column headings<br />

cannot be more than 60 characters (blanks included). The following are examples<br />

of LABEL ON statements:<br />

This LABEL ON statement provides column heading 1 and column heading 2.<br />

*...+....1....+....2....+....3....+....4....+....5....+....6..*<br />

LABEL ON COLUMN CORPDATA.EMPLOYEE.EMPNO IS<br />

'Employee Number'<br />

This LABEL ON statement provides 3 levels of column headings <strong>for</strong> the SALARY<br />

column.<br />

*...+....1....+....2....+....3....+....4....+....5....+....6..*<br />

LABEL ON COLUMN CORPDATA.EMPLOYEE.SALARY IS<br />

'Yearly Salary (in dollars)'<br />

This LABEL ON statement removes the column heading <strong>for</strong> SALARY.<br />

*...+....1....+....2....+....3....+....4....+....5....+....6..*<br />

LABEL ON COLUMN CORPDATA.EMPLOYEE.SALARY IS ''<br />

An example of a DBCS column heading with two levels specified.<br />

*...+....1....+....2....+....3....+....4....+....5....+....6..*<br />

LABEL ON COLUMN CORPDATA.EMPLOYEE.SALARY IS<br />

' '<br />

This LABEL ON statement provides column text <strong>for</strong> the EDLEVEL column.<br />

*...+....1....+....2....+....3....+....4....+....5....+....6..*<br />

LABEL ON COLUMN CORPDATA.EMPLOYEE.EDLEVEL TEXT IS<br />

'Number of years of <strong>for</strong>mal education'<br />

For more in<strong>for</strong>mation about the LABEL ON statement, see the <strong>SQL</strong> Reference book.<br />

Describing an <strong>SQL</strong> object using COMMENT ON<br />

After you create an <strong>SQL</strong> object such as a table, view, index, package, procedure,<br />

parameter, user-defined type, or function, you can supply in<strong>for</strong>mation about it <strong>for</strong><br />

future referral, such as the purpose of the object, who uses it, and anything<br />

unusual or special about it. You can also include similar in<strong>for</strong>mation about each<br />

column of a table or view. Your comment must not be more than 2000 bytes.<br />

A comment is especially useful if your names do not clearly indicate the contents<br />

of the columns or objects. In that case, use a comment to describe the specific<br />

contents of the column or objects.<br />

An example of using COMMENT ON follows:<br />

COMMENT ON TABLE CORPDATA.EMPLOYEE IS<br />

'Employee table. Each row in this table represents<br />

one employee of the company.'<br />

Getting comments after running a COMMENT ON statement<br />

After running a COMMENT ON statement <strong>for</strong> a table, your comments are stored<br />

in the REMARKS column of SYSTABLES. Comments <strong>for</strong> the other objects are<br />

Chapter 3. Basic <strong>Concepts</strong> and Techniques 49


Sort sequences in <strong>SQL</strong><br />

stored in the REMARKS column of the appropriate catalog table. (If the indicated<br />

row had already contained a comment, the old comment is replaced by the new<br />

one.) The following example gets the comments added by the COMMENT ON<br />

statement in the previous example:<br />

SELECT REMARKS<br />

FROM CORPDATA.SYSTABLES<br />

WHERE NAME = 'EMPLOYEE'<br />

A sort sequence defines how characters in a character set relate to each other when<br />

they are compared or ordered. For more in<strong>for</strong>mation on sort sequences, see<br />

Chapter 1 in <strong>SQL</strong> Reference book.<br />

The sort sequence is used <strong>for</strong> all character and UCS-2 graphic comparisons<br />

per<strong>for</strong>med in <strong>SQL</strong> statements. There are sort sequence tables <strong>for</strong> both single byte<br />

and double byte character data. Each single byte sort sequence table has an<br />

associated double byte sort sequence table, and vice versa. Conversion between the<br />

two tables is per<strong>for</strong>med when necessary to implement a query. In addition, the<br />

CREATE INDEX statement has the sort sequence (in effect at the time the<br />

statement was run) applied to the character columns referred to in the index.<br />

Sort sequence used with ORDER BY and record selection<br />

To see how to use a sort sequence, run the examples in this section against the<br />

STAFF table shown in Table 2. Notice that the values in the JOB column are in<br />

mixed case. You can see the values 'Mgr', 'MGR', and 'mgr'.<br />

Table 2. The STAFF Table<br />

ID NAME DEPT JOB YEARS SALARY COMM<br />

10 Sanders 20 Mgr 7 18357.50 0<br />

20 Pernal 20 Sales 8 18171.25 612.45<br />

30 Merenghi 38 MGR 5 17506.75 0<br />

40 OBrien 38 Sales 6 18006.00 846.55<br />

50 Hanes 15 Mgr 10 20659.80 0<br />

60 Quigley 38 SALES 0 16808.30 650.25<br />

70 Rothman 15 Sales 7 16502.83 1152.00<br />

80 James 20 Clerk 0 13504.60 128.20<br />

90 Koonitz 42 sales 6 18001.75 1386.70<br />

100 Plotz 42 mgr 6 18352.80 0<br />

In the following examples, the results are shown <strong>for</strong> each statement using:<br />

v *HEX sort sequence<br />

v Shared-weight sort sequence using the language identifier ENU<br />

v Unique-weight sort sequence using the language identifier ENU<br />

Note: ENU is chosen as a language identifier by specifying either<br />

SRTSEQ(*LANGIDUNQ), or SRTSEQ(*LANGIDSHR) and LANGID(ENU),<br />

on the CRT<strong>SQL</strong>xxx, STR<strong>SQL</strong>, or RUN<strong>SQL</strong>STM commands, or by using the<br />

SET OPTION statement.<br />

50 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


ORDER BY<br />

The following <strong>SQL</strong> statement causes the result table to be sorted using the values<br />

in the JOB column:<br />

SELECT * FROM STAFF ORDER BY JOB<br />

Table 3 shows the result table using a *HEX sort sequence. The rows are sorted<br />

based on the EBCDIC value in the JOB column. In this case, all lowercase letters<br />

sort be<strong>for</strong>e the uppercase letters.<br />

Table 3. ″SELECT * FROM STAFF ORDER BY JOB″ Using the *HEX Sort Sequence.<br />

ID NAME DEPT JOB YEARS SALARY COMM<br />

100 Plotz 42 mgr 6 18352.80 0<br />

90 Koonitz 42 sales 6 18001.75 1386.70<br />

80 James 20 Clerk 0 13504.60 128.20<br />

10 Sanders 20 Mgr 7 18357.50 0<br />

50 Hanes 15 Mgr 10 20659.80 0<br />

30 Merenghi 38 MGR 5 17506.75 0<br />

20 Pernal 20 Sales 8 18171.25 612.45<br />

40 OBrien 38 Sales 6 18006.00 846.55<br />

70 Rothman 15 Sales 7 16502.83 1152.00<br />

60 Quigley 38 SALES 0 16808.30 650.25<br />

Table 4 shows how sorting is done <strong>for</strong> a unique-weight sort sequence. After the<br />

sort sequence is applied to the values in the JOB column, the rows are sorted.<br />

Notice that after the sort, lowercase letters are be<strong>for</strong>e the same uppercase letters,<br />

and the values 'mgr', 'Mgr', and 'MGR' are adjacent to each other.<br />

Table 4. ″SELECT * FROM STAFF ORDER BY JOB″ Using the Unique-Weight Sort<br />

Sequence <strong>for</strong> the ENU Language Identifier.<br />

ID NAME DEPT JOB YEARS SALARY COMM<br />

80 James 20 Clerk 0 13504.60 128.20<br />

100 Plotz 42 mgr 6 18352.80 0<br />

10 Sanders 20 Mgr 7 18357.50 0<br />

50 Hanes 15 Mgr 10 20659.80 0<br />

30 Merenghi 38 MGR 5 17506.75 0<br />

90 Koonitz 42 sales 6 18001.75 1386.70<br />

20 Pernal 20 Sales 8 18171.25 612.45<br />

40 OBrien 38 Sales 6 18006.00 846.55<br />

70 Rothman 15 Sales 7 16502.83 1152.00<br />

60 Quigley 38 SALES 0 16808.30 650.25<br />

Table 5 on page 52 shows how sorting is done <strong>for</strong> a shared-weight sort sequence.<br />

After the sort sequence is applied to the values in the JOB column, the rows are<br />

sorted. For the sort comparison, each lowercase letter is treated the same as the<br />

corresponding uppercase letter. In Table 5 on page 52, notice that all the values<br />

'MGR', 'mgr' and 'Mgr' are mixed together.<br />

Chapter 3. Basic <strong>Concepts</strong> and Techniques 51


Table 5. ″SELECT * FROM STAFF ORDER BY JOB″ Using the Shared-Weight Sort<br />

Sequence <strong>for</strong> the ENU Language Identifier.<br />

ID NAME DEPT JOB YEARS SALARY COMM<br />

80 James 20 Clerk 0 13504.60 128.20<br />

10 Sanders 20 Mgr 7 18357.50 0<br />

30 Merenghi 38 MGR 5 17506.75 0<br />

50 Hanes 15 Mgr 10 20659.80 0<br />

100 Plotz 42 mgr 6 18352.80 0<br />

20 Pernal 20 Sales 8 18171.25 612.45<br />

40 OBrien 38 Sales 6 18006.00 846.55<br />

60 Quigley 38 SALES 0 16808.30 650.25<br />

70 Rothman 15 Sales 7 16502.83 1152.00<br />

90 Koonitz 42 sales 6 18001.75 1386.70<br />

Record selection<br />

The following <strong>SQL</strong> statement selects records with the value 'MGR' in the JOB<br />

column:<br />

SELECT * FROM STAFF WHERE JOB='MGR'<br />

Table 6 shows how record selection is done with a *HEX sort sequence. In Table 6,<br />

the rows that match the record selection criteria <strong>for</strong> the column 'JOB' are selected<br />

exactly as specified in the select statement. Only the uppercase 'MGR' is selected.<br />

Table 6. ″SELECT * FROM STAFF WHERE JOB=’MGR’ Using the *HEX Sort Sequence.″<br />

ID NAME DEPT JOB YEARS SALARY COMM<br />

30 Merenghi 38 MGR 5 17506.75 0<br />

Table 7 shows how record selection is done with a unique-weight sort sequence. In<br />

Table 7, the lowercase and uppercase letters are treated as unique. The lowercase<br />

'mgr' is not treated the same as uppercase 'MGR'. There<strong>for</strong>e, the lower case 'mgr' is<br />

not selected.<br />

Table 7. ″SELECT * FROM STAFF WHERE JOB = ’MGR’ ″ Using Unique-Weight Sort<br />

Sequence <strong>for</strong> the ENU Language Identifier.<br />

ID NAME DEPT JOB YEARS SALARY COMM<br />

30 Merenghi 38 MGR 5 17506.75 0<br />

Table 8 shows how record selection is done with a shared-weight sort sequence. In<br />

Table 8, the rows that match the record selection criteria <strong>for</strong> the column 'JOB' are<br />

selected by treating uppercase letters the same as lowercase letters. Notice that in<br />

Table 8 all the values 'mgr', 'Mgr' and 'MGR' are selected.<br />

Table 8. ″SELECT * FROM STAFF WHERE JOB = ’MGR’ ″ Using the Shared-Weight Sort<br />

Sequence <strong>for</strong> the ENU Language Identifier.<br />

ID NAME DEPT JOB YEARS SALARY COMM<br />

10 Sanders 20 Mgr 7 18357.50 0<br />

30 Merenghi 38 MGR 5 17506.75 0<br />

50 Hanes 15 Mgr 10 20659.80 0<br />

52 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


Table 8. ″SELECT * FROM STAFF WHERE JOB = ’MGR’ ″ Using the Shared-Weight Sort<br />

Sequence <strong>for</strong> the ENU Language Identifier. (continued)<br />

ID NAME DEPT JOB YEARS SALARY COMM<br />

100 Plotz 42 mgr 6 18352.80 0<br />

Sort sequence and views<br />

Views are created with the sort sequence that was in effect when the CREATE<br />

VIEW statement was run. When the view is referred to in a FROM clause, that sort<br />

sequence is used <strong>for</strong> any character comparisons in the subselect of the CREATE<br />

VIEW. At that time, an intermediate result table is produced from the view<br />

subselect. The sort sequence in effect when the query is being run is then applied<br />

to all the character and UCS-2 graphic comparisons (including those comparisons<br />

involving implicit conversions to character or UCS-2 graphic) specified in the<br />

query.<br />

The following <strong>SQL</strong> statements and tables show how views and sort sequences<br />

work. View V1, used in the following examples, was created with a shared-weight<br />

sort sequence of SRTSEQ(*LANGIDSHR) and LANGID(ENU). The CREATE VIEW<br />

statement would be as follows:<br />

CREATE VIEW V1 <strong>AS</strong> SELECT *<br />

FROM STAFF<br />

WHERE JOB = 'MGR' AND ID < 100<br />

Table 9 shows the result table from the view.<br />

Table 9. ″SELECT * FROM V1″<br />

ID NAME DEPT JOB YEARS SALARY COMM<br />

10 Sanders 20 Mgr 7 18357.50 0<br />

30 Merenghi 38 MGR 5 17506.75 0<br />

50 Hanes 15 Mgr 10 20659.80 0<br />

Any queries run against view V1 are run against the result table shown in Table 9.<br />

The query shown below is run with a sort sequence of SRTSEQ(*LANGIDUNQ)<br />

and LANGID(ENU).<br />

Table 10. ″SELECT * FROM V1 WHERE JOB = ’MGR’″ Using the Unique-Weight Sort<br />

Sequence <strong>for</strong> Language Identifier ENU<br />

ID NAME DEPT JOB YEARS SALARY COMM<br />

30 Merenghi 38 MGR 5 17506.75 0<br />

Sort Sequence and the CREATE INDEX Statement<br />

Indexes are created using the sort sequence that was in effect when the CREATE<br />

INDEX statement was run. An entry is added to the index every time an insert is<br />

made into the table over which the index is defined. Index entries contain the<br />

weighted value <strong>for</strong> character key and UCS-2 graphic key columns. The system gets<br />

the weighted value by converting the key value based on the sort sequence of the<br />

index.<br />

When selection is made using that sort sequence and that index, the character or<br />

UCS-2 graphic keys do not need to be converted prior to comparison. This<br />

improves the per<strong>for</strong>mance of the query.<br />

Chapter 3. Basic <strong>Concepts</strong> and Techniques 53


Sort sequence and constraints<br />

Unique constraints are implemented with indexes. If the table on which a unique<br />

constraint is added was defined with a sort sequence, the index will be created<br />

with that same sort sequence.<br />

If defining a referential constraint, the sort sequence between the parent and<br />

dependent table must match. For more in<strong>for</strong>mation on sort sequence and<br />

constraints, see the Database <strong>Programming</strong> book.<br />

The sort sequence used at the time a check constraint is defined is the same sort<br />

sequence the system uses to validate adherence to the constraint at the time of an<br />

INSERT or UPDATE.<br />

54 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


Chapter 4. Using a Cursor<br />

Types of cursors<br />

When <strong>SQL</strong> runs a select statement, the resulting rows comprise the result table. A<br />

cursor provides a way to access a result table. It is used within an <strong>SQL</strong> program to<br />

maintain a position in the result table. <strong>SQL</strong> uses a cursor to work with the rows in<br />

the result table and to make them available to your program. Your program can<br />

have several cursors, although each must have a unique name.<br />

Statements related to using a cursor include the following:<br />

v A DECLARE CURSOR statement to define and name the cursor and specify the<br />

rows to be retrieved with the embedded select statement.<br />

v OPEN and CLOSE statements to open and close the cursor <strong>for</strong> use within the<br />

program. The cursor must be opened be<strong>for</strong>e any rows can be retrieved.<br />

v A FETCH statement to retrieve rows from the cursor’s result table or to position<br />

the cursor on another row.<br />

v An UPDATE ... WHERE CURRENT OF statement to update the current row of a<br />

cursor.<br />

v A DELETE ... WHERE CURRENT OF statement to delete the current row of a<br />

cursor.<br />

<strong>SQL</strong> supports serial and scrollable cursors. The type of cursor determines the<br />

positioning methods which can be used with the cursor.<br />

Serial cursor<br />

A serial cursor is one defined without the SCROLL keyword.<br />

For a serial cursor, each row of the result table can be fetched only once per OPEN<br />

of the cursor. When the cursor is opened, it is positioned be<strong>for</strong>e the first row in the<br />

result table. When a FETCH is issued, the cursor is moved to the next row in the<br />

result table. That row is then the current row. If host variables are specified (with<br />

the INTO clause on the FETCH statement), <strong>SQL</strong> moves the current row’s contents<br />

into your program’s host variables.<br />

This sequence is repeated each time a FETCH statement is issued until the<br />

end-of-data (<strong>SQL</strong>CODE = 100) is reached. When you reach the end-of-data, close<br />

the cursor. You cannot access any rows in the result table after you reach the<br />

end-of-data. To use the cursor again, you must first close the cursor and then<br />

re-issue the OPEN statement. You can never back up.<br />

Scrollable cursor<br />

For a scrollable cursor, the rows of the result table can be fetched many times. The<br />

cursor is moved through the result table based on the position option specified on<br />

the FETCH statement. When the cursor is opened, it is positioned be<strong>for</strong>e the first<br />

row in the result table. When a FETCH is issued, the cursor is positioned to the<br />

row in the result table that is specified by the position option. That row is then the<br />

current row. If host variables are specified (with the INTO clause on the FETCH<br />

© Copyright IBM Corp. 2000 55


Example of using a cursor<br />

statement), <strong>SQL</strong> moves the current row’s contents into your program’s host<br />

variables. Host variables cannot be specified <strong>for</strong> the BEFORE and AFTER position<br />

options.<br />

This sequence is repeated each time a FETCH statement is issued. The cursor does<br />

not need to be closed when an end-of-data or beginning-of-data condition occurs.<br />

The position options enable the program to continue fetching rows from the table.<br />

The following scroll options are used to position the cursor when issuing a FETCH<br />

statement. These positions are relative to the current cursor location in the result<br />

table.<br />

NEXT Positions the cursor on the next row. This is the default if no<br />

position is specified.<br />

PRIOR Positions the cursor on the previous row.<br />

FIRST Positions the cursor on the first row.<br />

L<strong>AS</strong>T Positions the cursor on the last row.<br />

BEFORE Positions the cursor be<strong>for</strong>e the first row.<br />

AFTER Positions the cursor after the last row.<br />

CURRENT Does not change the cursor position.<br />

RELATIVE n Evaluates a host variable or integer n in relationship to the<br />

cursor’s current position. For example, if n is -1, the cursor is<br />

positioned on the previous row of the result table. If n is +3,<br />

the cursor is positioned three rows after the current row.<br />

Suppose your program examines data about people in department D11. The<br />

following examples show the <strong>SQL</strong> statements you would include in a program to<br />

define and use a serial and a scrollable cursor. These cursors can be used to obtain<br />

in<strong>for</strong>mation about the department from the CORPDATA.EMPLOYEE table.<br />

For the serial cursor example, the program processes all of the rows from the table,<br />

updating the job <strong>for</strong> all members of department D11 and deleting the records of<br />

employees from the other departments.<br />

Table 11. A Serial Cursor Example<br />

Serial Cursor <strong>SQL</strong> Statement Described in Section<br />

EXEC <strong>SQL</strong><br />

“Step 1: Define the cursor” on page 58.<br />

DECLARE THISEMP CURSOR FOR<br />

SELECT EMPNO, L<strong>AS</strong>TNAME,<br />

WORKDEPT, JOB<br />

FROM CORPDATA.EMPLOYEE<br />

FORUPDATEOFJOB<br />

END-EXEC.<br />

EXEC <strong>SQL</strong><br />

OPEN THISEMP<br />

END-EXEC.<br />

EXEC <strong>SQL</strong><br />

WHENEVER NOT FOUND<br />

GO TO CLOSE-THISEMP<br />

END-EXEC.<br />

56 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5<br />

“Step 2: Open the cursor” on page 59.<br />

“Step 3: Specify what to do when end-of-data<br />

is reached” on page 59.


Table 11. A Serial Cursor Example (continued)<br />

Serial Cursor <strong>SQL</strong> Statement Described in Section<br />

EXEC <strong>SQL</strong><br />

“Step 4: Retrieve a row using a cursor” on<br />

FETCH THISEMP<br />

page 60.<br />

INTO :EMP-NUM, :NAME2,<br />

:DEPT, :JOB-CODE<br />

END-EXEC.<br />

... <strong>for</strong> all employees<br />

in department D11, update<br />

the JOB value:<br />

EXEC <strong>SQL</strong><br />

UPDATE CORPDATA.EMPLOYEE<br />

SET JOB = :NEW-CODE<br />

WHERE CURRENT OF THISEMP<br />

END-EXEC.<br />

... then print the row.<br />

... <strong>for</strong> other employees,<br />

delete the row:<br />

EXEC <strong>SQL</strong><br />

DELETE FROM CORPDATA.EMPLOYEE<br />

WHERE CURRENT OF THISEMP<br />

END-EXEC.<br />

Branch back to fetch and process the next<br />

row.<br />

CLOSE-THISEMP.<br />

EXEC <strong>SQL</strong><br />

CLOSE THISEMP<br />

END-EXEC.<br />

“Step 5a: Update the current row” on<br />

page 61.<br />

“Step 5b: Delete the current row” on page 61.<br />

“Step 6: Close the cursor” on page 62.<br />

For the scrollable cursor example, the program uses the RELATIVE position option<br />

to obtain a representative sample of salaries from department D11.<br />

Table 12. Scrollable Cursor Example<br />

Scrollable Cursor <strong>SQL</strong> Statement Described in Section<br />

EXEC <strong>SQL</strong><br />

“Step 1: Define the cursor” on page 58.<br />

DECLARE THISEMP DYNAMIC SCROLL CURSOR FOR<br />

SELECT EMPNO, L<strong>AS</strong>TNAME,<br />

SALARY<br />

FROM CORPDATA.EMPLOYEE<br />

WHERE WORKDEPT = ’D11’<br />

END-EXEC.<br />

EXEC <strong>SQL</strong><br />

OPEN THISEMP<br />

END-EXEC.<br />

EXEC <strong>SQL</strong><br />

WHENEVER NOT FOUND<br />

GO TO CLOSE-THISEMP<br />

END-EXEC.<br />

“Step 2: Open the cursor” on page 59.<br />

“Step 3: Specify what to do when end-of-data<br />

is reached” on page 59.<br />

Chapter 4. Using a Cursor 57


Table 12. Scrollable Cursor Example (continued)<br />

Scrollable Cursor <strong>SQL</strong> Statement Described in Section<br />

...initialize program summation<br />

“Step 4: Retrieve a row using a cursor” on<br />

salary variable<br />

page 60.<br />

EXEC <strong>SQL</strong><br />

FETCH RELATIVE 3 FROM THISEMP<br />

INTO :EMP-NUM, :NAME2,<br />

:JOB-CODE<br />

END-EXEC.<br />

...add the current salary to<br />

program summation salary<br />

...branch back to fetch and<br />

process the next row.<br />

...calculate the average<br />

salary<br />

CLOSE-THISEMP.<br />

EXEC <strong>SQL</strong><br />

CLOSE THISEMP<br />

END-EXEC.<br />

Step 1: Define the cursor<br />

“Step 6: Close the cursor” on page 62.<br />

To define a result table to be accessed with a cursor, use the DECLARE CURSOR<br />

statement.<br />

The DECLARE CURSOR statement names a cursor and specifies a select-statement.<br />

The select-statement defines a set of rows that, conceptually, make up the result<br />

table. For a serial cursor, the statement looks like this (the FOR UPDATE OF clause<br />

is optional):<br />

EXEC <strong>SQL</strong><br />

DECLARE cursor-name CURSOR FOR<br />

SELECT column-1, column-2 ,...<br />

FROM table-name , ...<br />

FOR UPDATE OF column-2 ,...<br />

END-EXEC.<br />

For a scrollable cursor, the statement looks like this (the WHERE clause is<br />

optional):<br />

EXEC <strong>SQL</strong><br />

DECLARE cursor-name DYNAMIC SCROLL CURSOR FOR<br />

SELECT column-1, column-2 ,...<br />

FROM table-name ,...<br />

WHERE column-1 = expression ...<br />

END-EXEC.<br />

The select-statements shown here are rather simple. However, you can code several<br />

other types of clauses in a select-statement within a DECLARE CURSOR statement<br />

<strong>for</strong> a serial and a scrollable cursor.<br />

If you intend to update any columns in any or all of the rows of the identified<br />

table (the table named in the FROM clause), include the FOR UPDATE OF clause.<br />

It names each column you intend to update. If you do not specify the names of<br />

columns, and you specify either the ORDER BY clause or FOR READ ONLY<br />

clause, a negative <strong>SQL</strong>CODE is returned if an update is attempted. If you do not<br />

58 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


specify the FOR UPDATE OF clause, the FOR READ ONLY clause, or the ORDER<br />

BY clause, and the result table is not read-only, you can update any of the columns<br />

of the specified table.<br />

You can update a column of the identified table even though it is not part of the<br />

result table. In this case, you do not need to name the column in the SELECT<br />

statement. When the cursor retrieves a row (using FETCH) that contains a column<br />

value you want to update, you can use UPDATE ... WHERE CURRENT OF to<br />

update the row.<br />

For example, assume that each row of the result table includes the EMPNO,<br />

L<strong>AS</strong>TNAME, and WORKDEPT columns from the CORPDATA.EMPLOYEE table. If<br />

you want to update the JOB column (one of the columns in each row of the<br />

CORPDATA.EMPLOYEE table), the DECLARE CURSOR statement should include<br />

FOR UPDATE OF JOB ... even though JOB is omitted from the SELECT statement.<br />

The result table and cursor are read-only if any of the following are true:<br />

v The first FROM clause identifies more than one table or view.<br />

v The first FROM clause identifies a read-only view.<br />

v The first SELECT clause specifies the keyword DISTINCT.<br />

v The outer subselect contains a GROUP BY clause.<br />

v The outer subselect contains a HAVING clause.<br />

v The first SELECT clause contains a column function.<br />

v The select-statement contains a subquery such that the base object of the outer<br />

subselect and of the subquery is the same table.<br />

v The select-statement contains a UNION or UNION ALL operator.<br />

v The select-statement contains an ORDER BY clause, and the FOR UPDATE OF<br />

clause and DYNAMIC SCROLL are not specified.<br />

v The select-statement includes a FOR READ ONLY clause.<br />

v The SCROLL keyword is specified without DYNAMIC.<br />

v The select-list includes a DataLink column and a FOR UPDATE OF clause is not<br />

specified.<br />

Step 2: Open the cursor<br />

To begin processing the rows of the result table, issue the OPEN statement. When<br />

your program issues the OPEN statement, <strong>SQL</strong> processes the select-statement<br />

within the DECLARE CURSOR statement to identify a set of rows, called a result<br />

table 3 , using the current value of any host variables specified in the<br />

select-statement. The OPEN statement looks like this:<br />

EXEC <strong>SQL</strong><br />

OPEN cursor-name<br />

END-EXEC.<br />

Step 3: Specify what to do when end-of-data is reached<br />

To find out when the end of the result table is reached, test the <strong>SQL</strong>CODE field <strong>for</strong><br />

a value of 100 or test the <strong>SQL</strong>STATE field <strong>for</strong> a value of '02000' (that is,<br />

3. A result table can contain zero, one, or many rows, depending on the extent to which the search condition is satisfied.<br />

Chapter 4. Using a Cursor 59


end-of-data). This condition occurs when the FETCH statement has retrieved the<br />

last row in the result table and your program issues a subsequent FETCH. For<br />

example:<br />

...<br />

IF <strong>SQL</strong>CODE =100 GO TO DATA-NOT-FOUND.<br />

or<br />

IF <strong>SQL</strong>STATE ='02000' GO TO DATA-NOT-FOUND.<br />

An alternative to this technique is to code the WHENEVER statement. Using<br />

WHENEVER NOT FOUND can result in a branch to another part of your<br />

program, where a CLOSE statement is issued. The WHENEVER statement looks<br />

like this:<br />

EXEC <strong>SQL</strong><br />

WHENEVER NOT FOUND GO TO symbolic-address<br />

END-EXEC.<br />

Your program should anticipate an end-of-data condition whenever a cursor is<br />

used to fetch a row, and should be prepared to handle this situation when it<br />

occurs.<br />

When you are using a serial cursor and the end-of-data is reached, every<br />

subsequent FETCH statement returns the end-of-data condition. You cannot<br />

position the cursor on rows that are already processed. The CLOSE statement is<br />

the only operation that can be per<strong>for</strong>med on the cursor.<br />

When you are using a scrollable cursor and the end-of-data is reached, the result<br />

table can still process more data. You can position the cursor anywhere in the<br />

result table using a combination of the position options. You do not need to<br />

CLOSE the cursor when the end-of-data is reached.<br />

Step 4: Retrieve a row using a cursor<br />

To move the contents of a selected row into your program’s host variables, use the<br />

FETCH statement. The SELECT statement within the DECLARE CURSOR<br />

statement identifies rows that contain the column values your program wants.<br />

However, <strong>SQL</strong> does not retrieve any data <strong>for</strong> your application program until the<br />

FETCH statement is issued.<br />

When your program issues the FETCH statement, <strong>SQL</strong> uses the current cursor<br />

position as a starting point to locate the requested row in the result table. This<br />

changes that row to the current row. If an INTO clause was specified, <strong>SQL</strong> moves<br />

the current row’s contents into your program’s host variables. This sequence is<br />

repeated each time the FETCH statement is issued.<br />

<strong>SQL</strong> maintains the position of the current row (that is, the cursor points to the<br />

current row) until the next FETCH statement <strong>for</strong> the cursor is issued. The UPDATE<br />

statement does not change the position of the current row within the result table,<br />

although the DELETE statement does.<br />

The serial cursor FETCH statement looks like this:<br />

EXEC <strong>SQL</strong><br />

FETCH cursor-name<br />

INTO :host variable-1[, :host variable-2] ...<br />

END-EXEC.<br />

60 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


The scrollable cursor FETCH statement looks like this:<br />

EXEC <strong>SQL</strong><br />

FETCH RELATIVE integer<br />

FROM cursor-name<br />

INTO :host variable-1[, :host variable-2] ...<br />

END-EXEC.<br />

Step 5a: Update the current row<br />

When your program has positioned the cursor on a row, you can update its data<br />

by using the UPDATE statement with the WHERE CURRENT OF clause. The<br />

WHERE CURRENT OF clause specifies a cursor that points to the row you want to<br />

update. The UPDATE ... WHERE CURRENT OF statement looks like this:<br />

EXEC <strong>SQL</strong><br />

UPDATE table-name<br />

SET column-1 = value [, column-2 = value] ...<br />

WHERE CURRENT OF cursor-name<br />

END-EXEC.<br />

When used with a cursor, the UPDATE statement:<br />

v Updates only one row—the current row<br />

v Identifies a cursor that points to the row to be updated<br />

v Requires that the columns updated be named previously in the FOR UPDATE<br />

OF clause of the DECLARE CURSOR statement, if an ORDER BY clause was<br />

also specified<br />

After you update a row, the cursor’s position remains on that row (that is, the<br />

current row of the cursor does not change) until you issue a FETCH statement <strong>for</strong><br />

the next row.<br />

Step 5b: Delete the current row<br />

When your program has retrieved the current row, you can delete the row by<br />

using the DELETE statement. To do this, you issue a DELETE statement designed<br />

<strong>for</strong> use with a cursor; the WHERE CURRENT OF clause specifies a cursor that<br />

points to the row you want to delete. The DELETE ... WHERE CURRENT OF<br />

statement looks like this:<br />

EXEC <strong>SQL</strong><br />

DELETE FROM table-name<br />

WHERE CURRENT OF cursor-name<br />

END-EXEC.<br />

When used with a cursor, the DELETE statement:<br />

v Deletes only one row—the current row<br />

v Uses the WHERE CURRENT OF clause to identify a cursor that points to the<br />

row to be deleted<br />

After you delete a row, you cannot update or delete another row using that cursor<br />

until you issue a FETCH statement to position the cursor.<br />

“Removing rows from a table using the DELETE statement” on page 34 shows you<br />

how to use the DELETE statement to delete all rows that meet a specific search<br />

condition. You can also use the FETCH and DELETE ... WHERE CURRENT OF<br />

statements when you want to obtain a copy of the row, examine it, then delete it.<br />

Chapter 4. Using a Cursor 61


Step 6: Close the cursor<br />

If you processed the rows of a result table <strong>for</strong> a serial cursor, and you want to use<br />

the cursor again, issue a CLOSE statement to close the cursor prior to re-opening<br />

it.<br />

EXEC <strong>SQL</strong><br />

CLOSE cursor-name<br />

END-EXEC.<br />

If you processed the rows of a result table and you do not want to use the cursor<br />

again, you can let the system close the cursor. The system automatically closes the<br />

cursor when:<br />

v A COMMIT without HOLD statement is issued and the cursor is not declared<br />

using the WITH HOLD clause.<br />

v A ROLLBACK without HOLD statement is issued.<br />

v The job ends.<br />

v The activation group ends and CLO<strong>SQL</strong>CSR(*ENDACTGRP) was specified on<br />

the precompile.<br />

v The first <strong>SQL</strong> program in the call stack ends and neither<br />

CLO<strong>SQL</strong>CSR(*ENDJOB) or CLO<strong>SQL</strong>CSR(*ENDACTGRP) was specified when<br />

the program was precompiled.<br />

v The connection to the application server is ended using the DISCONNECT<br />

statement.<br />

v The connection to the application server was released and a successful COMMIT<br />

occurred.<br />

v An *RUW CONNECT occurred.<br />

Because an open cursor still holds locks on referred-to-tables or views, you<br />

should explicitly close any open cursors as soon as they are no longer needed.<br />

Using the multiple-row FETCH statement<br />

The multiple-row FETCH statement can be used to retrieve multiple rows from a<br />

table or view with a single FETCH. The program controls the blocking of rows by<br />

the number of rows requested on the FETCH statement (OVRDBF has no effect).<br />

The maximum number of rows that can be requested on a single fetch call is<br />

32767. Once the data is retrieved, the cursor is positioned on the last row retrieved.<br />

There are two ways to define the storage where fetched rows are placed: a host<br />

structure array or a row storage area with an associated descriptor. Both methods<br />

can be coded in all of the languages supported by the <strong>SQL</strong> precompilers, with the<br />

exception of the host structure array in REXX. Refer to the <strong>SQL</strong> <strong>Programming</strong> with<br />

Host Languages in<strong>for</strong>mation <strong>for</strong> details on the programming languages. Both <strong>for</strong>ms<br />

of the multiple-row FETCH statement allow the application to code a separate<br />

indicator array. The indicator array should contain one indicator <strong>for</strong> each host<br />

variable that is null capable.<br />

The multiple-row FETCH statement can be used with both serial and scrollable<br />

cursors. The operations used to define, open, and close a cursor <strong>for</strong> a multiple-row<br />

FETCH remain the same. Only the FETCH statement changes to specify the<br />

number of rows to retrieve and the storage where the rows are placed.<br />

62 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


After each multiple-row FETCH, in<strong>for</strong>mation is returned to the program through<br />

the <strong>SQL</strong>CA. In addition to the <strong>SQL</strong>CODE and <strong>SQL</strong>STATE fields, the <strong>SQL</strong>ERRD<br />

provides the following in<strong>for</strong>mation:<br />

v <strong>SQL</strong>ERRD3 contains the number of rows retrieved on the multiple-row FETCH<br />

statement. If <strong>SQL</strong>ERRD3 is less than the number of rows requested, then an<br />

error or end-of-data condition occurred.<br />

v <strong>SQL</strong>ERRD4 contains the length of each row retrieved.<br />

v <strong>SQL</strong>ERRD5 contains an indication that the last row in the table was fetched. It<br />

can be used to detect the end-of-data condition in the table being fetched when<br />

the cursor does not have immediate sensitivity to updates. Cursors which do<br />

have immediate sensitivity to updates should continue fetching until an<br />

<strong>SQL</strong>CODE +100 is received to detect an end-of-data condition.<br />

Multiple-row FETCH using a host structure array<br />

To use the multiple-row FETCH with the host structure array, the application must<br />

define a host structure array that can be used by <strong>SQL</strong>. Each language has its own<br />

conventions and rules <strong>for</strong> defining a host structure array. Host structure arrays can<br />

be defined by using variable declarations or by using compiler directives to<br />

retrieve External File Descriptions (such as the COBOL COPY directive).<br />

The host structure array consists of an array of structures. Each structure<br />

corresponds to one row of the result table. The first structure in the array<br />

corresponds to the first row, the second structure in the array corresponds to the<br />

second row, and so on. <strong>SQL</strong> determines the attributes of elementary items in the<br />

host structure array based on the declaration of the host structure array. To<br />

maximize per<strong>for</strong>mance, the attributes of the items that make up the host structure<br />

array should match the attributes of the columns being retrieved.<br />

Consider the following COBOL example:<br />

...<br />

...<br />

...<br />

EXEC <strong>SQL</strong> INCLUDE <strong>SQL</strong>CA<br />

END-EXEC.<br />

01 TABLE-1.<br />

02 DEPT OCCURS 10 TIMES.<br />

05 EMPNO PIC X(6).<br />

05 L<strong>AS</strong>TNAME.<br />

49 L<strong>AS</strong>TNAME-LEN PIC S9(4) BINARY.<br />

49 L<strong>AS</strong>TNAME-TEXT PIC X(15).<br />

05 WORKDEPT PIC X(3).<br />

05 JOB PIC X(8).<br />

01 TABLE-2.<br />

02 IND-ARRAY OCCURS 10 TIMES.<br />

05 INDS PIC S9(4) BINARY OCCURS 4 TIMES.<br />

EXEC <strong>SQL</strong><br />

DECLARE D11 CURSOR FOR<br />

SELECT EMPNO, L<strong>AS</strong>TNAME, WORKDEPT, JOB<br />

FROM CORPDATA.EMPLOYEE<br />

WHERE WORKDEPT = "D11"<br />

END-EXEC.<br />

EXEC <strong>SQL</strong><br />

OPEN D11<br />

Chapter 4. Using a Cursor 63


...<br />

...<br />

END-EXEC.<br />

PERFORM FETCH-PARA UNTIL <strong>SQL</strong>CODE NOT EQUAL TO ZERO.<br />

ALL-DONE.<br />

EXEC <strong>SQL</strong> CLOSE D11 END-EXEC.<br />

FETCH-PARA.<br />

EXEC <strong>SQL</strong> WHENEVER NOT FOUND GO TO ALL-DONE END-EXEC.<br />

EXEC <strong>SQL</strong> FETCH D11 FOR 10 ROWS INTO :DEPT :IND-ARRAY<br />

END-EXEC.<br />

In this example, a cursor was defined <strong>for</strong> the CORPDATA.EMPLOYEE table to<br />

select all rows where the WORKDEPT column equals 'D11'. The result table<br />

contains eight rows. The DECLARE CURSOR and OPEN statements do not have<br />

any special syntax when they are used with a multiple-row FETCH statement.<br />

Another FETCH statement that returns a single row against the same cursor can be<br />

coded elsewhere in the program. The multiple-row FETCH statement is used to<br />

retrieve all of the rows in the result table. Following the FETCH, the cursor<br />

position remains on the last row retrieved.<br />

The host structure array DEPT and the associated indicator array IND-ARRAY are<br />

defined in the application. Both arrays have a dimension of ten. The indicator<br />

array has an entry <strong>for</strong> each column in the result table.<br />

The attributes of type and length of the DEPT host structure array elementary<br />

items match the columns that are being retrieved.<br />

When the multiple-row FETCH statement has successfully completed, the host<br />

structure array contains the data <strong>for</strong> all eight rows. The indicator array,<br />

IND_ARRAY, contains zeros <strong>for</strong> every column in every row because no NULL<br />

values were returned.<br />

The <strong>SQL</strong>CA that is returned to the application contains the following in<strong>for</strong>mation:<br />

v <strong>SQL</strong>CODE contains 0<br />

v <strong>SQL</strong>STATE contains '00000'<br />

v <strong>SQL</strong>ERRD3 contains 8, the number of rows fetched<br />

v <strong>SQL</strong>ERRD4 contains 34, the length of each row<br />

v <strong>SQL</strong>ERRD5 contains +100, indicating the last row in the result table is in the<br />

block<br />

See Appendix B of the <strong>SQL</strong> Reference book <strong>for</strong> a description of the <strong>SQL</strong>CA.<br />

Multiple-row FETCH using a row storage area<br />

The application must define a row storage area and an associated description area<br />

be<strong>for</strong>e the application can use a multiple-row FETCH with a row storage area. The<br />

row storage area is a host variable defined in the application program. The row<br />

storage area contains the results of the multiple-row FETCH. A row storage area<br />

can be a character variable with enough bytes to hold all of the rows requested on<br />

the multiple-row FETCH.<br />

An <strong>SQL</strong>DA that contains the <strong>SQL</strong>TYPE and <strong>SQL</strong>LEN <strong>for</strong> each returned column is<br />

defined by the associated descriptor used on the row storage area <strong>for</strong>m of the<br />

64 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


...<br />

...<br />

multiple-row FETCH. The in<strong>for</strong>mation provided in the descriptor determines the<br />

data mapping from the database to the row storage area. To maximize<br />

per<strong>for</strong>mance, the attribute in<strong>for</strong>mation in the descriptor should match the<br />

attributes of the columns retrieved.<br />

See Appendix C of the <strong>SQL</strong> Reference book <strong>for</strong> a description of the <strong>SQL</strong>DA.<br />

Consider the following PL/I example:<br />

*....+....1....+....2....+....3....+....4....+....5....+....6....+....7...*<br />

EXEC <strong>SQL</strong> INCLUDE <strong>SQL</strong>CA;<br />

EXEC <strong>SQL</strong> INCLUDE <strong>SQL</strong>DA;<br />

DCL DEPTPTR PTR;<br />

DCL 1 DEPT(10) B<strong>AS</strong>ED(DEPTPTR),<br />

3 EMPNO CHAR(6),<br />

3 L<strong>AS</strong>TNAME CHAR(15) VARYING,<br />

3 WORKDEPT CHAR(3),<br />

3 JOB CHAR(8);<br />

DCL I BIN(31) FIXED;<br />

DEC J BIN(31) FIXED;<br />

DCL ROWAREA CHAR(2000);<br />

ALLOCATE <strong>SQL</strong>DA SET(<strong>SQL</strong>DAPTR);<br />

EXEC <strong>SQL</strong><br />

DECLARE D11 CURSOR FOR<br />

SELECT EMPNO, L<strong>AS</strong>TNAME, WORKDEPT, JOB<br />

FROM CORPDATA.EMPLOYEE<br />

WHERE WORKDEPT = 'D11';<br />

Figure 1. Example of Multiple-Row FETCH Using a Row Storage Area (Part 1 of 2)<br />

Chapter 4. Using a Cursor 65


...<br />

EXEC <strong>SQL</strong><br />

OPEN D11;<br />

/* SET UP THE DESCRIPTOR FOR THE MULTIPLE-ROW FETCH */<br />

/* 4 COLUMNS ARE BEING FETCHED */<br />

<strong>SQL</strong>D = 4;<br />

<strong>SQL</strong>N = 4;<br />

<strong>SQL</strong>DABC = 366;<br />

<strong>SQL</strong>TYPE(1) = 452; /* FIXED LENGTH CHARACTER - */<br />

/* NOT NULLABLE */<br />

<strong>SQL</strong>LEN(1) = 6;<br />

<strong>SQL</strong>TYPE(2) = 456; /*VARYING LENGTH CHARACTER */<br />

/* NOT NULLABLE */<br />

<strong>SQL</strong>LEN(2) = 15;<br />

<strong>SQL</strong>TYPE(3) = 452; /* FIXED LENGTH CHARACTER - */<br />

<strong>SQL</strong>LEN(3) = 3;<br />

<strong>SQL</strong>TYPE(4) = 452; /* FIXED LENGTH CHARACTER - */<br />

/* NOT NULLABLE */<br />

<strong>SQL</strong>LEN(4) = 8;<br />

/*ISSUE THE MULTIPLE-ROW FETCH STATEMENT TO RETRIEVE*/<br />

/*THE DATA INTO THE DEPT ROW STORAGE AREA */<br />

/*USE A HOST VARIABLE TO CONTAIN THE COUNT OF */<br />

/*ROWS TO BE RETURNED ON THE MULTIPLE-ROW FETCH */<br />

J = 10; /*REQUESTS 10 ROWS ON THE FETCH */<br />

...<br />

EXEC <strong>SQL</strong><br />

WHENEVER NOT FOUND<br />

GOTO FINISHED;<br />

EXEC <strong>SQL</strong><br />

WHENEVER <strong>SQL</strong>ERROR<br />

GOTO FINISHED;<br />

EXEC <strong>SQL</strong><br />

FETCH D11 FOR :J ROWS<br />

USING DESCRIPTOR :<strong>SQL</strong>DA INTO :ROWAREA;<br />

/* ADDRESS THE ROWS RETURNED */<br />

DEPTPTR = ADDR(ROWAREA);<br />

/*PROCESS EACH ROW RETURNED IN THE ROW STORAGE */<br />

/*AREA B<strong>AS</strong>ED ON THE COUNT OF RECORDS RETURNED */<br />

/*IN <strong>SQL</strong>ERRD3. */<br />

DOI=1TO<strong>SQL</strong>ERRD(3);<br />

IF EMPNO(I) = '000170' THEN<br />

DO;<br />

:<br />

END;<br />

END;<br />

IF <strong>SQL</strong>ERRD(5) = 100 THEN<br />

DO;<br />

/* PROCESS END OF FILE */<br />

END;<br />

FINISHED:<br />

Figure 1. Example of Multiple-Row FETCH Using a Row Storage Area (Part 2 of 2)<br />

In this example, a cursor has been defined <strong>for</strong> the CORPDATA.EMPLOYEE table to<br />

select all rows where the WORKDEPT column equal 'D11'. The sample EMPLOYEE<br />

table in Appendix A. <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> Sample Tables shows the result table<br />

contains eight rows. The DECLARE CURSOR and OPEN statements do not have<br />

special syntax when they are used with a multiple-row FETCH statement. Another<br />

FETCH statement that returns a single row against the same cursor can be coded<br />

66 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


elsewhere in the program. The multiple-row FETCH statement is used to retrieve<br />

all rows in the result table. Following the FETCH, the cursor position remains on<br />

the eighth record in the block.<br />

The row area, ROWAREA, is defined as a character array. The data from the result<br />

table is placed in the host variable. In this example, a pointer variable is assigned<br />

to the address of ROWAREA. Each item in the rows that are returned is examined<br />

and used with the based structure DEPT.<br />

The attributes (type and length) of the items in the descriptor match the columns<br />

that are retrieved. In this case, no indicator area is provided.<br />

After the FETCH statement is completed, the ROWAREA contains eight rows. The<br />

<strong>SQL</strong>CA that is returned to the application contains the following:<br />

v <strong>SQL</strong>CODE contains 0<br />

v <strong>SQL</strong>STATE contains '00000'<br />

v <strong>SQL</strong>ERRD3 contains 8, the number of rows returned<br />

v <strong>SQL</strong>ERRD4 contains 34, <strong>for</strong> the length of the row fetched<br />

v <strong>SQL</strong>ERRD5 contains +100, indicating the last row in the result table was fetched<br />

In this example, the application has taken advantage of the fact that <strong>SQL</strong>ERRD5<br />

contains an indication of the end of the file being reached. As a result, the<br />

application does not need to call <strong>SQL</strong> again to attempt to retrieve more rows. If the<br />

cursor has immediate sensitivity to inserts, you should call <strong>SQL</strong> in case any records<br />

were added. Cursors have immediate sensitivity when the commitment control<br />

level is something other than *RR.<br />

Unit of work and open cursors<br />

When your program completes a unit of work, it should commit or rollback the<br />

changes you made. Unless you specified HOLD on the COMMIT or ROLLBACK<br />

statement, all open cursors are automatically closed by <strong>SQL</strong>. Cursors that are<br />

declared with the WITH HOLD clause are not automatically closed on COMMIT.<br />

They are automatically closed on a ROLLBACK (the WITH HOLD clause specified<br />

on the DECLARE CURSOR statement is ignored).<br />

If you want to continue processing from the current cursor position after a<br />

COMMIT or ROLLBACK, you must specify COMMIT HOLD or ROLLBACK<br />

HOLD. When HOLD is specified, any open cursors are left open and keep their<br />

cursor position so processing can resume. On a COMMIT statement, the cursor<br />

position is maintained. On a ROLLBACK statement, the cursor position is restored<br />

to just after the last row retrieved from the previous unit of work. All record locks<br />

are still released.<br />

After issuing a COMMIT or ROLLBACK statement without HOLD, all locks are<br />

released and all cursors are closed. You can open the cursor again, but you will<br />

begin processing at the first row of the result table.<br />

Note: Specification of the ALWBLK(*ALLREAD) parameter of the CRT<strong>SQL</strong>xxx<br />

commands can change the restoration of the cursor position <strong>for</strong> read-only<br />

cursors. See Chapter 10. Dynamic <strong>SQL</strong> Applications <strong>for</strong> in<strong>for</strong>mation on the<br />

use of the ALWBLK parameter and other per<strong>for</strong>mance related options on the<br />

CRT<strong>SQL</strong>xxx commands.<br />

Chapter 4. Using a Cursor 67


68 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


Chapter 5. Advanced Coding Techniques<br />

Advanced insert techniques<br />

This chapter covers the more advanced <strong>SQL</strong> coding techniques. The topics<br />

included in this chapter are:<br />

v inserting rows<br />

v updating rows<br />

v preventing duplicate rows<br />

v searching<br />

v joining<br />

v using UNION<br />

v using subqueries<br />

v using views<br />

v using indexes<br />

v using the system catalog<br />

The next two sections cover two advanced techniques on how to insert rows into a<br />

table. The first section Inserting rows into a table using a Select-Statement<br />

discusses how to insert more than one row at a time using a select statement. The<br />

second section Inserting multiple rows in a table with the blocked INSERT<br />

statement discusses how to insert multiple rows that are in a host structure array.<br />

The second method can be used with all languages except REXX.<br />

Inserting rows into a table using a Select-Statement<br />

You can use a select-statement within an INSERT statement to insert zero, one, or<br />

more rows selected from the table or view you specify into another table. The table<br />

you select the rows from can be the same table you are inserting into. If they are<br />

the same table, <strong>SQL</strong> will create a temporary result table containing the selected<br />

rows and then insert from the temporary table into the target table.<br />

One use <strong>for</strong> this kind of INSERT statement is to move data into a table you created<br />

<strong>for</strong> summary data. For example, suppose you want a table that shows each<br />

employee’s time commitments to projects. You could create a table called<br />

EMPTIME with the columns EMPNUMBER, PROJNUMBER, STARTDATE,<br />

ENDDATE, and TTIME, and then use the following INSERT statement to fill the<br />

table:<br />

INSERT INTO CORPDATA.EMPTIME<br />

(EMPNUMBER, PROJNUMBER, STARTDATE, ENDDATE)<br />

SELECT EMPNO, PROJNO, EMSTDATE, EMENDATE<br />

FROM CORPDATA.EMP_ACT<br />

The select-statement embedded in the INSERT statement is no different from the<br />

select-statement you use to retrieve data. With the exception of FOR READ ONLY,<br />

FOR UPDATE OF, or the OPTIMIZE clause, you can use all the keywords, column<br />

functions, and techniques used to retrieve data. <strong>SQL</strong> inserts all the rows that meet<br />

the search conditions into the table you specify. Inserting rows from one table into<br />

another table does not affect any existing rows in either the source table or the<br />

target table.<br />

© Copyright IBM Corp. 2000 69


Notes on multiple-row Iinsertion<br />

You should consider the following when inserting multiple rows into a table:<br />

v The number of columns implicitly or explicitly listed in the INSERT statement<br />

must equal the number of columns listed in the select-statement.<br />

v The data in the columns you are selecting must be compatible with the columns<br />

you are inserting into when using the INSERT with select-statement.<br />

v In the event the select-statement embedded in the INSERT returns no rows, an<br />

<strong>SQL</strong>CODE of 100 is returned to alert you that no rows were inserted. If you<br />

successfully insert rows, the <strong>SQL</strong>ERRD(3) field of the <strong>SQL</strong>CA has an integer<br />

representing the number of rows <strong>SQL</strong> actually inserted.<br />

v If <strong>SQL</strong> finds an error while running the INSERT statement, <strong>SQL</strong> stops the<br />

operation. If you specify COMMIT (*CHG), COMMIT(*CS), COMMIT (*ALL), or<br />

COMMIT(*RR), nothing is inserted into the table and a negative <strong>SQL</strong>CODE is<br />

returned. If you specify COMMIT(*NONE), any rows inserted prior to the error<br />

remain in the table.<br />

v You can join two or more tables with a select-statement in an INSERT statement.<br />

Loaded in this manner, the table can be operated on with UPDATE, DELETE,<br />

and INSERT statements, because the rows exist as physically stored rows in a<br />

table.<br />

Inserting multiple rows in a table with the blocked INSERT<br />

statement<br />

Advanced update techniques<br />

A blocked INSERT can be used to insert multiple rows into a table with a single<br />

statement. The blocked INSERT statement is supported in all of the languages<br />

except REXX. The data inserted into the table must be in a host structure array. If<br />

indicator variables are used with a blocked INSERT, they must also be in a host<br />

structure array. For in<strong>for</strong>mation on host structure arrays <strong>for</strong> a particular language,<br />

refer to the chapter on that language.<br />

For example, to add ten employees to the CORPDATA.EMPLOYEE table:<br />

INSERT INTO CORPDATA.EMPLOYEE<br />

(EMPNO,FIRSTNME,MIDINIT,L<strong>AS</strong>TNAME,WORKDEPT)<br />

10 ROWS VALUES(:DSTRUCT:ISTRUCT)<br />

DSTRUCT is a host structure array with five elements that is declared in the<br />

program. The five elements correspond to EMPNO, FIRSTNME, MIDINIT,<br />

L<strong>AS</strong>TNAME, and WORKDEPT. DSTRUCT has a dimension of at least ten to<br />

accommodate inserting ten rows. ISTRUCT is a host structure array that is declared<br />

in the program. ISTRUCT has a dimension of at least ten small integer fields <strong>for</strong><br />

the indicators.<br />

Blocked INSERT statements are supported <strong>for</strong> non-distributed <strong>SQL</strong> applications<br />

and <strong>for</strong> distributed applications where both the application server and the<br />

application requester are <strong>AS</strong>/<strong>400</strong> systems.<br />

The SET clause of an UPDATE statement can be used in many ways to determine<br />

the actual values to be set in each row being updated. The following example lists<br />

each column with its corresponding value:<br />

70 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


UPDATE EMPLOYEE<br />

SET WORKDEPT = 'D11',<br />

PHONENO = '7213',<br />

JOB = 'DESIGNER'<br />

WHERE EMPNO = '000270'<br />

Preventing duplicate rows<br />

The previous update can also be written by specifying all of the columns and then<br />

all of the values:<br />

UPDATE EMPLOYEE<br />

SET (WORKDEPT, PHONENO, JOB)<br />

= ('D11', '7213', 'DESIGNER')<br />

WHERE EMPNO = '000270'<br />

Another way to select a value (or multiple values) <strong>for</strong> an update is to use a<br />

scalar-subselect. The scalar-subselect allows you to update one or more columns by<br />

setting them to one or more values selected from another table. In the following<br />

example, an employee moves to a different department but continues working on<br />

the same projects. The employee table has already been updated to contain the<br />

new department number. Now the project table needs to be updated to reflect the<br />

new department number of this employee (employee number is ’000030’).<br />

UPDATE PROJECT<br />

SET DEPTNO =<br />

(SELECT WORKDEPT FROM EMPLOYEE<br />

WHERE PROJECT.RESPEMP = EMPLOYEE.EMPNO)<br />

WHERE RESPEMP='000030'<br />

This same technique could be used to update a list of columns with multiple<br />

values returned from a single select.<br />

It is also possible to update an entire row in one table with values from a row in<br />

another table.<br />

Suppose there is a master class schedule table that needs to be udpated with<br />

changes that have been made in a copy of the table. The changes are made to the<br />

work copy and merged into the master table every night. The two tables have<br />

exactly the same columns and one column, CL<strong>AS</strong>S_CODE, is a unique key column.<br />

UPDATE CL_SCHED<br />

SET ROW =<br />

(SELECT * FROM MYCOPY<br />

WHERE CL_SCHED.CL<strong>AS</strong>S_CODE = MYCOPY.CL<strong>AS</strong>S_CODE)<br />

This update will update all of the rows in CL_SCHED with the values from<br />

MYCOPY.<br />

When <strong>SQL</strong> evaluates a select-statement, several rows might qualify to be in the<br />

result table, depending on the number of rows that satisfy the select-statement’s<br />

search condition. Some of the rows in the result table might be duplicates. You can<br />

specify that you do not want any duplicates by using the DISTINCT keyword,<br />

followed by the list of column names:<br />

SELECT DISTINCT JOB, SEX<br />

...<br />

DISTINCT means you want to select only the unique rows. If a selected row<br />

duplicates another row in the result table, the duplicate row is ignored (it is not<br />

put into the result table). For example, suppose you want a list of employee job<br />

Chapter 5. Advanced Coding Techniques 71


codes. You do not need to know which employee has what job code. Because it is<br />

probable that several people in a department have the same job code, you can use<br />

DISTINCT to ensure that the result table has only unique values.<br />

The following example shows how to do this:<br />

DECLARE XMP2 CURSOR FOR<br />

SELECT DISTINCT JOB<br />

FROM CORPDATA.EMPLOYEE<br />

WHERE WORKDEPT = :JOB-DEPT<br />

...<br />

FETCH XMP2<br />

INTO :JOB<br />

The result is two rows (in this example, JOB-DEPT is set to D11).<br />

fetch JOB<br />

1 Designer<br />

RV2W557-2<br />

If you do not include DISTINCT in a SELECT clause, you might find duplicate<br />

rows in your result, because <strong>SQL</strong> retrieves the JOB column’s value <strong>for</strong> each row<br />

that satisfies the search condition. Null values are treated as duplicate rows <strong>for</strong><br />

DISTINCT.<br />

If you include DISTINCT in a SELECT clause and you also include a<br />

shared-weight sort sequence, fewer values are returned. The sort sequence causes<br />

values that contain the same characters to be weighted the same. If 'MGR', 'Mgr',<br />

and 'mgr' were all in the same table, only one of these values would be returned.<br />

Per<strong>for</strong>ming complex search conditions<br />

The following section explains more advanced things you can do with search<br />

conditions.<br />

Keywords <strong>for</strong> use in search conditions<br />

A search condition can contain any of the keywords BETWEEN, IN, IS NULL, and<br />

LIKE.<br />

Note: Constants are shown in the following examples to keep the examples<br />

simple. However, you could just as easily code host variables instead.<br />

Remember to precede each host variable with a colon.<br />

For character and UCS-2 graphic column predicates, the sort sequence is applied to<br />

the operands be<strong>for</strong>e evaluation of the predicates <strong>for</strong> BETWEEN, IN, EXISTS, and<br />

LIKE clauses. See “Sort sequences in <strong>SQL</strong>” on page 50 <strong>for</strong> more in<strong>for</strong>mation on the<br />

using sort sequence with selection.<br />

v BETWEEN ... AND ... is used to specify a search condition that is satisfied by<br />

any value that falls on or between two other values. For example, to find all<br />

employees who were hired in 1987, you could use this:<br />

... WHERE HIREDATE BETWEEN '1987-01-01' AND '1987-12-31'<br />

The BETWEEN keyword is inclusive. A more complex, but explicit, search<br />

condition that produces the same result is:<br />

... WHERE HIREDATE >= '1987-01-01' AND HIREDATE


v IN says you are interested in rows in which the value of the specified expression<br />

is among the values you listed. For example, to find the names of all employees<br />

in departments A00, C01, and E21, you could specify:<br />

... WHERE WORKDEPT IN ('A00', 'C01', 'E21')<br />

v LIKE says you are interested in rows in which a column value is similar to the<br />

value you supply. When you use LIKE, <strong>SQL</strong> searches <strong>for</strong> a character string<br />

similar to the one you specify. The degree of similarity is determined by two<br />

special characters used in the string that you include in the search condition:<br />

_ An underline character stands <strong>for</strong> any single character.<br />

% A percent sign stands <strong>for</strong> an unknown string of 0 or more characters. If<br />

the percent sign starts the search string, then <strong>SQL</strong> allows 0 or more<br />

character(s) to precede the matching value in the column. Otherwise, the<br />

search string must begin in the first position of the column.<br />

Note: If you are operating on MIXED data, the following distinction applies: an<br />

SBCS underline character refers to one SBCS character. No such restriction<br />

applies to the percent sign; that is, a percent sign refers to any number of<br />

SBCS or DBCS characters. See the<strong>SQL</strong> Reference book <strong>for</strong> more<br />

in<strong>for</strong>mation on the LIKE predicate and MIXED data.<br />

Use the underline character or percent sign either when you do not know or do<br />

not care about all the characters of the column’s value. For example, to find out<br />

which employees live in Minneapolis, you could specify:<br />

... WHERE ADDRESS LIKE '%MINNEAPOLIS%'<br />

In this case, you should be sure that MINNEAPOLIS was not part of a street<br />

address or part of another city name. <strong>SQL</strong> returns any row with the string<br />

MINNEAPOLIS in the ADDRESS column, no matter where the string occurs.<br />

In another example, to list the towns whose names begin with 'SAN', you could<br />

specify:<br />

... WHERE TOWN LIKE 'SAN%'<br />

If you want to search <strong>for</strong> a character string that contains either the underscore or<br />

percent character, use the ESCAPE clause to specify an escape character. For<br />

example, to see all businesses that have a percent in their name, you could<br />

specify:<br />

... WHERE BUSINESS_NAME LIKE '%@%%' ESCAPE '@'<br />

The first and last percent characters are interpreted as usual. The combination<br />

’@%’ is taken as the actual percent character.<br />

Special considerations <strong>for</strong> LIKE<br />

v When host variables are used in place of string constants in a search pattern,<br />

you should consider using varying length host variables. This allows you to:<br />

– Assign previously used string constants to host variables without any change.<br />

– Obtain the same selection criteria and results as if a string constant was used.<br />

v When fixed-length host variables are used in place of string constants in a search<br />

pattern, you should ensure the value specified in the host variable matches the<br />

pattern previously used by the string constants. All characters in a host variable<br />

that are not assigned a value are initialized with a blank.<br />

For example, if you did a search using the string pattern ’ABC%’, these are some<br />

of the values that could be returned:<br />

Chapter 5. Advanced Coding Techniques 73


'ABCD ' 'ABCDE' 'ABCxxx' 'ABC '<br />

For example, if you did a search using the search pattern ’ABC%’ contained in a<br />

host variable with a fixed length of 10, these are some the values that could be<br />

returned assuming the column has a length of 12:<br />

'ABCDE ' 'ABCD ' 'ABCxxx ' 'ABC '<br />

Note that all returned values start with ’ABC’ and end with at least six blanks.<br />

This is because the last six characters in the host variable were not assigned a<br />

specific value so blanks were used.<br />

If you wanted to do a search on a fixed-length host variable where the last 7<br />

characters could be anything, you would search <strong>for</strong> ’ABC%%%%%%%’. These<br />

are some values that could be returned:<br />

'ABCDEFGHIJ' 'ABCXXXXXXX' 'ABCDE' 'ABCDD'<br />

Multiple search conditions within a WHERE clause<br />

You saw how to qualify a request using one search condition. You can qualify your<br />

request further by coding a search condition that includes several predicates. The<br />

search condition you specify can contain any of the comparison operators or the<br />

keywords BETWEEN, IN, LIKE, IS NULL, and IS NOT NULL.<br />

You can join any two predicates with the connectors AND and OR. In addition,<br />

you can use the NOT keyword to specify that the desired search condition is the<br />

negated value of the specified search condition. A WHERE clause can have as<br />

many predicates as you want.<br />

v AND says that, <strong>for</strong> a row to qualify, the row must satisfy both predicates of the<br />

search condition. For example, to find out which employees in department D21<br />

were hired after December 31, 1987, you would specify:<br />

...<br />

WHERE WORKDEPT = 'D21' AND HIREDATE > '1987-12-31'<br />

v OR says that, <strong>for</strong> a row to qualify, the row can satisfy the condition set by either<br />

or both predicates of the search condition. For example, to find out which<br />

employees are in either department C01 or D11, you could specify 4 :<br />

...<br />

WHERE WORKDEPT = 'C01' OR WORKDEPT = 'D11'<br />

v NOT says that, to qualify, a row must not meet the criteria set by the search<br />

condition or predicate that follows the NOT. For example, to find all employees<br />

in department E11 except those with a job code equal to analyst, you could<br />

specify:<br />

...<br />

WHERE WORKDEPT = 'E11' AND NOT JOB = 'ANALYST'<br />

When <strong>SQL</strong> evaluates search conditions that contain these connectors, it does so in a<br />

specific order. <strong>SQL</strong> first evaluates the NOT clauses, next evaluates the AND<br />

clauses, and then the OR clauses.<br />

You can change the order of evaluation by using parentheses. The search<br />

conditions enclosed in parentheses are evaluated first. For example, to select all<br />

employees in departments E11 and E21 who have education levels greater than 12,<br />

you could specify:<br />

4. You could also use IN to specify this request: WHERE WORKDEPT IN ('C01', 'D11').<br />

74 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


...<br />

WHERE EDLEVEL > 12 AND<br />

(WORKDEPT = 'E11' OR WORKDEPT = 'E21')<br />

The parentheses determine the meaning of the search condition. In this example,<br />

you want all rows that have a:<br />

WORKDEPT value of E11 or E21, and<br />

EDLEVEL value greater than 12<br />

If you did not use parentheses:<br />

...<br />

WHERE EDLEVEL > 12 AND WORKDEPT = 'E11'<br />

OR WORKDEPT = 'E21'<br />

Your result is different. The selected rows are rows that have:<br />

WORKDEPT = E11 and EDLEVEL > 12, or<br />

WORKDEPT = E21, regardless of the EDLEVEL value<br />

Joining data from more than one table<br />

Inner Join<br />

Sometimes the in<strong>for</strong>mation you want to see is not in a single table. To <strong>for</strong>m a row<br />

of the result table, you might want to retrieve some column values from one table<br />

and some column values from another table. You can retrieve and join column<br />

values from two or more tables into a single row. You can join tables using<br />

Operations Navigator, or using the JOIN statement.<br />

Four different types of joins are supported by <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong>: inner join, left<br />

outer join, exception join, and cross join.<br />

v An “Inner Join” returns only the rows from each table that have matching values<br />

in the join columns. Any rows that do not have a match between the tables will<br />

not appear in the result table.<br />

v A “Left Outer Join” on page 76 returns values <strong>for</strong> all of the rows from the first<br />

table (the table on the left) and the values from the second table <strong>for</strong> the rows<br />

that match. Any rows that do not have a match in the second table will return<br />

the null value <strong>for</strong> all columns from the second table.<br />

v An “Exception Join” on page 77 returns only the rows from the left table that do<br />

not have a match in the right table. Columns in the result table that come from<br />

the right table have the null value.<br />

v A “Cross Join” on page 78 returns a row in the result table <strong>for</strong> each combination<br />

of rows from the tables being joined (a Cartesian Product).<br />

With an inner join, column values from one row of a table are combined with<br />

column values from another row of another (or the same) table to <strong>for</strong>m a single<br />

row of data. <strong>SQL</strong> examines both tables specified <strong>for</strong> the join to retrieve data from<br />

all the rows that meet the search condition <strong>for</strong> the join. There are two ways of<br />

specifying an inner join: using the JOIN syntax, and using the WHERE clause.<br />

Suppose you want to retrieve the employee numbers, names, and project numbers<br />

<strong>for</strong> all employees that are responsible <strong>for</strong> a project. In other words, you want the<br />

EMPNO and L<strong>AS</strong>TNAME columns from the CORPDATA.EMPLOYEE table and the<br />

Chapter 5. Advanced Coding Techniques 75


PROJNO column from the CORPDATA.PROJECT table. Only employees with last<br />

names starting with ’S’ or later should be considered. To find this in<strong>for</strong>mation, you<br />

need to join the two tables.<br />

Inner join using JOIN syntax<br />

To use the inner join syntax, both of the tables you are joining are listed in the<br />

FROM clause, along with the join condition that applies to the tables. The join<br />

condition is specified after the ON keyword and determines how the two tables<br />

are to be compared to each other to produce the join result. The condition can be<br />

any comparison operator; it does not need to be the equal operator. Multiple join<br />

conditions can be specified in the ON clause separated by the AND keyword. Any<br />

additional conditions that do not relate to the actual join are specified in either the<br />

WHERE clause or as part of the actual join in the ON clause.<br />

SELECT EMPNO, L<strong>AS</strong>TNAME, PROJNO<br />

FROM CORPDATA.EMPLOYEE INNER JOIN CORPDATA.PROJECT<br />

ON EMPNO = RESPEMP<br />

WHERE L<strong>AS</strong>TNAME > 'S'<br />

In this example, the join is done on the two tables using the EMPNO and<br />

RESPEMP columns from the tables. Since only employees that have last names<br />

starting with at least ’S’ are to be returned, this additional condition is provided in<br />

the WHERE clause.<br />

This query returns the following output:<br />

EMPNO L<strong>AS</strong>TNAME PROJNO<br />

000020 THOMPSON PL2100<br />

000060 STERN MA2110<br />

000100 SPENSER OP2010<br />

000250 SMITH AD3112<br />

Inner join using the WHERE clause<br />

Using the WHERE clause to per<strong>for</strong>m this same join is written with both the join<br />

condition and the additional selection condition in the WHERE clause. The tables<br />

to be joined are listed in the FROM clause, separated by commas.<br />

SELECT EMPNO, L<strong>AS</strong>TNAME, PROJNO<br />

FROM CORPDATA.EMPLOYEE, CORPDATA.PROJECT<br />

WHERE EMPNO = RESPEMP<br />

AND L<strong>AS</strong>TNAME > 'S'<br />

This query returns the same output as the previous example.<br />

Left Outer Join<br />

A left outer join will return all the rows that an inner join returns plus one row <strong>for</strong><br />

each of the other rows in the first table that did not have a match in the second<br />

table.<br />

Suppose you want to find all employees and the projects they are currently<br />

responsible <strong>for</strong>. You want to see those employees that are not currently in charge of<br />

a project as well. The following query will return a list of all employees whose<br />

names are greater than ’S’, along with their assigned project numbers.<br />

76 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


SELECT EMPNO, L<strong>AS</strong>TNAME, PROJNO<br />

FROM CORPDATA.EMPLOYEE LEFT OUTER JOIN CORPDATA.PROJECT<br />

ON EMPNO = RESPEMP<br />

WHERE L<strong>AS</strong>TNAME > 'S'<br />

The result of this query contains some employees that do not have a project<br />

number. They are listed in the query, but have the null value returned <strong>for</strong> their<br />

project number.<br />

EMPNO L<strong>AS</strong>TNAME PROJNO<br />

000020 THOMPSON PL2100<br />

000060 STERN MA2110<br />

000100 SPENSER OP2010<br />

000170 YOSHIMURA -<br />

000180 SCOUTTEN -<br />

000190 WALKER -<br />

000250 SMITH AD3112<br />

000280 SCHNEIDER -<br />

000300 SMITH -<br />

000310 SETRIGHT -<br />

Notes<br />

Using the RRN scalar function to return the relative record number <strong>for</strong> a column in<br />

the table on the right in a left outer join or exception join will return a value of 0<br />

<strong>for</strong> the unmatched rows.<br />

Exception Join<br />

An exception join returns only the records from the first table that do NOT have a<br />

match in the second table. Using the same tables as be<strong>for</strong>e, return those employees<br />

that are not responsible <strong>for</strong> any projects.<br />

SELECT EMPNO, L<strong>AS</strong>TNAME, PROJNO<br />

FROM CORPDATA.EMPLOYEE EXCEPTION JOIN CORPDATA.PROJECT<br />

ON EMPNO = RESPEMP<br />

WHERE L<strong>AS</strong>TNAME > 'S'<br />

This join returns the output:<br />

EMPNO L<strong>AS</strong>TNAME PROJNO<br />

000170 YOSHIMURA -<br />

000180 SCOUTTEN -<br />

000190 WALKER -<br />

000280 SCHNEIDER -<br />

000300 SMITH -<br />

000310 SETRIGHT -<br />

An exception join can also be written as a subquery using the NOT EXISTS<br />

predicate. The previous query could be rewritten in the following way:<br />

Chapter 5. Advanced Coding Techniques 77


Cross Join<br />

SELECT EMPNO, L<strong>AS</strong>TNAME<br />

FROM CORPDATA.EMPLOYEE<br />

WHERE L<strong>AS</strong>TNAME > 'S'<br />

AND NOT EXISTS<br />

(SELECT * FROM CORPDATA.PROJECT<br />

WHERE EMPNO = RESPEMP)<br />

The only difference in this query is that it cannot return values from the PROJECT<br />

table.<br />

A cross join (or Cartesian Product join) will return a result table where each row<br />

from the first table is combined with each row from the second table. The number<br />

of rows in the result table is the product of the number of rows in each table. If the<br />

tables involved are large, this join can take a very long time.<br />

A cross join can be specified in two ways: using the JOIN syntax or by listing the<br />

tables in the FROM clause separated by commas without using a WHERE clause to<br />

supply join criteria.<br />

Suppose the following tables exist.<br />

Table 13. Table A<br />

T1COL1 T1COL2<br />

A1 AA1<br />

A2 AA2<br />

A3 AA3<br />

Table 14. Table B<br />

T2COL1 T2COL2<br />

B1 BB1<br />

B2 BB2<br />

The following two select statements produce identical results.<br />

SELECT * FROM A CROSS JOIN B<br />

SELECT * FROM A, B<br />

The result table <strong>for</strong> either of these select statements looks like this:<br />

T1COL1 T1COL2 T2COL1 T2COL2<br />

A1 AA1 B1 BB1<br />

A1 AA1 B2 BB2<br />

A2 AA2 B1 BB1<br />

A2 AA2 B2 BB2<br />

A3 AA3 B1 BB1<br />

A3 AA3 B2 BB2<br />

Multiple join types in one statement<br />

There are times when more than two tables need to be joined to produce the<br />

desired result. If you wanted to return all the employees, their department name,<br />

and the project they are responsible <strong>for</strong>, if any, the EMPLOYEE table,<br />

78 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


DEPARTMENT table, and PROJECT table would all need to be joined to get the<br />

in<strong>for</strong>mation. The following example shows the query and the results.<br />

SELECT EMPNO, L<strong>AS</strong>TNAME, DEPTNAME, PROJNO<br />

FROM CORPDATA.EMPLOYEE INNER JOIN CORPDATA.DEPARTMENT<br />

ON WORKDEPT = DEPTNO<br />

LEFT OUTER JOIN CORPDATA.PROJECT<br />

ON EMPNO = RESPEMP<br />

WHERE L<strong>AS</strong>TNAME > 'S'<br />

EMPNO L<strong>AS</strong>TNAME DEPTNAME PROJNO<br />

000020 THOMPSON PLANNING PL2100<br />

000060 STERN MANUFACTURING SYSTEMS MA2110<br />

000100 SPENSER SOFTWARE SUPPORT OP2010<br />

000170 YOSHIMURA MANUFACTURING SYSTEMS -<br />

000180 SCOUTTEN MANUFACTURING SYSTEMS -<br />

000190 WALKER MANUFACTURING SYSTEMS -<br />

000250 SMITH ADMINISTRATION SYSTEMS AD3112<br />

000280 SCHNEIDER OPERATIONS -<br />

000300 SMITH OPERATIONS -<br />

000310 SETRIGHT OPERATIONS -<br />

Notes on joins<br />

When you join two or more tables:<br />

v If there are common column names, you must qualify each common name with<br />

the name of the table (or a correlation name). Column names that are unique do<br />

not need to be qualified.<br />

v If you do not list the column names you want, but instead use SELECT *, <strong>SQL</strong><br />

returns rows that consist of all the columns of the first table, followed by all the<br />

columns of the second table, and so on.<br />

v You must be authorized to select rows from each table or view specified in the<br />

FROM clause.<br />

v The sort sequence is applied to all character and UCS-2 graphic columns being<br />

joined.<br />

Specifying itermediate join tables using table expressions<br />

You can use table expressions to specify an intermediate result table. They can be<br />

used in place of a view to avoid creating the view when general use of the view is<br />

not required. Table expressions consist of nested table expressions and common<br />

table expressions.<br />

Nested table expressions are specified within parentheses in the FROM clause. For<br />

example, suppose you want a result table that shows the manager number,<br />

department number, and maximum salary <strong>for</strong> each department. The manager<br />

number is in the DEPARTMENT table, the department number is in both the<br />

DEPARTMENT and EMPLOYEE tables, and the salaries are in the EMPLOYEE<br />

table. You can use a table expression in the from clause to select the maximum<br />

salary <strong>for</strong> each department. You add a correlation name, T2, following the nested<br />

table expression to name the derived table. The outer select then uses T2 to qualify<br />

columns that are selected from the derived table, in this case MAXSAL and<br />

Chapter 5. Advanced Coding Techniques 79


WORKDEPT. Note that the MAX(SALARY) column selected in the nested table<br />

expression must be named in order to be referenced in the outer select. The <strong>AS</strong><br />

clause is used to do that.<br />

SELECT MGRNO, T1.DEPTNO, MAXSAL<br />

FROM CORPDATA.DEPARTMENT T1,<br />

(SELECT MAX(SALARY) <strong>AS</strong> MAXSAL, WORKDEPT<br />

FROM CORPDATA.EMPLOYEE E1<br />

GROUP BY WORKDEPT) T2<br />

WHERE T1.DEPTNO = T2.WORKDEPT<br />

ORDER BY DEPTNO<br />

The result of the query is:<br />

MGRNO DEPTNO MAXSAL<br />

000010 A00 52,750.00<br />

000020 B01 41,250.00<br />

000030 C01 38,250.00<br />

000060 D11 32,250.00<br />

000070 D21 36,170.00<br />

000050 E01 40,175.00<br />

000090 E11 29,750.00<br />

000100 E21 26,150.00<br />

Common table expressions can be specified prior to the full-select in a SELECT<br />

statement, an INSERT statement, or a CREATE VIEW statement. They can be used<br />

when the same result table needs to be shared in a full-select. Common table<br />

expressions are preceeded with the keyword WITH.<br />

For example, suppose you want a table that shows the minimum and maximum of<br />

the average salary of a certain set of departments. The first character of the<br />

department number has some meaning and you want to get the minimum and<br />

maximum <strong>for</strong> those departments that start with the letter ’D’ and those that start<br />

with the letter ’E’. You can use a common table expression to select the average<br />

salary <strong>for</strong> each department. Again, you must name the derived table; in this case,<br />

the name is DT. You can then specify a SELECT statement using a WHERE clause<br />

to restrict the selection to only the departments that begin with a certain letter.<br />

Specify the minimum and maximum of column AVGSAL from the derived table<br />

DT. Specify a UNION to get the results <strong>for</strong> the letter ’E’ and the results <strong>for</strong> the<br />

letter ’D’.<br />

WITH DT <strong>AS</strong> (SELECT E.WORKDEPT <strong>AS</strong> DEPTNO, AVG(SALARY) <strong>AS</strong> AVGSAL<br />

FROM CORPDATA.DEPARTMENT D , CORPDATA.EMPLOYEE E<br />

WHERE D.DEPTNO = E.WORKDEPT<br />

GROUP BY E.WORKDEPT)<br />

SELECT 'E', MAX(AVGSAL), MIN(AVGSAL) FROM DT<br />

WHERE DEPTNO LIKE 'E%'<br />

UNION<br />

SELECT 'D', MAX(AVGSAL), MIN(AVGSAL) FROM DT<br />

WHERE DEPTNO LIKE 'D%'<br />

The result of the query is:<br />

MAX (AVGSAL ) MIN (AVGSAL )<br />

E 40,175.00 20,998.00<br />

D 25,153.33 24,677.77<br />

Using the UNION keyword to combine subselects<br />

Using the UNION keyword, you can combine two or more subselects to <strong>for</strong>m a<br />

single select-statement. When <strong>SQL</strong> encounters the UNION keyword, it processes<br />

each subselect to <strong>for</strong>m an interim result table, then it combines the interim result<br />

table of each subselect and deletes duplicate rows to <strong>for</strong>m a combined result table.<br />

80 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


You use UNION to merge lists of values from two or more tables. You can use any<br />

of the clauses and techniques you have learned so far when coding<br />

select-statements, including ORDER BY.<br />

You can use UNION to eliminate duplicates when merging lists of values obtained<br />

from several tables. For example, you can obtain a combined list of employee<br />

numbers that includes:<br />

v People in department D11<br />

v People whose assignments include projects MA2112, MA2113, and AD3111<br />

The combined list is derived from two tables and contains no duplicates. To do<br />

this, specify:<br />

MOVE 'D11' TO WORK-DEPT.<br />

...<br />

EXEC <strong>SQL</strong><br />

DECLARE XMP6 CURSOR FOR<br />

SELECT EMPNO<br />

FROM CORPDATA.EMPLOYEE<br />

WHERE WORKDEPT = :WORK-DEPT<br />

UNION<br />

SELECT EMPNO<br />

FROM CORPDATA.EMP_ACT<br />

WHERE PROJNO = 'MA2112' OR<br />

PROJNO = 'MA2113' OR<br />

PROJNO = 'AD3111'<br />

ORDER BY EMPNO<br />

END-EXEC.<br />

...<br />

EXEC <strong>SQL</strong><br />

FETCH XMP6<br />

INTO :EMP-NUMBER<br />

END-EXEC.<br />

To better understand what results from these <strong>SQL</strong> statements, imagine that <strong>SQL</strong><br />

goes through the following process:<br />

Chapter 5. Advanced Coding Techniques 81


Step 1: <strong>SQL</strong> processes the<br />

first SELECT statement:<br />

Step 2: <strong>SQL</strong> processes the<br />

second SELECT statement:<br />

Step 3: <strong>SQL</strong> combines the<br />

two interim result tables:<br />

Which results in an interim<br />

result table:<br />

(from CORPDATA.EMPLOYEE)<br />

000060<br />

000150<br />

000160<br />

000170<br />

...<br />

Which results in another<br />

interim result table:<br />

(from CORPDATA.EMP ACT)<br />

000230<br />

000230<br />

000230<br />

...<br />

Which results in a combined<br />

result table with values in<br />

ascending sequence:<br />

fetch EMP-NUMBER<br />

1 000060<br />

2 000150<br />

3 000160<br />

4 000170<br />

5 000180<br />

... ...<br />

When you use UNION:<br />

v Any ORDER BY clause must appear after the last subselect that is part of the<br />

union. In this example, the results are sequenced on the basis of the first selected<br />

column, EMPNO. The ORDER BY clause specifies that the combined result table<br />

is to be in collated sequence.<br />

v A name may be specified on the ORDER BY clause if the result columns are<br />

named. A result column is named if the corresponding columns in each of the<br />

unioned select-statements have the same name. An <strong>AS</strong> clause can be used to<br />

assign a name to columns in the select list.<br />

SELECT A+B<strong>AS</strong> X ...<br />

UNION SELECT X ... ORDER BY X<br />

If the result columns are unnamed, use numbers to order the result. The number<br />

refers to the position of the expression in the list of expressions you include in<br />

your subselects.<br />

SELECT A+B...<br />

UNION SELECT X ... ORDER BY 1<br />

You cannot use UNION when creating a view.<br />

82 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5<br />

RV3W186-0


To identify which subselect each row is from, you can include a constant at the end<br />

of the select list of each subselect in the union. When <strong>SQL</strong> returns your results, the<br />

last column contains the constant <strong>for</strong> the subselect that is the source of that row.<br />

For example, you can specify:<br />

SELECT A, B, 'A1' ... UNION SELECT X, Y, 'B2'<br />

When a row is presented to your program, it includes a value (either A1 or B2) to<br />

indicate the table that is the source of the row’s values. If the column names in the<br />

union are different, <strong>SQL</strong> uses the set of column names specified in the first<br />

subselect when interactive <strong>SQL</strong> displays or prints the results, or in the <strong>SQL</strong>DA<br />

resulting from processing an <strong>SQL</strong> DESCRIBE statement.<br />

For in<strong>for</strong>mation on compatibility of the length and data type <strong>for</strong> columns in a<br />

UNION, see chapter 4 of the <strong>SQL</strong> Reference book.<br />

Note: Sort sequence is applied after the fields across the UNION pieces are made<br />

compatible. The sort sequence is used <strong>for</strong> the distinct processing that<br />

implicitly occurs during UNION processing.<br />

Specifying UNION ALL<br />

If you want to keep duplicates in the result of a UNION, specify UNION ALL<br />

instead of just UNION.<br />

Step 3. <strong>SQL</strong> combines two<br />

interim result tables:<br />

v The UNION ALL operation is associative, <strong>for</strong> example:<br />

(SELECT PROJNO FROM CORPDATA.PROJECT<br />

UNION ALL<br />

SELECT PROJNO FROM CORPDATA.PROJECT)<br />

UNION ALL<br />

SELECT PROJNO FROM CORPDATA.EMP_ACT<br />

gives the same result as:<br />

fetch<br />

1<br />

2<br />

3<br />

4<br />

5<br />

6<br />

7<br />

8<br />

...<br />

SELECT PROJNO FROM CORPDATA.PROJECT<br />

UNION ALL<br />

(SELECT PROJNO FROM CORPDATA.PROJECT<br />

UNION ALL<br />

SELECT PROJNO FROM CORPDATA.EMP_ACT)<br />

Resulting in a result table that<br />

includes duplicates:<br />

EMP-NUMBER<br />

000060<br />

000150<br />

000150<br />

000150<br />

000160<br />

000160<br />

000170<br />

000170<br />

...<br />

RV3W187-0<br />

v When you include the UNION ALL in the same <strong>SQL</strong> statement as a UNION<br />

operator, however, the result of the operation depends on the order of<br />

Chapter 5. Advanced Coding Techniques 83


evaluation. Where there are no parentheses, evaluation is from left to right.<br />

Where parentheses are included, the parenthesized subselect is evaluated first,<br />

followed, from left to right, by the other parts of the statement.<br />

Subqueries in SELECT statements<br />

In the WHERE and HAVING clauses you have seen so far, you specified a search<br />

condition by using a literal value, a column name, an expression, or the registers.<br />

In those search conditions, you know that you are searching <strong>for</strong> a specific value,<br />

but sometimes you cannot supply that value until you have retrieved other data<br />

from a table. For example, suppose you want a list of the employee numbers,<br />

names, and job codes of all employees working on a particular project, say project<br />

number MA2100. The first part of the statement is easy to write:<br />

DECLARE XMP CURSOR FOR<br />

SELECT EMPNO, L<strong>AS</strong>TNAME, JOB<br />

FROM CORPDATA.EMPLOYEE<br />

WHERE EMPNO ...<br />

But you cannot go further because the CORPDATA.EMPLOYEE table does not<br />

include project number data. You do not know which employees are working on<br />

project MA2100 without issuing another SELECT statement against the<br />

CORPDATA.EMP_ACT table.<br />

With <strong>SQL</strong>, you can nest one SELECT statement within another to solve this<br />

problem. The inner SELECT statement is called a subquery. The SELECT statement<br />

surrounding the subquery is called the outer-level SELECT. Using a subquery, you<br />

could issue just one <strong>SQL</strong> statement to retrieve the employee numbers, names, and<br />

job codes <strong>for</strong> employees who work on project MA2100:<br />

DECLARE XMP CURSOR FOR<br />

SELECT EMPNO, L<strong>AS</strong>TNAME, JOB<br />

FROM CORPDATA.EMPLOYEE<br />

WHERE EMPNO IN<br />

(SELECT EMPNO<br />

FROM CORPDATA.EMP_ACT<br />

WHERE PROJNO = 'MA2100')<br />

To better understand what will result from this <strong>SQL</strong> statement, imagine that <strong>SQL</strong><br />

goes through the following process:<br />

84 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


Correlation<br />

Step 1: <strong>SQL</strong> evaluates the<br />

subquery to obtain a list<br />

of EMPNO values:<br />

Step 2: The interim results<br />

table then serves as a list<br />

in the search condition of<br />

the outer-level SELECT.<br />

Essentially, this is what is<br />

executed.<br />

The purpose of a subquery is to supply in<strong>for</strong>mation needed to qualify a row<br />

(WHERE clause) or a group of rows (HAVING clause). This is done through the<br />

result table that the subquery produces. Conceptually, the subquery is evaluated<br />

whenever a new row or group of rows must be qualified. In fact, if the subquery is<br />

the same <strong>for</strong> every row or group, it is evaluated only once. For example, the<br />

previous subquery has the same content <strong>for</strong> every row of the table<br />

CORPDATA.EMPLOYEE. Subqueries like this are said to be uncorrelated.<br />

Some subqueries vary in content from row to row or group to group. The<br />

mechanism that allows this is called correlation, and the subqueries are said to be<br />

correlated. More in<strong>for</strong>mation on correlated subqueries can be found in “Correlated<br />

subqueries” on page 88. Even so, what is said be<strong>for</strong>e that point applies equally to<br />

correlated and uncorrelated subqueries.<br />

Subqueries and search conditions<br />

Which results in an interim<br />

results table:<br />

(from CORPDATA.EMP ACT)<br />

000010<br />

000110<br />

The final result table looks like this:<br />

fetch<br />

1<br />

2<br />

EMPNO L<strong>AS</strong>TNAME JOB<br />

000010<br />

000110<br />

HA<strong>AS</strong><br />

LUCCHESSI<br />

PRES<br />

SALESREP<br />

RV2W559-2<br />

A subquery is always part of a search condition. The search condition is in the<br />

<strong>for</strong>m operand operator (subquery). In the example, the operand is EMPNO and<br />

operator is IN. The search condition can be part of a WHERE or HAVING clause.<br />

The clause can include more than one search condition that contains a subquery. A<br />

search condition containing a subquery, like any other search condition, can be<br />

enclosed in parentheses, can be preceded by the keyword NOT, and can be linked<br />

to other search conditions through the keywords AND and OR. For example, the<br />

WHERE clause of some query could look something like this:<br />

WHERE X IN (subquery1) AND (Y>SOME (subquery2) OR Z = 100)<br />

Chapter 5. Advanced Coding Techniques 85


Subqueries can also appear in the search conditions of other subqueries. Such<br />

subqueries are said to be nested at some level of nesting. For example, a subquery<br />

within a subquery within an outer-level SELECT is nested at a nesting level of two.<br />

<strong>SQL</strong> allows nesting down to a nesting level of 32, but few queries require a nesting<br />

level greater than 1.<br />

How subqueries are used<br />

There are four ways to include a subquery in either a WHERE or HAVING clause:<br />

Basic comparisons<br />

You can use a subquery immediately after any of the comparison operators. If you<br />

do, the subquery can return at most one value. The value can be the result of a<br />

column function or an arithmetic expression. <strong>SQL</strong> then compares the value that<br />

results from the subquery with the value to the left of the comparison operator. For<br />

example, suppose you want to find the employee numbers, names, and salaries <strong>for</strong><br />

employees whose education level is higher than the average education level<br />

throughout the company.<br />

DECLARE XMP CURSOR FOR<br />

SELECT EMPNO, L<strong>AS</strong>TNAME, SALARY<br />

FROM CORPDATA.EMPLOYEE<br />

WHERE EDLEVEL ><br />

(SELECT AVG(EDLEVEL)<br />

FROM CORPDATA.EMPLOYEE)<br />

<strong>SQL</strong> first evaluates the subquery and then substitutes the result in the WHERE<br />

clause of the SELECT statement. In this example, the result is (as it should be) the<br />

company-wide average educational level. Besides returning a single value, a<br />

subquery could return no value at all. If it does, the result of the compare is<br />

unknown. Consider, <strong>for</strong> example, the first query shown in this section, and assume<br />

that there are not any employees currently working on project MA2100. Then the<br />

subquery would return no value, and the search condition would be unknown <strong>for</strong><br />

every row. In this case, then, the result produced by the query would be an empty<br />

table.<br />

Quantified comparisons (ALL, ANY, and SOME)<br />

You can use a subquery after a comparison operator followed by the keyword<br />

ALL, ANY, or SOME. When used in this way, the subquery can return zero, one, or<br />

many values, including null values. You can use ALL, ANY, and SOME in the<br />

following ways:<br />

v Use ALL to indicate that the value you supplied must compare in the indicated<br />

way to ALL the values the subquery returns. For example, suppose you use the<br />

greater-than comparison operator with ALL:<br />

... WHERE expression > ALL (subquery)<br />

To satisfy this WHERE clause, the value in the expression must be greater than<br />

all the values (that is, greater than the highest value) returned by the subquery.<br />

If the subquery returns an empty set (that is, no values were selected), the<br />

condition is satisfied.<br />

v Use ANY or SOME to indicate that the value you supplied must compare in the<br />

indicated way to at least one of the values the subquery returns. For example,<br />

suppose you use the greater-than comparison operator with ANY:<br />

... WHERE expression > ANY (subquery)<br />

86 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


To satisfy this WHERE clause, the value in the expression must be greater than<br />

at least one of the values (that is, greater than the lowest value) returned by the<br />

subquery. If what the subquery returns is empty, the condition is not satisfied.<br />

Note: The results when a subquery returns one or more null values may surprise<br />

you, unless you are familiar with <strong>for</strong>mal logic. For applicable rules, read the<br />

discussion of quantified predicates in the <strong>SQL</strong> Reference.<br />

IN keyword<br />

You can use IN to say that the value in the expression must be among the values<br />

returned by the subquery. The first example in this chapter illustrates this type of<br />

usage. Using IN is equivalent to using =ANY or =SOME. Using ANY and SOME<br />

were previously described. You could also use the IN keyword with the NOT<br />

keyword in order to select rows when the value is not among the values returned<br />

by the subquery. For example, you could use:<br />

... WHERE WORKDEPT NOT IN (SELECT ...)<br />

EXISTS Keyword<br />

In the subqueries presented so far, <strong>SQL</strong> evaluates the subquery and uses the result<br />

as part of the WHERE clause of the outer-level SELECT. In contrast, when you use<br />

the keyword EXISTS, <strong>SQL</strong> simply checks whether the subquery returns one or<br />

more rows. If it does, the condition is satisfied. If it does not (if it returns no rows),<br />

the condition is not satisfied. For example:<br />

DECLARE XMP CURSOR FOR<br />

SELECT EMPNO,L<strong>AS</strong>TNAME<br />

FROM CORPDATA.EMPLOYEE<br />

WHERE EXISTS<br />

(SELECT *<br />

FROM CORPDATA.PROJECT<br />

WHERE PRSTDATE > '1982-01-01');<br />

In the example, the search condition holds if any project represented in the<br />

CORPDATA.PROJECT table has an estimated start date that is later than January 1,<br />

1982. Please note that this example does not show the full power of EXISTS,<br />

because the result is always the same <strong>for</strong> every row examined <strong>for</strong> the outer-level<br />

SELECT. As a consequence, either every row appears in the results, or none<br />

appear. In a more powerful example, the subquery itself would be correlated, and<br />

would change from row to row. See “Correlated subqueries” on page 88 <strong>for</strong> more<br />

in<strong>for</strong>mation on correlated subqueries.<br />

As shown in the example, you do not need to specify column names in the<br />

subquery of an EXISTS clause. Instead, you can code SELECT *.<br />

You could also use the EXISTS keyword with the NOT keyword in order to select<br />

rows when the data or condition you specify does not exist. That is, you could use:<br />

... WHERE NOT EXISTS (SELECT ...)<br />

For all general types of usage <strong>for</strong> subqueries but one (using a subquery with the<br />

EXISTS keyword), the subquery must produce a one-column result table. This<br />

means that the SELECT clause in a subquery must name a single column, or<br />

contain a single expression. For example, both of the following SELECT clauses<br />

would be allowed <strong>for</strong> all four usage types:<br />

SELECT AVG(SALARY)<br />

SELECT EMPNO<br />

Chapter 5. Advanced Coding Techniques 87


The result table produced by a subquery can have zero or more rows. For some<br />

usages, no more than one row is allowed.<br />

Using subqueries with UPDATE and DELETE<br />

In the examples shown so far, you have seen subqueries within SELECT<br />

statements. You can also use subqueries in the WHERE clause of the UPDATE or<br />

DELETE statements or in the SET clause of an UPDATE. For the most part, this is<br />

not very different from using subqueries with outer-level SELECTs.<br />

Notes on using subqueries<br />

1. When nesting SELECT statements, you can use as many as you need to satisfy<br />

your requirements (1 to 31 subqueries), although per<strong>for</strong>mance is slower <strong>for</strong><br />

each additional subquery. A maximum of 128 tables can be specified in an <strong>SQL</strong><br />

statement.<br />

2. When the outer statement is a SELECT statement (at any level of nesting):<br />

v The subquery can be based on the same table or view as the outer statement,<br />

or on a different table or view.<br />

v You can use a subquery in the WHERE clause of the outer-level SELECT,<br />

even when the outer-level SELECT is part of a DECLARE CURSOR, CREATE<br />

VIEW, or INSERT statement.<br />

v You can use a subquery in the HAVING clause of a SELECT statement.<br />

When you do, <strong>SQL</strong> evaluates the subquery and uses it to qualify each group.<br />

3. When the statement is an UPDATE or DELETE statement, you can use<br />

subqueries in the WHERE clause of the UPDATE or DELETE statement.<br />

4. When a subquery is used in the SET clause of an UPDATE statement, the result<br />

table of a subselect must contain the same number of values as the<br />

corresponding list of columns to be updated. In all other cases, the result table<br />

<strong>for</strong> a subquery must consist of a single column, unless the subquery is being<br />

used with the EXISTS keyword. The number of rows in this table can vary<br />

from zero to many, but <strong>for</strong> comparisons not involving the keywords ALL, ANY,<br />

or SOME, the number of rows must be zero or one.<br />

5. A subquery cannot include the ORDER BY, UNION, UNION ALL, FOR READ<br />

ONLY, UPDATE, or OPTIMIZE clauses.<br />

6. In any subquery, as in any search condition, the values compared must be<br />

compatible.<br />

7. Using a column function or an arithmetic expression with a column name in a<br />

subquery does not make it incompatible. The data type of the column does not<br />

change after <strong>SQL</strong> applies a column function or arithmetic operator.<br />

Correlated subqueries<br />

In the subqueries previously discussed, <strong>SQL</strong> evaluates the subquery once,<br />

substitutes the result of the subquery in the right side of the search condition, and<br />

evaluates the outer-level SELECT based on the value of the search condition. You<br />

can also write a subquery that <strong>SQL</strong> may have to re-evaluate as it examines each<br />

new row (WHERE clause) or group of rows (HAVING clause) in the outer-level<br />

SELECT. This is called a correlated subquery.<br />

Example: Correlated Subquery in a WHERE Clause<br />

Suppose that you want a list of all the employees whose education levels are<br />

higher than the average education levels in their respective departments. To get<br />

88 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


this in<strong>for</strong>mation, <strong>SQL</strong> must search the CORPDATA.EMPLOYEE table. For each<br />

employee in the table, <strong>SQL</strong> needs to compare the employee’s education level to the<br />

average education level <strong>for</strong> the employee’s department. In the subquery, you tell<br />

<strong>SQL</strong> to calculate the average education level <strong>for</strong> the department number in the<br />

current row. For example:<br />

DECLARE XMP CURSOR FOR<br />

SELECT EMPNO, L<strong>AS</strong>TNAME, WORKDEPT, EDLEVEL<br />

FROM CORPDATA.EMPLOYEE X<br />

WHERE EDLEVEL ><br />

(SELECT AVG(EDLEVEL)<br />

FROM CORPDATA.EMPLOYEE<br />

WHERE WORKDEPT = X.WORKDEPT)<br />

A correlated subquery looks like an uncorrelated one, except <strong>for</strong> the presence of<br />

one or more correlated references. In the example, the single correlated reference is<br />

the occurrence of X.WORKDEPT in the subselect’s FROM clause. Here, the<br />

qualifier X is the correlation name defined in the FROM clause of the outer<br />

SELECT statement. In that clause, X is introduced as the correlation name of the<br />

table CORPDATA.EMPLOYEE.<br />

Now, consider what happens when the subquery is executed <strong>for</strong> a given row of<br />

CORPDATA.EMPLOYEE. Be<strong>for</strong>e it is executed, the occurrence of X.WORKDEPT is<br />

replaced with the value of the WORKDEPT column <strong>for</strong> that row. Suppose, <strong>for</strong><br />

example, that the row is <strong>for</strong> CHRISTINE I HA<strong>AS</strong>. Her work department is A00,<br />

which is the value of WORKDEPT <strong>for</strong> this row. The subquery executed <strong>for</strong> this<br />

row is:<br />

(SELECT AVG(EDLEVEL)<br />

FROM CORPDATA.EMPLOYEE<br />

WHERE WORKDEPT = 'A00')<br />

Thus, <strong>for</strong> the row considered, the subquery produces the average education level<br />

of Christine’s department. This is then compared in the outer statement to<br />

Christine’s own education level. For some other row <strong>for</strong> which WORKDEPT has a<br />

different value, that value appears in the subquery in place of A00. For example,<br />

<strong>for</strong> the row <strong>for</strong> MICHAEL L THOMPSON, this value would be B01, and the<br />

subquery <strong>for</strong> his row would deliver the average education level <strong>for</strong> department<br />

B01.<br />

The result table produced by the query would have the following values:<br />

fetch<br />

1<br />

2<br />

3<br />

4<br />

(from CORPDATA.EMPLOYEE)<br />

EMPNO L<strong>AS</strong>TNAME WORKDEPT EDLEVEL<br />

000010<br />

000030<br />

000070<br />

000090<br />

HA<strong>AS</strong><br />

KWAN<br />

PUL<strong>AS</strong>KI<br />

HENDERSON<br />

A00<br />

C01<br />

D21<br />

E11<br />

18<br />

20<br />

16<br />

16<br />

RV2W560-3<br />

Chapter 5. Advanced Coding Techniques 89


Example: Correlated Subquery in a HAVING Clause<br />

Suppose that you want a list of all the departments whose average salary is higher<br />

than the average salary of their area (all departments whose WORKDEPT begins<br />

with the same letter belong to the same area). To get this in<strong>for</strong>mation, <strong>SQL</strong> must<br />

search the CORPDATA.EMPLOYEE table. For each department in the table, <strong>SQL</strong><br />

compares the department’s average salary to the average salary of the area. In the<br />

subquery, <strong>SQL</strong> calculates the average salary <strong>for</strong> the area of the department in the<br />

current group. For example:<br />

DECLARE XMP CURSOR FOR<br />

SELECT WORKDEPT, DECIMAL(AVG(SALARY),8,2)<br />

FROM CORPDATA.EMPLOYEE X<br />

GROUP BY WORKDEPT<br />

HAVING AVG(SALARY) ><br />

(SELECT AVG(SALARY)<br />

FROM CORPDATA.EMPLOYEE<br />

WHERE SUBSTR(X.WORKDEPT,1,1) = SUBSTR(WORKDEPT,1,1))<br />

Consider what happens when the subquery is executed <strong>for</strong> a given department of<br />

CORPDATA.EMPLOYEE. Be<strong>for</strong>e it is executed, the occurrence of X.WORKDEPT is<br />

replaced with the value of the WORKDEPT column <strong>for</strong> that group. Suppose, <strong>for</strong><br />

example, that the first group selected has A00 <strong>for</strong> the value of WORKDEPT. The<br />

subquery executed <strong>for</strong> this group is:<br />

(SELECT AVG(SALARY)<br />

FROM CORPDATA.EMPLOYEE<br />

WHERE SUBSTR('A00',1,1) = SUBSTR(WORKDEPT,1,1))<br />

Thus, <strong>for</strong> the group considered, the subquery produces the average salary <strong>for</strong> the<br />

area. This is then compared in the outer statement to the average salary <strong>for</strong><br />

department 'A00'. For some other group <strong>for</strong> which WORKDEPT is ’B01’, the<br />

subquery would result in the average salary <strong>for</strong> the area where department B01<br />

belongs.<br />

The result table produced by the query would have the following values:<br />

(from CORPDATA.EMPLOYEE)<br />

fetch WORKDEPT<br />

AVG<br />

SALARY<br />

1 D21 25153.33<br />

2 E01 40175.00<br />

RV2W561-3<br />

Correlated names and references<br />

A correlated reference can appear only in a search condition in a subquery. The<br />

reference is always of the <strong>for</strong>m X.C, where X is a correlation name and C is the<br />

name of a column in the table that X represents. In the preceding example, <strong>for</strong><br />

instance, X represents the table CORPDATA.EMPLOYEE, and C identifies the<br />

column WORKDEPT in this table.<br />

The correlation name is defined in the FROM clause of some query. This query<br />

could be the outer-level SELECT, or any of the subqueries that contain the one<br />

with the reference. Suppose, <strong>for</strong> example, that a query contains subqueries A, B,<br />

and C, and that A contains B and B contains C. Then a correlation name used in C<br />

could be defined in B, A, or the outer-level SELECT.<br />

90 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


You can define a correlation name <strong>for</strong> each table name appearing in a FROM<br />

clause. Simply include the correlation names after the table names. Leave one or<br />

more blanks between a table name and its correlation name, and place a comma<br />

after the correlation name if it is followed by another table name. The following<br />

FROM clause, <strong>for</strong> example, defines the correlation names TA and TB <strong>for</strong> the tables<br />

TABLEA and TABLEB, and no correlation name <strong>for</strong> the table TABLEC.<br />

FROM TABLEA TA, TABLEC, TABLEB TB<br />

Any number of correlated references can appear in a subquery. There are no<br />

restrictions on variety. For example, one correlated name in a reference could be<br />

defined in the outer-level SELECT, while another could be defined in a containing<br />

subquery.<br />

Be<strong>for</strong>e the subquery is executed, a value from the referenced column is always<br />

substituted <strong>for</strong> the correlated reference. The value is determined as follows:<br />

Note: Use D to designate the query in which the correlation name is defined. Then<br />

the subquery is either in the WHERE clause of D, or in its HAVING clause.<br />

v If the subquery is in the WHERE clause, its results are used by D to qualify a<br />

row. The substituted value is then taken from this row. This is the case <strong>for</strong> the<br />

example, where the defining query is the outer one and the subquery appears in<br />

the outer query’s WHERE clause.<br />

v If the subquery is in the HAVING clause, its results are used by D to qualify a<br />

group of rows. The substituted value is then taken from this group. Note that in<br />

this case, the column specified must be identified in the GROUP BY clause in D.<br />

If it is not, the specified column could have more than one value <strong>for</strong> the group.<br />

Using correlated subqueries in an UPDATE statement<br />

When you use a correlated subquery in an UPDATE statement, the correlation<br />

name refers to the rows you are interested in updating. For example, when all<br />

activities of a project must be completed be<strong>for</strong>e September 1983, your department<br />

considers that project to be a priority project. You could use the <strong>SQL</strong> statement<br />

below to evaluate the projects in the CORPDATA.PROJECT table, and write a1(a<br />

flag to indicate PRIORITY) in the PRIORITY column (a column you added to<br />

CORPDATA.PROJECT <strong>for</strong> this purpose) <strong>for</strong> each priority project.<br />

UPDATE CORPDATA.PROJECT X<br />

SET PRIORITY = 1<br />

WHERE '1983-09-01' ><br />

(SELECT MAX(EMENDATE)<br />

FROM CORPDATA.EMP_ACT<br />

WHERE PROJNO = X.PROJNO)<br />

As <strong>SQL</strong> examines each row in the CORPDATA.EMP_ACT table, it determines the<br />

maximum activity end date (EMENDATE) <strong>for</strong> all activities of the project (from the<br />

CORPDATA.PROJECT table). If the end date of each activity associated with the<br />

project is prior to September 1983, the current row in the CORPDATA.PROJECT<br />

table qualifies and is updated.<br />

Using correlated subqueries in a DELETE statement<br />

When you use a correlated subquery in a DELETE statement, the correlation name<br />

represents the row you delete. <strong>SQL</strong> evaluates the correlated subquery once <strong>for</strong> each<br />

row in the table named in the DELETE statement to decide whether or not to<br />

delete the row.<br />

Chapter 5. Advanced Coding Techniques 91


Suppose a row in the CORPDATA.PROJECT table was deleted. Rows related to the<br />

deleted project in the CORPDATA.EMP_ACT table must also be deleted. To do<br />

this, you can use:<br />

DELETE FROM CORPDATA.EMP_ACT X<br />

WHERE NOT EXISTS<br />

(SELECT *<br />

FROM CORPDATA.PROJECT<br />

WHERE PROJNO = X.PROJNO)<br />

<strong>SQL</strong> determines, <strong>for</strong> each row in the CORPDATA.EMP_ACT table, whether a row<br />

with the same project number exists in the CORPDATA.PROJECT table. If not, the<br />

CORPDATA.EMP_ACT row is deleted.<br />

Notes on using correlated subqueries<br />

Changing a table definition<br />

v The correlation name is separated from its associated table name with a space.<br />

To specify another table name, precede the table name with a comma, <strong>for</strong><br />

example:<br />

FROM CORPDATA.EMPLOYEE X, CORPDATA.PROJECT ....<br />

v The correlated subquery and the outer-level statement can refer to the same<br />

table or to different tables.<br />

v In an INSERT statement, neither the correlated subquery nor an outer-level<br />

SELECT within the INSERT statement can be based on the same table into<br />

which you are inserting.<br />

v The outer-level SELECT that defines the correlation name can join two or more<br />

tables.<br />

v You can use correlated subqueries in HAVING clauses. When you do, <strong>SQL</strong><br />

evaluates the subquery, once per group, of the outer-level SELECT. The column<br />

you refer to in the HAVING clause must specify a property of each group (<strong>for</strong><br />

example, WORKDEPT) either the columns you grouped the rows by or another<br />

column with one of the column functions.<br />

v You can nest correlated subqueries.<br />

Changing the definition of a table allows you to add new columns, change an<br />

existing column definition (change its length, default value, and so on), drop<br />

existing columns, and add and remove constraints. You can change the definition<br />

of a table using Operations Navigator. Or, use the <strong>SQL</strong> ALTER TABLE statement.<br />

You can add, change, or drop columns and add or remove constraints all with one<br />

ALTER TABLE statement. However, a single column can be referenced only once in<br />

the ADD COLUMN, ALTER COLUMN, and DROP COLUMN clauses. That is, you<br />

cannot add a column and then alter that column in the same ALTER TABLE<br />

statement.<br />

Adding a column<br />

You can add a column to a table using Operations Navigator. Or use the ADD<br />

COLUMN clause of the <strong>SQL</strong> ALTER TABLE statement.<br />

When you add a new column to a table, the column is initialized with its default<br />

value <strong>for</strong> all existing rows. If NOT NULL is specified, a default value must also be<br />

specified.<br />

92 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


|<br />

|<br />

|<br />

|<br />

|<br />

|<br />

The altered table may consist of up to 8000 columns. The sum of the byte counts of<br />

the columns must not be greater than 32766 or, if a VARCHAR or VARGRAPHIC<br />

column is specified, 32740. If a LOB column is specified, the sum of record data<br />

byte counts of the columns must not be greater than 15 728 640.<br />

Changing a column<br />

You can change a column definition in a table using Operations Navigator. Or, you<br />

can use the ALTER COLUMN clause of the ALTER TABLE statement. When you<br />

change the data type of an existing column, the old and new attributes must be<br />

compatible. “Allowable conversions” shows the conversions with compatible<br />

attributes.<br />

When you convert to a data type with a longer length, data will be padded with<br />

the appropriate pad character. When you convert to a data type with a shorter<br />

length, data may be lost due to truncation. An inquiry message prompts you to<br />

confirm the request.<br />

If you have a column that does not allow the null value and you want to change it<br />

to now allow the null value, use the DROP NOT NULL clause. If you have a<br />

column that allows the null value and you want to prevent the use of null values,<br />

use the SET NOT NULL clause. If any of the existing values in that column are the<br />

null value, the ALTER TABLE will not be per<strong>for</strong>med and an <strong>SQL</strong>CODE of -190 will<br />

result.<br />

Allowable conversions<br />

Table 15. Allowable Conversions<br />

FROM data type TO data type<br />

Decimal Numeric<br />

Decimal Bigint, Integer, Smallint<br />

Decimal Float<br />

Numeric Decimal<br />

Numeric Bigint, Integer, Smallint<br />

Numeric Float<br />

Bigint, Integer, Smallint Decimal<br />

Bigint, Integer, Smallint Numeric<br />

Bigint, Integer, Smallint Float<br />

Float Numeric<br />

Float Bigint, Integer, Smallint<br />

Character DBCS-open<br />

Character UCS-2 graphic<br />

DBCS-open Character<br />

DBCS-open UCS-2 graphic<br />

DBCS-either Character<br />

DBCS-either DBCS-open<br />

DBCS-either UCS-2 graphic<br />

DBCS-only DBCS-open<br />

Chapter 5. Advanced Coding Techniques 93


Table 15. Allowable Conversions (continued)<br />

FROM data type TO data type<br />

DBCS-only DBCS graphic<br />

DBCS-only UCS-2 graphic<br />

DBCS graphic UCS-2 graphic<br />

UCS-2 graphic Character<br />

UCS-2 graphic DBCS-open<br />

UCS-2 graphic DBCS graphic<br />

distinct type source type<br />

source type distinct type<br />

When modifying an existing column, only the attributes that you specify will be<br />

changed. All other attributes will remain unchanged. For example, given the<br />

following table definition:<br />

CREATE TABLE EX1 (COL1 CHAR(10) DEFAULT 'COL1',<br />

COL2 VARCHAR(20) ALLOCATE(10) CCSID 937,<br />

COL3 VARGRAPHIC(20) ALLOCATE(10)<br />

NOT NULL WITH DEFAULT)<br />

After running the following ALTER TABLE statement:<br />

ALTER TABLE EX1 ALTER COLUMN COL2 SET DATA TYPE VARCHAR(30)<br />

ALTER COLUMN COL3 DROP NOT NULL<br />

COL2 would still have an allocated length of 10 and CCSID 937, and COL3 would<br />

still have an allocated length of 10.<br />

Deleting a column<br />

You can delete a column using Operations Navigator. Or you can delete a column<br />

using the DROP COLUMN clause of the ALTER TABLE statement.<br />

Dropping a column deletes that column from the table definition. If C<strong>AS</strong>CADE is<br />

specified, any views, indexes, and constraints dependent on that column will also<br />

be dropped. If RESTRICT is specified, and any views, indexes, or constraints are<br />

dependent on the column, the column will not be dropped and <strong>SQL</strong>CODE of -196<br />

will be issued.<br />

Order of operations <strong>for</strong> ALTER TABLE statement<br />

An ALTER TABLE statement is per<strong>for</strong>med as a set of steps as follows:<br />

1. Drop constraints<br />

2. Drop columns <strong>for</strong> which the RESTRICT option was specified<br />

3. Alter column definitions (this includes adding columns and dropping columns<br />

<strong>for</strong> which the C<strong>AS</strong>CADE option was specified)<br />

4. Add constraints<br />

Within each of these steps, the order in which you specify the clauses is the order<br />

in which they are per<strong>for</strong>med, with one exception. If any columns are being<br />

dropped, that operation is logically done be<strong>for</strong>e any column definitions are added<br />

or altered, in case record length is increased as a result of the ALTER TABLE<br />

statement.<br />

94 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


Creating and using views<br />

A view can be used to access part of the data in one or more tables. You can define<br />

the columns of the view in the SELECT clause and the tables the view is based on<br />

in the FROM clause. To define the rows in the view, you can specify a WHERE<br />

clause, a GROUP by clause, or a HAVING clause.<br />

For example, to create a view that selects only the last name and the department of<br />

all the managers, specify:<br />

CREATE VIEW CORPDATA.EMP_MANAGERS <strong>AS</strong><br />

SELECT L<strong>AS</strong>TNAME, WORKDEPT FROM CORPDATA.EMPLOYEE<br />

WHERE JOB = 'MANAGER'<br />

If the select list contains elements other than columns such as expressions,<br />

functions, constants, or special registers, and the <strong>AS</strong> clause was not used to name<br />

the columns, a column list must be specified <strong>for</strong> the view. In the following<br />

example, the columns of the view are L<strong>AS</strong>TNAME and YEARSOFSERVICE.<br />

CREATE VIEW CORPDATA.EMP_YEARSOFSERVICE<br />

(L<strong>AS</strong>TNAME, YEARSOFSERVICE) <strong>AS</strong><br />

SELECT L<strong>AS</strong>TNAME, YEARS (CURRENT DATE - HIREDATE)<br />

FROM CORPDATA.EMPLOYEE<br />

The previous view can also be defined by using the <strong>AS</strong> clause in the select list to<br />

name the columns in the view. For example:<br />

CREATE VIEW CORPDATA.EMP_YEARSOFSERVICE <strong>AS</strong><br />

SELECT L<strong>AS</strong>TNAME,<br />

YEARS (CURRENT_DATE - HIREDATE) <strong>AS</strong> YEARSOFSERVICE<br />

FROM CORPDATA.EMPLOYEE<br />

Once you have created the view, you can use it to select the data or possibly<br />

change the data in the base table.<br />

The following restrictions must be considered when creating the view:<br />

v You cannot change, insert, or delete data in a read-only view. A view is<br />

read-only if it includes any of the following:<br />

– The first FROM clause identifies more than one table (join).<br />

– The first FROM clause identifies a read-only view.<br />

– The first SELECT clause contains any of the <strong>SQL</strong> column functions (SUM,<br />

MAX, MIN, AVG, COUNT, STDDEV, or VAR).<br />

– The first SELECT clause specifies the keyword DISTINCT.<br />

– The outer subselect contains a GROUP BY or HAVING clause.<br />

– A subquery, such that the base object of the outer-most subselect and a table<br />

of a subquery are the same table<br />

In the above cases, you can get data from the views by means of the <strong>SQL</strong><br />

SELECT statement, but you cannot use statements such as INSERT, UPDATE,<br />

or DELETE.<br />

v You cannot insert a row in a view if:<br />

– The table on which the view is based has a column that has no default value,<br />

does not allow nulls, and is not in the view.<br />

– The view has a column resulting from an expression, a constant, a function,<br />

or a special register and the column was specified in the INSERT column list.<br />

– The WITH CHECK OPTION was specified when the view was created and<br />

the row does not match the selection criteria.<br />

Chapter 5. Advanced Coding Techniques 95


Adding indexes<br />

v You cannot update a column of a view that results from an expression, a<br />

constant, a function, or a special register.<br />

v You cannot use UNION, UNION ALL, FOR UPDATE OF, FOR READ ONLY,<br />

ORDER BY, or OPTIMIZE FOR n ROWS in the definition of a view.<br />

Views are created with the sort sequence in effect at the time the CREATE VIEW<br />

statement is run. The sort sequence applies to all character and UCS-2 graphic<br />

comparisons in the CREATE VIEW statement subselect. See “Sort sequences in<br />

<strong>SQL</strong>” on page 50 <strong>for</strong> more in<strong>for</strong>mation on sort sequences.<br />

Views can also be created using the WITH CHECK OPTION to specify the level of<br />

checking that should be done when data is inserted or updated through the view.<br />

See “WITH CHECK OPTION on a View” on page 108 <strong>for</strong> more in<strong>for</strong>mation.<br />

You can use indexes to sort and select data. In addition, indexes help the system<br />

retrieve data faster <strong>for</strong> better query per<strong>for</strong>mance.<br />

You can create an index when creating a table using Operations Navigator. Or use<br />

the <strong>SQL</strong> CREATE INDEX statement. The following example creates an index over<br />

the column L<strong>AS</strong>TNAME in the CORPDATA.EMPLOYEE table:<br />

CREATE INDEX CORPDATA.INX1 ON CORPDATA.EMPLOYEE (L<strong>AS</strong>TNAME)<br />

You can create a number of indexes. However, because the indexes are maintained<br />

by the system, a large number of indexes can adversely affect per<strong>for</strong>mance. For<br />

more in<strong>for</strong>mation about indexes and query per<strong>for</strong>mance, see Effectively Using <strong>SQL</strong><br />

Indexes in the Database Per<strong>for</strong>mance and Query Optimization in<strong>for</strong>mation.<br />

One type of index, the encoded vector index, allows <strong>for</strong> faster scans that can be<br />

more easily processed in parallel. You create encoded vector indexes by using the<br />

<strong>SQL</strong> CREATE INDX statement. For more in<strong>for</strong>mation about accelerating your<br />

queries with encoded vector indexes , go to the <strong>DB2</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> webpages.<br />

If an index is created that has exactly the same attributes as an existing index, the<br />

new index shares the existing indexes’ binary tree. Otherwise, another binary tree<br />

is created. If the attributes of the new index are exactly the same as another index,<br />

except the new index has fewer columns, another binary tree is still created. It is<br />

still created because the extra columns would prevent the index from being used<br />

by cursors or UPDATE statements which update those extra columns.<br />

Indexes are created with the sort sequence in effect at the time the CREATE INDEX<br />

statement is run. The sort sequence applies to all SBCS character fields and UCS-2<br />

graphic fields of the index. See “Sort sequences in <strong>SQL</strong>” on page 50 <strong>for</strong> more<br />

in<strong>for</strong>mation on sort sequences.<br />

96 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


Catalogs in database design<br />

A catalog is automatically created when you create a collection. There is also a<br />

system-wide catalog that is always in the QSYS2 library. When an <strong>SQL</strong> object is<br />

created in a collection, in<strong>for</strong>mation is added to both the system catalog tables and<br />

the collection’s catalog tables. When an <strong>SQL</strong> object is created in a library, only the<br />

QSYS2 catalog is updated. For more in<strong>for</strong>mation about catalogs, see the <strong>SQL</strong><br />

Reference book.<br />

As the following examples show, you can display catalog in<strong>for</strong>mation. You cannot<br />

INSERT, DELETE, or UPDATE catalog in<strong>for</strong>mation. You must have SELECT<br />

privileges on the catalog views to run the following examples.<br />

Attention: Operations that normally update the <strong>SQL</strong> catalog <strong>for</strong> a collection can no<br />

longer update the catalog if the collection is saved, restored, and given a different<br />

name. Saving in one collection and restoring to another is not supported by the<br />

product.<br />

Getting catalog in<strong>for</strong>mation about a table<br />

SYSTABLES contains a row <strong>for</strong> every table and view in the <strong>SQL</strong> collection. It tells<br />

you if the object is a table or view, the object name, the owner of the object, what<br />

<strong>SQL</strong> collection it is in, and so <strong>for</strong>th.<br />

The following sample statement displays in<strong>for</strong>mation <strong>for</strong> the<br />

CORPDATA.DEPARTMENT table:<br />

SELECT *<br />

FROM CORPDATA.SYSTABLES<br />

WHERE NAME = 'DEPARTMENT'<br />

Getting catalog in<strong>for</strong>mation about a column<br />

SYSCOLUMNS contains a row <strong>for</strong> each column of every table and view in the<br />

collection.<br />

The following sample statement displays all the column names in the<br />

CORPDATA.DEPARTMENT table:<br />

SELECT *<br />

FROM CORPDATA.SYSCOLUMNS<br />

WHERE TBNAME = 'DEPARTMENT'<br />

The result of the previous sample statement is a row of in<strong>for</strong>mation <strong>for</strong> each<br />

column in the table. Some of the in<strong>for</strong>mation is not visible because the width of<br />

the in<strong>for</strong>mation is wider than the display screen.<br />

For more in<strong>for</strong>mation about each column, specify a select-statement like this:<br />

SELECT NAME, TBNAME, COLTYPE, LENGTH, DEFAULT<br />

FROM CORPDATA.SYSCOLUMNS<br />

WHERE TBNAME = 'DEPARTMENT'<br />

In addition to the column name <strong>for</strong> each column, the select-statement shows:<br />

v The name of the table that contains the column<br />

v The data type of the column<br />

v The length attribute of the column<br />

Chapter 5. Advanced Coding Techniques 97


v If the column allows default values<br />

The result looks like this:<br />

NAME TBNAME COLTYPE LENGTH DEFAULT<br />

DEPTNO DEPARTMENT CHAR 3 N<br />

DEPTNAME DEPARTMENT VARCHAR 29 N<br />

MGRNO DEPARTMENT CHAR 6 Y<br />

ADMRDEPT DEPARTMENT CHAR 3 N<br />

98 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


Chapter 6. Data Integrity<br />

Data integrity is the principle of ensuring data values between tables of a<br />

collection are kept in a state which makes sense to the business. For example, if a<br />

bank has a list of customers in table A and a list of customer accounts in table B, it<br />

would not make sense to allow a new account to be added to table B unless an<br />

associated customer exists in table A.<br />

This chapter describes the different ways the system automatically en<strong>for</strong>ces these<br />

kinds of relationships. Referential integrity, check constraints, and triggers are all<br />

ways of accomplishing data integrity. Additionally, the WITH CHECK OPTION<br />

clause on a CREATE VIEW constrains the inserting or updating of data through a<br />

view.<br />

For comprehensive in<strong>for</strong>mation about data integrity, see theDatabase <strong>Programming</strong><br />

book.<br />

Adding and using check constraints<br />

Referential integrity<br />

A check constraint assures the validity of data during inserts and updates by<br />

limiting the allowable values in a column or group of columns. You can add check<br />

constraints using Operations Navigator when creating a table. Or use the <strong>SQL</strong><br />

CREATE TABLE and ALTER TABLE statements to add or drop check constraints.<br />

In this example, the following statement creates a table with three columns and a<br />

check constraint over COL2 which limits the values allowed in that column to<br />

positive integers:<br />

CREATE TABLE T1 (COL1 INT, COL2 INT CHECK (COL2>0), COL3 INT)<br />

Given this table, the following statement:<br />

INSERT INTO T1 VALUES (-1, -1, -1)<br />

would fail because the value to be inserted into COL2 does not meet the check<br />

constraint; that is, -1 is not greater than 0.<br />

The following statement would be successful:<br />

INSERT INTO T1 VALUES (1, 1, 1)<br />

Once that row is inserted, the following statement would fail:<br />

ALTER TABLE T1 ADD CONSTRAINT C1 CHECK (COL1=1 AND COL1


Consider the following example: (These sample tables are given in Appendix A.<br />

<strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> Sample Tables:<br />

v CORPDATA.EMPLOYEE serves as a master list of employees.<br />

v CORPDATA.DEPARTMENT acts as a master list of all valid department<br />

numbers.<br />

v CORPDATA.EMP_ACT provides a master list of activities per<strong>for</strong>med <strong>for</strong><br />

projects.<br />

Other tables refer to the same entities described in these tables. When a table<br />

contains data <strong>for</strong> which there is a master list, that data should actually appear in<br />

the master list, or the reference is not valid. The table that contains the master list<br />

is the parent table, and the table that refers to it is a dependent table. When the<br />

references from the dependent table to the parent table are valid, the condition of<br />

the set of tables is called referential integrity.<br />

Stated another way, referential integrity is the state of a database in which all<br />

values of all <strong>for</strong>eign keys are valid. Each value of the <strong>for</strong>eign key must also exist in<br />

the parent key or be null. This definition of referential integrity requires an<br />

understanding of the following terms:<br />

v A unique key is a column or set of columns in a table which uniquely identify a<br />

row. Although a table can have several unique keys, no two rows in a table can<br />

have the same unique key value.<br />

v A primary key is a unique key that does not allow nulls. A table cannot have<br />

more than one primary key.<br />

v A parent key is either a unique key or a primary key which is referenced in a<br />

referential constraint.<br />

v A <strong>for</strong>eign key is a column or set of columns whose values must match those of a<br />

parent key. If any column value used to build the <strong>for</strong>eign key is null, then the<br />

rule does not apply.<br />

v A parent table is a table that contains the parent key.<br />

v A dependent table is the table that contains the <strong>for</strong>eign key.<br />

v A descendent table is a table that is a dependent table or a descendent of a<br />

dependent table.<br />

En<strong>for</strong>cement of referential integrity prevents the violation of the rule which states<br />

that every non-null <strong>for</strong>eign key must have a matching parent key.<br />

<strong>SQL</strong> supports the referential integrity concept with the CREATE TABLE and<br />

ALTER TABLE statements. For detailed descriptions of these commands, see the<br />

<strong>SQL</strong> Reference book.<br />

Adding or dropping referential constraints<br />

“Constraints” on page 245 are rules that ensure that references from one table, a<br />

dependent table, to data in another table, the parent table, are valid. You use<br />

referential constraints to ensure “Referential integrity” on page 99.<br />

You can add referential constraints using Operations Navigator when creating a<br />

table. Or, use the <strong>SQL</strong> CREATE TABLE and ALTER TABLE statements to add or<br />

change referential constraints.<br />

With a referential constraint, non-null values of the <strong>for</strong>eign key are valid only if<br />

they also appear as values of a parent key. When you define a referential<br />

constraint, you specify:<br />

100 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


v A primary or unique key<br />

v A <strong>for</strong>eign key<br />

v Delete and update rules that specify the action taken with respect to dependent<br />

rows when the parent row is deleted or updated.<br />

Optionally, you can specify a name <strong>for</strong> the constraint. If a name is not specified,<br />

one is automatically generated.<br />

Once a referential constraint is defined, the system en<strong>for</strong>ces the constraint on every<br />

INSERT, DELETE, and UPDATE operation per<strong>for</strong>med through <strong>SQL</strong> or any other<br />

interface including Operations Navigator, CL commands, utilities, or high-level<br />

language statements.<br />

Example: Adding referential constraints<br />

The rule that every department number shown in the sample employee table must<br />

appear in the department table is a referential constraint. This constraint ensures<br />

that every employee belongs to an existing department. The following <strong>SQL</strong><br />

statements create the CORPDATA.DEPARTMENT and CORPDATA.EMPLOYEE<br />

tables with those constraint relationships defined.<br />

CREATE TABLE CORPDATA.DEPARTMENT<br />

(DEPTNO CHAR(3) NOT NULL PRIMARY KEY,<br />

DEPTNAME VARCHAR(29) NOT NULL,<br />

MGRNO CHAR(6),<br />

ADMRDEPT CHAR(3) NOT NULL<br />

CONSTRAINT REPORTS_TO_EXISTS<br />

REFERENCES CORPDATA.DEPARTMENT (DEPTNO)<br />

ON DELETE C<strong>AS</strong>CADE)<br />

CREATE TABLE CORPDATA.EMPLOYEE<br />

(EMPNO CHAR(6) NOT NULL PRIMARY KEY,<br />

FIRSTNAME VARCHAR(12) NOT NULL,<br />

MIDINIT CHAR(1) NOT NULL,<br />

L<strong>AS</strong>TNAME VARCHAR(15) NOT NULL,<br />

WORKDEPT CHAR(3) CONSTRAINT WORKDEPT_EXISTS<br />

REFERENCES CORPDATA.DEPARTMENT (DEPTNO)<br />

ON DELETE SET NULL ON UPDATE RESTRICT,<br />

PHONENO CHAR(4),<br />

HIREDATE DATE,<br />

JOB CHAR(8),<br />

EDLEVEL SMALLINT NOT NULL,<br />

SEX CHAR(1),<br />

BIRTHDATE DATE,<br />

SALARY DECIMAL(9,2),<br />

BONUS DECIMAL(9,2),<br />

COMM DECIMAL(9,2),<br />

CONSTRAINT UNIQUE_LNAME_IN_DEPT UNIQUE (WORKDEPT, L<strong>AS</strong>TNAME))<br />

In this case, the DEPARTMENT table has a column of unique department numbers<br />

(DEPTNO) which functions as a primary key, and is a parent table in two<br />

constraint relationships:<br />

REPORTS_TO_EXISTS<br />

is a self-referencing constraint in which the DEPARTMENT table is both<br />

the parent and the dependent in the same relationship. Every non-null<br />

value of ADMRDEPT must match a value of DEPTNO. A department must<br />

report to an existing department in the database. The DELETE C<strong>AS</strong>CADE<br />

rule indicates that if a row with a DEPTNO value n is deleted, every row<br />

in the table <strong>for</strong> which the ADMRDEPT is n is also deleted.<br />

Chapter 6. Data Integrity 101


WORKDEPT_EXISTS<br />

establishes the EMPLOYEE table as a dependent table, and the column of<br />

employee department assignments (WORKDEPT) as a <strong>for</strong>eign key. Thus,<br />

every value of WORKDEPT must match a value of DEPTNO. The DELETE<br />

SET NULL rule says that if a row is deleted from DEPARTMENT in which<br />

the value of DEPTNO is n, then the value of WORKDEPT in EMPLOYEE<br />

is set to null in every row in which the value was n. The UPDATE<br />

RESTRICT rule says that a value of DEPTNO in DEPARTMENT cannot be<br />

updated if there are values of WORKDEPT in EMPLOYEE that match the<br />

current DEPTNO value.<br />

Constraint UNIQUE_LNAME_IN_DEPT in the EMPLOYEE table causes last names<br />

to be unique within a department. While this constraint is unlikely, it illustrates<br />

how a constraint made up of several columns can be defined at the table level.<br />

Removing referential constraints<br />

The ALTER TABLE statement can be used to add or drop one constraint at a time<br />

<strong>for</strong> a table. If the constraint being dropped is the parent key in some referential<br />

constraint relationship, the constraint between this parent file and any dependent<br />

files is also removed.<br />

DROP TABLE and DROP COLLECTION statements also remove any constraints<br />

on the table or collection being dropped.<br />

Example: Removing Constraints<br />

The following example removes the primary key over column DEPTNO in table<br />

DEPARTMENT. The constraints REPORTS_TO_EXISTS and WORKDEPT_EXISTS<br />

defined on tables DEPARTMENT and EMPLOYEE respectively will be removed as<br />

well, since the primary key being removed is the parent key in those constraint<br />

relationships.<br />

ALTER TABLE CORPDATA.EMPLOYEE DROP PRIMARY KEY<br />

You can also remove a constraint by name, as in the following example:<br />

ALTER TABLE CORPDATA.DEPARTMENT<br />

DROP CONSTRAINT UNIQUE_LNAME_IN_DEPT<br />

Inserting into tables with referential constraints<br />

There are some important things to remember when inserting data into tables with<br />

referential constraints. If you are inserting data into a parent table with a parent<br />

key, <strong>SQL</strong> does not allow:<br />

v Duplicate values <strong>for</strong> the parent key<br />

v If the parent key is a primary key, a null value <strong>for</strong> any column of the primary<br />

key<br />

If you are inserting data into a dependent table with <strong>for</strong>eign keys:<br />

v Each non-null value you insert into a <strong>for</strong>eign key column must be equal to some<br />

value in the corresponding parent key of the parent table.<br />

v If any column in the <strong>for</strong>eign key is null, the entire <strong>for</strong>eign key is considered null.<br />

If all <strong>for</strong>eign keys that contain the column are null, the INSERT succeeds (as<br />

long as there are no unique index violations).<br />

102 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


Example: Inserting data with constraints<br />

Alter the sample application project table (PROJECT) to define two <strong>for</strong>eign keys:<br />

v A <strong>for</strong>eign key on the department number (DEPTNO) which references the<br />

department table<br />

v A <strong>for</strong>eign key on the employee number (RESPEMP) which references the<br />

employee table.<br />

ALTER TABLE CORPDATA.PROJECT ADD CONSTRAINT RESP_DEPT_EXISTS<br />

FOREIGN KEY (DEPTNO)<br />

REFERENCES CORPDATA.DEPARTMENT<br />

ON DELETE RESTRICT<br />

ALTER TABLE CORPDATA.PROJECT ADD CONSTRAINT RESP_EMP_EXISTS<br />

FOREIGN KEY (RESPEMP)<br />

REFERENCES CORPDATA.EMPLOYEE<br />

ON DELETE RESTRICT<br />

Notice that the parent table columns are not specified in the REFERENCES clause.<br />

The columns are not required to be specified as long as the referenced table has a<br />

primary key or eligible unique key which can be used as the parent key.<br />

Every row inserted into the PROJECT table must have a value of DEPTNO that is<br />

equal to some value of DEPTNO in the department table. (The null value is not<br />

allowed because DEPTNO in the project table is defined as NOT NULL.) The row<br />

must also have a value of RESPEMP that is either equal to some value of EMPNO<br />

in the employee table or is null.<br />

The tables with the sample data as they appear in Appendix A. <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong><br />

<strong>AS</strong>/<strong>400</strong> Sample Tables con<strong>for</strong>m to these constraints. The following INSERT<br />

statement fails because there is no matching DEPTNO value (’A01’) inthe<br />

DEPARTMENT table.<br />

INSERT INTO CORPDATA.PROJECT (PROJNO, PROJNAME, DEPTNO, RESPEMP)<br />

VALUES ('AD3120', 'BENEFITS ADMIN', 'A01', '000010')<br />

Likewise, the following INSERT statement would be unsuccessful since there is no<br />

EMPNO value of ’000011’ in the EMPLOYEE table.<br />

INSERT INTO CORPDATA.PROJECT (PROJNO, PROJNAME, DEPTNO, RESPEMP)<br />

VALUES ('AD3130', 'BILLING', 'D21', '000011')<br />

The following INSERT statement completes successfully because there is a<br />

matching DEPTNO value of ’E01’ in the DEPARTMENT table and a matching<br />

EMPNO value of ’000010’ in the EMPLOYEE table.<br />

INSERT INTO CORPDATA.PROJECT (PROJNO, PROJNAME, DEPTNO, RESPEMP)<br />

VALUES ('AD3120', 'BENEFITS ADMIN', 'E01', '000010')<br />

Updating tables with referential constraints<br />

If you are updating a parent table, you cannot modify a primary key <strong>for</strong> which<br />

dependent rows exist. Changing the key violates referential constraints <strong>for</strong><br />

dependent tables and leaves some rows without a parent. Furthermore, you cannot<br />

give any part of a primary key a null value.<br />

Chapter 6. Data Integrity 103


Update Rules<br />

The action taken on dependent tables when an UPDATE is per<strong>for</strong>med on a parent<br />

table depends on the update rule specified <strong>for</strong> the referential constraint. If no<br />

update rule was defined <strong>for</strong> a referential constraint, the UPDATE NO ACTION<br />

rule is used.<br />

v UPDATE NO ACTION<br />

Specifies that the row in the parent table can be updated if no other row<br />

depends on it. If a dependent row exists in the relationship, the UPDATE fails.<br />

The check <strong>for</strong> dependent rows is per<strong>for</strong>med at the end of the statement.<br />

v UPDATE RESTRICT<br />

Specifies that the row in the parent table can be updated if no other row<br />

depends on it. If a dependent row exists in the relationship, the UPDATE fails.<br />

The check <strong>for</strong> dependent rows is per<strong>for</strong>med immediately.<br />

The subtle difference between RESTRICT and NO ACTION rules is easiest seen<br />

when looking at the interaction of triggers and referential constraints. Triggers can<br />

be defined to fire either be<strong>for</strong>e or after an operation (an UPDATE statement, in this<br />

case). A be<strong>for</strong>e trigger fires be<strong>for</strong>e the UPDATE is per<strong>for</strong>med and there<strong>for</strong>e be<strong>for</strong>e<br />

any checking of constraints. An after trigger is fired after the UPDATE is per<strong>for</strong>med,<br />

and after a constraint rule of RESTRICT (where checking is per<strong>for</strong>med<br />

immediately), but be<strong>for</strong>e a constraint rule of NO ACTION (where checking is<br />

per<strong>for</strong>med at the end of the statement). The triggers and rules would occur in the<br />

following order:<br />

1. A be<strong>for</strong>e trigger would be fired be<strong>for</strong>e the UPDATE and be<strong>for</strong>e a constraint rule<br />

of RESTRICT or NO ACTION.<br />

2. An after trigger would be fired after a constraint rule of RESTRICT, but be<strong>for</strong>e a<br />

NO ACTION rule.<br />

If you are updating a dependent table, any non-null <strong>for</strong>eign key values that you<br />

change must match the primary key <strong>for</strong> each relationship in which the table is a<br />

dependent. For example, department numbers in the employee table depend on<br />

the department numbers in the department table. You can assign an employee to<br />

no department (the null value), but not to a department that does not exist.<br />

If an UPDATE against a table with a referential constraint fails, all changes made<br />

during the update operation are undone. For more in<strong>for</strong>mation on the implications<br />

of commitment control and journaling when working with constraints, see<br />

“Journaling” on page 239 and “Commitment control” on page 239.<br />

Examples: UPDATE Rules<br />

For example, you cannot update a department number from the department table<br />

if it is still responsible <strong>for</strong> some project, which is described by a dependent row in<br />

the project table.<br />

The following UPDATE fails because the PROJECT table has rows which are<br />

dependent on DEPARTMENT.DEPTNO having a value of ’D01’ (the row targeted<br />

by the WHERE statement). If this UPDATE were allowed, the referential constraint<br />

between the PROJECT and DEPARTMENT tables would be broken.<br />

UPDATE CORPDATA.DEPARTMENT<br />

SET DEPTNO = 'D99'<br />

WHERE DEPTNAME = 'DEVELOPMENT CENTER'<br />

104 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


The following statement fails because it violates the referential constraint that exists<br />

between the primary key DEPTNO in DEPARTMENT and the <strong>for</strong>eign key<br />

DEPTNO in PROJECT:<br />

UPDATE CORPDATA.PROJECT<br />

SET DEPTNO = 'D00'<br />

WHERE DEPTNO = 'D01';<br />

The statement attempts to change all department numbers of D01 to department<br />

number D00. Since D00 is not a value of the primary key DEPTNO in<br />

DEPARTMENT, the statement fails.<br />

Deleting from tables with referential constraints<br />

If a table has a primary key but no dependents, DELETE operates as it does<br />

without referential constraints. The same is true if a table has only <strong>for</strong>eign keys,<br />

but no primary key. If a table has a primary key and dependent tables, DELETE<br />

deletes or updates rows according to the delete rules specified. All delete rules of<br />

all affected relationships must be satisfied in order <strong>for</strong> the delete operation to<br />

succeed. If a referential constraint is violated, the DELETE fails.<br />

The action to be taken on dependent tables when a DELETE is per<strong>for</strong>med on a<br />

parent table depends on the delete rule specified <strong>for</strong> the referential constraint. If no<br />

delete rule was defined, the DELETE NO ACTION rule is used.<br />

v DELETE NO ACTION<br />

Specifies that the row in the parent table can be deleted if no other row depends<br />

on it. If a dependent row exists in the relationship, the DELETE fails. The check<br />

<strong>for</strong> dependent rows is per<strong>for</strong>med at the end of the statement.<br />

v DELETE RESTRICT<br />

Specifies that the row in the parent table can be deleted if no other row depends<br />

on it. If a dependent row exists in the relationship, the DELETE fails. The check<br />

<strong>for</strong> dependent rows is per<strong>for</strong>med immediately.<br />

For example, you cannot delete a department from the department table if it is<br />

still responsible <strong>for</strong> some project which is described by a dependent row in the<br />

project table.<br />

v DELETE C<strong>AS</strong>CADE<br />

Specifies that first the designated rows in the parent table are deleted. Then, the<br />

dependent rows are deleted.<br />

For example, you can delete a department by deleting its row in the department<br />

table. Deleting the row from the department table also deletes:<br />

– The rows <strong>for</strong> all departments that report to it<br />

– All departments that report to those departments and so <strong>for</strong>th.<br />

v DELETE SET NULL<br />

Specifies that each nullable column of the <strong>for</strong>eign key in each dependent row is<br />

set to its default value. This means that the column is only set to its default<br />

value if it is a member of a <strong>for</strong>eign key that references the row being deleted.<br />

Only the dependent rows that are immediate descendents are affected.<br />

v DELETE SET DEFAULT<br />

Specifies that each column of the <strong>for</strong>eign key in each dependent row is set to its<br />

default value. This means that the column is only set to its default value if it is a<br />

member of a <strong>for</strong>eign key that references the row being deleted. Only the<br />

dependent rows that are immediate descendants are affected.<br />

Chapter 6. Data Integrity 105


For example, you can delete an employee from the employee table even if the<br />

employee manages some department. In that case, the value of MGRNO <strong>for</strong> each<br />

employee who reported to the manager is set to blanks in the department table.<br />

If some other default value was specified on the create of the table, that value is<br />

used.<br />

This is due to the REPORTS_TO_EXISTS constraint defined <strong>for</strong> the department<br />

table.<br />

If a descendent table has a delete rule of RESTRICT or NO ACTION and a row is<br />

found such that a descendant row cannot be deleted, the entire DELETE fails.<br />

When running this statement with a program, the number of rows deleted is<br />

returned in <strong>SQL</strong>ERRD(3) in the <strong>SQL</strong>CA. This number includes only the number of<br />

rows deleted in the table specified in the DELETE statement. It does not include<br />

those rows deleted according to the C<strong>AS</strong>CADE rule. <strong>SQL</strong>ERRD(5) in the <strong>SQL</strong>CA<br />

contains the number of rows that were affected by referential constraints in all<br />

tables.<br />

The subtle difference between RESTRICT and NO ACTION rules is easiest seen<br />

when looking at the interaction of triggers and referential constraints. Triggers can<br />

be defined to fire either be<strong>for</strong>e or after an operation (a DELETE statement, in this<br />

case). A be<strong>for</strong>e trigger fires be<strong>for</strong>e the DELETE is per<strong>for</strong>med and there<strong>for</strong>e be<strong>for</strong>e<br />

any checking of constraints. An after trigger is fired after the DELETE is per<strong>for</strong>med,<br />

and after a constraint rule of RESTRICT (where checking is per<strong>for</strong>med<br />

immediately), but be<strong>for</strong>e a constraint rule of NO ACTION (where checking is<br />

per<strong>for</strong>med at the end of the statement). The triggers and rules would occur in the<br />

following order:<br />

1. A be<strong>for</strong>e trigger would be fired be<strong>for</strong>e the DELETE and be<strong>for</strong>e a constraint rule<br />

of RESTRICT or NO ACTION.<br />

2. An after trigger would be fired after a constraint rule of RESTRICT, but be<strong>for</strong>e a<br />

NO ACTION rule.<br />

Example: DELETE Cascade Rule<br />

Deleting a department from the department table sets WORKDEPT (in the<br />

employee table) to null <strong>for</strong> every employee assigned to that department. Consider<br />

the following DELETE statement:<br />

DELETE FROM CORPDATA.DEPARTMENT<br />

WHERE DEPTNO = 'E11'<br />

Given the tables and the data as they appear in Appendix A. <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong><br />

Sample Tables, one row is deleted from table DEPARTMENT, and table<br />

EMPLOYEE is updated to set the value of WORKDEPT to its default wherever the<br />

value was ’E11’. A question mark (’?’) in the sample data below reflects the null<br />

value. The results would appear as follows:<br />

Table 16. DEPARTMENT Table. Contents of the table after the DELETE statement is<br />

complete.<br />

DEPTNO DEPTNAME MGRNO ADMRDEPT<br />

A00 SPIFFY COMPUTER SERVICE DIV. 000010 A00<br />

B01 PLANNING 000020 A00<br />

C01 INFORMATION CENTER 000030 A00<br />

D01 DEVELOPMENT CENTER ? A00<br />

D11 MANUFACTURING SYSTEMS 000060 D01<br />

106 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


Table 16. DEPARTMENT Table (continued). Contents of the table after the DELETE<br />

statement is complete.<br />

DEPTNO DEPTNAME MGRNO ADMRDEPT<br />

D21 ADMINISTRATION SYSTEMS 000070 D01<br />

E01 SUPPORT SERVICES 000050 A00<br />

E21 SOFTWARE SUPPORT 000100 E01<br />

Note that there were no cascaded deletes in the DEPARTMENT table because no<br />

department reported to department ’E11’.<br />

Below are snapshots of the affected portion of the EMPLOYEE table be<strong>for</strong>e and<br />

after the DELETE statement is completed.<br />

Table 17. Partial EMPLOYEE Table. Partial contents be<strong>for</strong>e the DELETE statement.<br />

EMPNO FIRSTNME MI L<strong>AS</strong>TNAME WORKDEPTPHONENO HIREDATE<br />

000230 JAMES J JEFFERSON D21 2094 1966-11-21<br />

000240 SALVATORE M MARINO D21 3780 1979-12-05<br />

000250 DANIEL S SMITH D21 0961 1960-10-30<br />

000260 SYBIL P JOHNSON D21 8953 1975-09-11<br />

000270 MARIA L PEREZ D21 9001 1980-09-30<br />

000280 ETHEL R SCHNEIDER E11 0997 1967-03-24<br />

000290 JOHN R PARKER E11 4502 1980-05-30<br />

000300 PHILIP X SMITH E11 2095 1972-06-19<br />

000310 MAUDE F SETRIGHT E11 3332 1964-09-12<br />

000320 RAMLAL V MEHTA E21 9990 1965-07-07<br />

000330 WING LEE E21 2103 1976-02-23<br />

000340 J<strong>AS</strong>ON R GOUNOT E21 5696 1947-05-05<br />

Table 18. Partial EMPLOYEE Table. Partial contents after the DELETE statement.<br />

EMPNO FIRSTNME MI L<strong>AS</strong>TNAME WORKDEPTPHONENO HIREDATE<br />

000230 JAMES J JEFFERSON D21 2094 1966-11-21<br />

000240 SALVATORE M MARINO D21 3780 1979-12-05<br />

000250 DANIEL S SMITH D21 0961 1960-10-30<br />

000260 SYBIL P JOHNSON D21 8953 1975-09-11<br />

000270 MARIA L PEREZ D21 9001 1980-09-30<br />

000280 ETHEL R SCHNEIDER ? 0997 1967-03-24<br />

000290 JOHN R PARKER ? 4502 1980-05-30<br />

000300 PHILIP X SMITH ? 2095 1972-06-19<br />

000310 MAUDE F SETRIGHT ? 3332 1964-09-12<br />

000320 RAMLAL V MEHTA E21 9990 1965-07-07<br />

000330 WING LEE E21 2103 1976-02-23<br />

000340 J<strong>AS</strong>ON R GOUNOT E21 5696 1947-05-05<br />

Check pending<br />

Referential constraints and check constraints can be in a state known as check<br />

pending, where potential violations of the constraint exist. For referential<br />

Chapter 6. Data Integrity 107


constraints, a violation occurs when potential mismatches exist between parent and<br />

<strong>for</strong>eign keys. For check constraints, a violation occurs when potential values exist<br />

in columns which are limited by the check constraint. When the system determines<br />

that the constraint may have been violated (such as after a restore operation), the<br />

constraint is marked as check pending. When this happens, restrictions are placed<br />

on the use of tables involved in the constraint. For referential constraints, the<br />

following restrictions apply:<br />

v No input or output operations are allowed on the dependent file.<br />

v Only read and insert operations are allowed on the parent file.<br />

When a check constraint is in check pending, the following restrictions apply:<br />

v Read operations are not allowed on the file.<br />

v Inserts and updates are allowed and the constraint is en<strong>for</strong>ced.<br />

To get a constraint out of check pending, you must:<br />

1. Disable the relationship with the Change Physical File Constraint (CHGPFCST)<br />

CL command.<br />

2. Correct the key (<strong>for</strong>eign, parent, or both) data <strong>for</strong> referential constraints or<br />

column data <strong>for</strong> check constraints.<br />

3. Enable the constraint again with the CHGPFCST CL command.<br />

You can identify the rows that are in violation of the constraint with the Display<br />

Check Pending Constraint (DSPCPCST) CL command.<br />

For more in<strong>for</strong>mation on working with tables in check pending, see the Database<br />

<strong>Programming</strong> book.<br />

WITH CHECK OPTION on a View<br />

WITH CHECK OPTION is an optional clause on the CREATE VIEW statement that<br />

specifies the level of checking to be done when inserting or updating data through<br />

a view. If the option is specified, every row that is inserted or updated through the<br />

view must con<strong>for</strong>m to the definition of that view.<br />

WITH CHECK OPTION cannot be specified if the view is read-only. The definition<br />

of the view must not include a subquery.<br />

If the view is created without a WITH CHECK OPTION clause, insert and update<br />

operations that are per<strong>for</strong>med on the view are not checked <strong>for</strong> con<strong>for</strong>mance to the<br />

view definition. Some checking might still occur if the view is directly or indirectly<br />

dependent on another view that includes WITH CHECK OPTION. Because the<br />

definition of the view is not used, rows might be inserted or updated through the<br />

view that do not con<strong>for</strong>m to the definition of the view. This means that the rows<br />

could not be selected again using the view.<br />

The checking can either be C<strong>AS</strong>CADED or LOCAL. See the <strong>SQL</strong> Reference book<br />

<strong>for</strong> additional discussion of WITH CHECK OPTION.<br />

WITH C<strong>AS</strong>CADED CHECK OPTION<br />

The WITH C<strong>AS</strong>CADED CHECK OPTION specifies that every row that is inserted<br />

or updated through the view must con<strong>for</strong>m to the definition of the view. In<br />

108 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


addition, the search conditions of all dependent views are checked when a row is<br />

inserted or updated. If a row does not con<strong>for</strong>m to the definition of the view, that<br />

row cannot be retrieved using the view.<br />

For example, consider the following updateable view:<br />

CREATE VIEW V1 <strong>AS</strong> SELECT COL1<br />

FROM T1 WHERE COL1 > 10<br />

Because no WITH CHECK OPTION is specified, the following INSERT statement<br />

is successful even though the value being inserted does not meet the search<br />

condition of the view.<br />

INSERT INTO V1 VALUES (5)<br />

Create another view over V1, specifying the WITH C<strong>AS</strong>CADED CHECK OPTION:<br />

CREATE VIEW V2 <strong>AS</strong> SELECT COL1<br />

FROM V1 WITH C<strong>AS</strong>CADED CHECK OPTION<br />

The following INSERT statement fails because it would produce a row that does<br />

not con<strong>for</strong>m to the definition of V2:<br />

INSERT INTO V2 VALUES (5)<br />

Consider one more view created over V2:<br />

CREATE VIEW V3 <strong>AS</strong> SELECT COL1<br />

FROM V2 WHERE COL1 < 100<br />

The following INSERT statement fails only because V3 is dependent on V2, and V2<br />

has a WITH C<strong>AS</strong>CADED CHECK OPTION.<br />

INSERT INTO V3 VALUES (5)<br />

However, the following INSERT statement is successful because it con<strong>for</strong>ms to the<br />

definition of V2. Because V3 does not have a WITH C<strong>AS</strong>CADED CHECK<br />

OPTION, it does not matter that the statement does not con<strong>for</strong>m to the definition<br />

of V3.<br />

INSERT INTO V3 VALUES (200)<br />

WITH LOCAL CHECK OPTION<br />

WITH LOCAL CHECK OPTION is identical to WITH C<strong>AS</strong>CADED CHECK<br />

OPTION except that you can update a row so that it no longer can be retrieved<br />

through the view. This can only happen when the view is directly or indirectly<br />

dependent on a view that was defined with no WITH CHECK OPTION clause.<br />

For example, consider the same updateable view used in the previous example:<br />

CREATE VIEW V1 <strong>AS</strong> SELECT COL1<br />

FROM T1 WHERE COL1 > 10<br />

Create second view over V1, this time specifying WITH LOCAL CHECK OPTION:<br />

CREATE VIEW V2 <strong>AS</strong> SELECT COL1<br />

FROM V1 WITH LOCAL CHECK OPTION<br />

The same INSERT that failed in the previous C<strong>AS</strong>CADED CHECK OPTION<br />

example would succeed now because V2 does not have any search conditions, and<br />

the search conditions of V1 do not need to be checked since V1 does not specify a<br />

check option.<br />

INSERT INTO V2 VALUES (5)<br />

Chapter 6. Data Integrity 109


If we again consider one more view created over V2:<br />

CREATE VIEW V3 <strong>AS</strong> SELECT COL1<br />

FROM V2 WHERE COL1 < 100<br />

The following INSERT is successful again because the search condition on V1 is<br />

not checked due to the WITH LOCAL CHECK OPTION on V2, versus the WITH<br />

C<strong>AS</strong>CADED CHECK OPTION in the previous example.<br />

INSERT INTO V3 VALUES (5)<br />

The difference between LOCAL and C<strong>AS</strong>CADED CHECK OPTION lies in how<br />

many of the dependent views’ search conditions are checked when a row is<br />

inserted or updated.<br />

v WITH LOCAL CHECK OPTION specifies that the search conditions of only<br />

those dependent views that have the WITH LOCAL CHECK OPTION or WITH<br />

C<strong>AS</strong>CADED CHECK OPTION are checked when a row is inserted or updated.<br />

v WITH C<strong>AS</strong>CADED CHECK OPTION specifies that the search conditions of all<br />

dependent views are checked when a row is inserted or updated.<br />

Example: Cascaded check option<br />

Use the following table and views:<br />

CREATE TABLE T1 (COL1 CHAR(10))<br />

CREATE VIEW V1 <strong>AS</strong> SELECT COL1<br />

FROM T1 WHERE COL1 LIKE 'A%'<br />

CREATE VIEW V2 <strong>AS</strong> SELECT COL1<br />

FROM V1 WHERE COL1 LIKE '%Z'<br />

WITH LOCAL CHECK OPTION<br />

CREATE VIEW V3 <strong>AS</strong> SELECT COL1<br />

FROM V2 WHERE COL1 LIKE 'AB%'<br />

CREATE VIEW V4 <strong>AS</strong> SELECT COL1<br />

FROM V3 WHERE COL1 LIKE '%YZ'<br />

WITH C<strong>AS</strong>CADED CHECK OPTION<br />

CREATE VIEW V5 <strong>AS</strong> SELECT COL1<br />

FROM V4 WHERE COL1 LIKE 'ABC%'<br />

Different search conditions are going to be checked depending on which view is<br />

being operated on with an INSERT or UPDATE.<br />

v If V1 is operated on, no conditions are checked because V1 does not have a<br />

WITH CHECK OPTION specified.<br />

v If V2 is operated on,<br />

– COL1 must end in the letter Z, but it doesn’t have to start with the letter A.<br />

This is because the check option is LOCAL, and view V1 does not have a<br />

check option specified.<br />

v If V3 is operated on,<br />

– COL1 must end in the letter Z, but it does not have to start with the letter A.<br />

V3 does not have a check option specified, so its own search condition must<br />

not be met. However, the search condition <strong>for</strong> V2 must be checked since V3 is<br />

defined on V2, and V2 has a check option.<br />

v If V4 is operated on,<br />

110 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


– COL1 must start with ’AB’, and must end with ’YZ’. Because V4 has the<br />

WITH C<strong>AS</strong>CADED CHECK OPTION specified, every search condition <strong>for</strong><br />

every view on which V4 is dependent must be checked.<br />

v If V5 is operated on,<br />

– COL1 must start with ’AB’, but not necessarily ’ABC’. This is because V5 does<br />

not specify a check option, so its own search condition does not need to be<br />

checked. However, because V5 is defined on V4, and V4 had a cascaded<br />

check option, every search condition <strong>for</strong> V4, V3, V2, and V1 must be checked.<br />

That is, COL1 must start with ’AB’ and end with ’YZ’.<br />

If V5 were created WITH LOCAL CHECK OPTION, operating on V5 would mean<br />

that COL1 must start with ’ABC’ and end with ’YZ’. The LOCAL CHECK OPTION<br />

adds the additional requirement that the third character must be a ’C’.<br />

<strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> trigger support<br />

A trigger is a set of actions that are run automatically when a specified change<br />

operation is per<strong>for</strong>med on a specified physical database file. In this discussion, a<br />

table is a physical file. The change operation can be an insert, update, or delete<br />

high level language statement in an application program, or an <strong>SQL</strong> INSERT,<br />

UPDATE, or DELETE statement. Triggers are useful <strong>for</strong> tasks such as en<strong>for</strong>cing<br />

business rules, validating input data, and keeping an audit trail.<br />

In <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong>, the program containing the set of trigger actions can be<br />

defined in any supported high level language. The trigger program can have <strong>SQL</strong><br />

embedded in it. To use trigger support, you must create a trigger program and add<br />

it to a physical file using the ADDPFTRG CL command. To add a trigger to a file,<br />

you must:<br />

v Identify the physical file<br />

v Identify the kind of operation<br />

v Identify the program that per<strong>for</strong>ms the desired actions.<br />

There is no <strong>SQL</strong> statement to associate a physical file with a trigger program. <strong>SQL</strong><br />

is only involved in that the trigger program can contain embedded <strong>SQL</strong><br />

statements, and that it could be an <strong>SQL</strong> INSERT, UPDATE, or DELETE that causes<br />

the trigger to be fired.<br />

Once a trigger program is associated with a physical file, the system trigger<br />

support calls the trigger program when a change operation is initiated against the<br />

physical file or table, or any logical file or view created over the physical file.<br />

Each change operation can call a trigger be<strong>for</strong>e or after the change operation<br />

occurs. Thus, a physical file can be associated with a maximum of six triggers<br />

v Be<strong>for</strong>e delete trigger<br />

v Be<strong>for</strong>e insert trigger<br />

v Be<strong>for</strong>e update trigger<br />

v After delete trigger<br />

v After insert trigger<br />

v After update trigger<br />

Chapter 6. Data Integrity 111


Trigger sample<br />

A sample trigger program follows. It is written in ILE C, with embedded <strong>SQL</strong>.<br />

See the Database <strong>Programming</strong> book <strong>for</strong> a full discussion and more examples of<br />

trigger usage in <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong>.<br />

#include "string.h"<br />

#include "stdlib.h"<br />

#include "stdio.h"<br />

#include <br />

#include <br />

#include "qsysinc/h/trgbuf" /* Trigger input parameter */<br />

#include "lib1/csrc/msghand1" /* User defined message handler */<br />

/*********************************************************************/<br />

/* This is a trigger program which is called whenever there is an */<br />

/* update to the EMPLOYEE table. If the employee's commission is */<br />

/* greater than the maximum commission, this trigger program will */<br />

/* increase the employee's salary by 1.04 percent and insert into */<br />

/* the RAISE table. */<br />

/* */<br />

/* The EMPLOYEE record in<strong>for</strong>mation is passed from the input parameter*/<br />

/* to this trigger program. */<br />

/*********************************************************************/<br />

Qdb_Trigger_Buffer_t *hstruct;<br />

char *datapt;<br />

/*******************************************************/<br />

/* Structure of the EMPLOYEE record which is used to */<br />

/* store the old or the new record that is passed to */<br />

/* this trigger program. */<br />

/* */<br />

/* Note : You must ensure that all the numeric fields */<br />

/* are aligned at 4 byte boundary in C. */<br />

/* Used either Packed struct or filler to reach */<br />

/* the byte boundary alignment. */<br />

/*******************************************************/<br />

_Packed struct rec{<br />

char empn[6];<br />

_Packed struct { short fstlen ;<br />

char fstnam[12];<br />

} fstname;<br />

char minit[1];<br />

_Packed struct { short lstlen;<br />

char lstnam[15];<br />

} lstname;<br />

char dept[3];<br />

char phone[4];<br />

char hdate[10];<br />

char jobn[8];<br />

short edclvl;<br />

char sex1[1];<br />

char bdate[10];<br />

decimal(9,2) salary1;<br />

decimal(9,2) bonus1;<br />

decimal(9,2) comm1;<br />

} oldbuf, newbuf;<br />

EXEC <strong>SQL</strong> INCLUDE <strong>SQL</strong>CA;<br />

Figure 2. Sample Trigger Program (Part 1 of 5)<br />

112 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


main(int argc, char **argv)<br />

{<br />

int i;<br />

int obufoff; /* old buffer offset */<br />

int nuloff; /* old null byte map offset */<br />

int nbufoff; /* new buffer offset */<br />

int nul2off; /* new null byte map offset */<br />

short work_days = 253; /* work days during in one year */<br />

decimal(9,2) commission = 2000.00; /* cutoff to qualify <strong>for</strong> */<br />

decimal(9,2) percentage = 1.04; /* raised salary as percentage */<br />

char raise_date[12] = "1982-06-01";/* effective raise date */<br />

struct {<br />

char empno[6];<br />

char name[30];<br />

decimal(9,2) salary;<br />

decimal(9,2) new_salary;<br />

} rpt1;<br />

/*******************************************************/<br />

/* Start to monitor any exception. */<br />

/*******************************************************/<br />

_FEEDBACK fc;<br />

_HDLR_ENTRY hdlr = main_handler;<br />

/****************************************/<br />

/* Make the exception handler active. */<br />

/****************************************/<br />

CEEHDLR(&hdlr, NULL, &fc);<br />

/****************************************/<br />

/* Ensure exception handler OK */<br />

/****************************************/<br />

if (fc.MsgNo != CEE0000)<br />

{<br />

printf("Failed to register exception handler.\n");<br />

exit(99);<br />

};<br />

/*******************************************************/<br />

/* Move the data from the trigger buffer to the local */<br />

/* structure <strong>for</strong> reference. */<br />

/*******************************************************/<br />

hstruct = (Qdb_Trigger_Buffer_t *)argv[1];<br />

datapt = (char *) hstruct;<br />

obufoff = hstruct ->Old_Record_Offset; /* old buffer */<br />

memcpy(&oldbuf,datapt+obufoff,; hstruct->Old_Record_Len);<br />

nbufoff = hstruct ->New_Record_Offset; /* new buffer */<br />

memcpy(&newbuf,datapt+nbufoff,; hstruct->New_Record_Len);<br />

Figure 2. Sample Trigger Program (Part 2 of 5)<br />

Chapter 6. Data Integrity 113


EXEC <strong>SQL</strong> WHENEVER <strong>SQL</strong>ERROR GO TO ERR_EXIT;<br />

/*******************************************************/<br />

/* Set the transaction isolation level to the same as */<br />

/* the application based on the input parameter in the */<br />

/* trigger buffer. */<br />

/*******************************************************/<br />

if(strcmp(hstruct->Commit_Lock_Level,"0") == 0)<br />

EXEC <strong>SQL</strong> SET TRANSACTION ISOLATION LEVEL NONE;<br />

else{<br />

if(strcmp(hstruct->Commit_Lock_Level,"1") == 0)<br />

EXEC <strong>SQL</strong> SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED, READ<br />

WRITE;<br />

else {<br />

if(strcmp(hstruct->Commit_Lock_Level,"2") == 0)<br />

EXEC <strong>SQL</strong> SET TRANSACTION ISOLATION LEVEL READ COMMITTED;<br />

else<br />

if(strcmp(hstruct->Commit_Lock_Level,"3") == 0)<br />

EXEC <strong>SQL</strong> SET TRANSACTION ISOLATION LEVEL ALL;<br />

}<br />

}<br />

/********************************************************/<br />

/* If the employee's commission is greater than maximum */<br />

/* commission, then increase the employee's salary */<br />

/* by 1.04 percent and insert into the RAISE table. */<br />

/********************************************************/<br />

if (newbuf.comm1 >= commission)<br />

{<br />

EXEC <strong>SQL</strong> SELECT EMPNO, EMPNAME, SALARY<br />

INTO :rpt1.empno, :rpt1.name, :rpt1.salary<br />

FROM TRGPERF/EMP_ACT<br />

WHERE EMP_ACT.EMPNO=:newbuf.empn ;<br />

if (sqlca.sqlcode == 0) then<br />

{<br />

rpt1.new_salary = salary * percentage;<br />

EXEC <strong>SQL</strong> INSERT INTO TRGPERF/RAISE VALUES(:rpt1);<br />

}<br />

goto finished;<br />

}<br />

err_exit:<br />

exit(1);<br />

/* All done */<br />

finished:<br />

return;<br />

} /* end of main line */<br />

Figure 2. Sample Trigger Program (Part 3 of 5)<br />

114 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


******************************************************************/<br />

/* INCLUDE NAME : MSGHAND1 */<br />

/* */<br />

/* DESCRIPTION : Message handler to signal an exception to */<br />

/* the application to in<strong>for</strong>m that an */<br />

/* error occured in the trigger program. */<br />

/* */<br />

/* NOTE : This message handler is a user defined routine. */<br />

/* */<br />

/******************************************************************/<br />

#include <br />

#include <br />

#include <br />

#include <br />

#pragma linkage (QMHSNDPM, OS)<br />

void QMHSNDPM(char *, /* Message identifier */<br />

void *, /* Qualified message file name */<br />

void *, /* Message data or text */<br />

int, /* Length of message data or text */<br />

char *, /* Message type */<br />

char *, /* Call message queue */<br />

int, /* Call stack counter */<br />

void *, /* Message key */<br />

void *, /* Error code */<br />

...); /* Optionals:<br />

length of call message queue<br />

name<br />

Call stack entry qualification<br />

display external messages<br />

screen wait time */<br />

/*********************************************************************/<br />

/******** This is the start of the exception handler function. */<br />

/*********************************************************************/<br />

void main_handler(_FEEDBACK *cond, _POINTER *token, _INT4 *rc,<br />

_FEEDBACK *new)<br />

{<br />

/****************************************/<br />

/* Initialize variables <strong>for</strong> call to */<br />

/* QMHSNDPM. */<br />

/* User must create a message file and */<br />

/* define a message ID to match the */<br />

/* following data. */<br />

/****************************************/<br />

char message_id[7] = "TRG9999";<br />

char message_file[20] = "MSGF LIB1 ";<br />

char message_data[50] = "Trigger error " ;<br />

int message_len = 30;<br />

char message_type[10] = "*ESCAPE ";<br />

char message_q[10] = "_C_pep ";<br />

int pgm_stack_cnt = 1;<br />

char message_key[4];<br />

Figure 2. Sample Trigger Program (Part 4 of 5)<br />

Chapter 6. Data Integrity 115


struct error_code {<br />

int bytes_provided;<br />

int bytes_available;<br />

char message_id[7];<br />

} error_code;<br />

/****************************************/<br />

/* Declare error code structure <strong>for</strong> */<br />

/* QMHSNDPM. */<br />

/****************************************/<br />

error_code.bytes_provided = 15;<br />

/****************************************/<br />

/* Set the error handler to resume and */<br />

/* mark the last escape message as */<br />

/* handled. */<br />

/****************************************/<br />

*rc = CEE_HDLR_RESUME;<br />

/****************************************/<br />

/* Send my own *ESCAPE message. */<br />

/****************************************/<br />

QMHSNDPM(message_id,<br />

&message_file,<br />

&message_data,<br />

message_len,<br />

message_type,<br />

message_q,<br />

pgm_stack_cnt,<br />

&message_key,<br />

&error_code );<br />

/****************************************/<br />

/* Check that the call to QMHSNDPM */<br />

/* finished correctly. */<br />

/****************************************/<br />

if (error_code.bytes_available != 0)<br />

{<br />

printf("Error in QMHOVPM : %s\n", error_code.message_id);<br />

}<br />

}<br />

Figure 2. Sample Trigger Program (Part 5 of 5)<br />

116 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


Chapter 7. Stored Procedures<br />

Creating a procedure<br />

<strong>DB2</strong> <strong>SQL</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> stored procedure support provides a way <strong>for</strong> an <strong>SQL</strong><br />

application to define and then invoke a procedure through <strong>SQL</strong> statements. Stored<br />

procedures can be used in both distributed and non-distributed <strong>DB2</strong> <strong>SQL</strong> <strong>for</strong><br />

<strong>AS</strong>/<strong>400</strong> applications. One of the big advantages in using stored procedures is that<br />

<strong>for</strong> distributed applications, the execution of one CALL statement on the<br />

application requester, or client, can per<strong>for</strong>m any amount of work on the application<br />

server.<br />

You may define a procedure as either an <strong>SQL</strong> procedure or an external procedure.<br />

An external procedure can be any supported high level language program (except<br />

System/36* programs and procedures) or a REXX procedure. The procedure does<br />

not need to contain <strong>SQL</strong> statements, but it may contain <strong>SQL</strong> statements. An <strong>SQL</strong><br />

procedure is defined entirely in <strong>SQL</strong>, and can contain <strong>SQL</strong> statements that include<br />

<strong>SQL</strong> control statements.<br />

Coding stored procedures requires that the user understand the following:<br />

v Stored procedure definition through the CREATE PROCEDURE statement<br />

v Stored procedure invocation through the CALL statement<br />

v Parameter passing conventions<br />

v Methods <strong>for</strong> returning a completion status to the program invoking the<br />

procedure.<br />

You may define stored procedures by using the CREATE PROCEDURE statement.<br />

The CREATE PROCEDURE statement adds procedure and parameter definitions to<br />

the catalog tables SYSROUTINES and SYSPARMS. These definitions are then<br />

accessible by any <strong>SQL</strong> CALL statement on the system.<br />

The following sections describe the <strong>SQL</strong> statements used to define and invoke the<br />

stored procedure, in<strong>for</strong>mation on passing parameters to the stored procedure, and<br />

examples of stored procedure usage.<br />

A procedure (often called a stored procedure) is a program that can be called to<br />

per<strong>for</strong>m operations that can include both host language statements and <strong>SQL</strong><br />

statements. Procedures in <strong>SQL</strong> provide the same benefits as procedures in a host<br />

language. That is, a common piece of code need only be written and maintained<br />

once and can be called from several programs.<br />

To create an external procedure or an <strong>SQL</strong> procedure, you can use the <strong>SQL</strong><br />

CREATE PROCEDURE statement. Or, you can use Operations Navigator.<br />

Defining an external procedure<br />

The CREATE PROCEDURE statement <strong>for</strong> an external procedure:<br />

v Names the procedure<br />

v Defines the parameters and their attributes<br />

© Copyright IBM Corp. 2000 117


Defining an <strong>SQL</strong> procedure<br />

v Gives other in<strong>for</strong>mation about the procedure which will the system uses when it<br />

calls the procedure.<br />

Consider the following example:<br />

EXEC <strong>SQL</strong> CREATE PROCEDURE P1<br />

(INOUT PARM1 CHAR(10))<br />

EXTERNAL NAME MYLIB.PROC1<br />

LANGUAGE C<br />

GENERAL WITH NULLS;<br />

This CREATE PROCEDURE statement:<br />

v Names the procedure P1<br />

v Defines one parameter which is used both as an input parameter and an output<br />

parameter. The parameter is a character field of length ten. Parameters can be<br />

defined to be type IN, OUT, or INOUT. The parameter type determines when<br />

the values <strong>for</strong> the parameters get passed to and from the procedure.<br />

v Defines the name of the program which corresponds to the procedure, which is<br />

PROC1 in MYLIB. MYLIB.PROC1 is the program which is called when the<br />

procedure is invoked on a CALL statement.<br />

v Indicates that the procedure P1 (program MYLIB.PROC1) is written in C. The<br />

language is important since it impacts the types of parameters that can be<br />

passed. It also affects how the parameters are passed to the procedure (<strong>for</strong><br />

example, <strong>for</strong> ILE C procedures, a NUL-terminator is passed on character,<br />

graphic, date, time, and timestamp parameters).<br />

v Defines the CALL type to be GENERAL WITH NULLS. This indicates that the<br />

parameter <strong>for</strong> the procedure can possibly contain the NULL value, and there<strong>for</strong>e<br />

would like an additional argument passed to the procedure on the CALL<br />

statement. The additional argument is an array of N short integers, where N is<br />

the number of parameters that are declared in the CREATE PROCEDURE<br />

statement. In this example, the array contains only one element since there is<br />

only parameter.<br />

It is important to note that it is not necessary to define a procedure in order to call<br />

it. However, if no procedure definition is found, either from a prior CREATE<br />

PROCEDURE or from a DECLARE PROCEDURE in this program, certain<br />

restrictions and assumptions are made when the procedure is invoked on the<br />

CALL statement. For example, the NULL indicator argument cannot be passed. See<br />

“Using Embedded CALL Statement where no procedure definition exists” on<br />

page 125 <strong>for</strong> an example of a CALL statement without a corresponding procedure<br />

definition.<br />

The CREATE PROCEDURE statement <strong>for</strong> <strong>SQL</strong> procedures:<br />

v Names the procedure<br />

v Defines the parameters and their attributes<br />

v Provides other in<strong>for</strong>mation about the procedure which will be used when the<br />

procedure is called<br />

v Defines the procedure body. The procedure body is the executable part of the<br />

procedure and is a single <strong>SQL</strong> statement.<br />

118 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


Consider the following simple example that takes as input an employee number<br />

and a rate and updates the employee’s salary:<br />

EXEC <strong>SQL</strong> CREATE PROCEDURE UPDATE_SALARY_1<br />

(IN EMPLOYEE_NUMBER CHAR(10),<br />

IN RATE DECIMAL(6,2))<br />

LANGUAGE <strong>SQL</strong> MODIFIES <strong>SQL</strong> DATA<br />

UPDATE CORPDATA.EMPLOYEE<br />

SET SALARY = SALARY * RATE<br />

WHERE EMPNO = EMPLOYEE_NUMBER;<br />

This CREATE PROCEDURE statement:<br />

v Names the procedure UPDATE_SALARY_1.<br />

v Defines parameter EMPLOYEE_NUMBER which is an input parameter and is a<br />

character data type of length 6 and parameter RATE which is an input<br />

parameter and is a decimal data type.<br />

v Indicates the procedure is an <strong>SQL</strong> procedure that modifies <strong>SQL</strong> data.<br />

v Defines the procedure body as a single UPDATE statement. When the procedure<br />

is called, the UPDATE statement is executed using the values passed <strong>for</strong><br />

EMPLOYEE_NUMBER and RATE.<br />

Instead of a single UPDATE statement, logic can be added to the <strong>SQL</strong> procedure<br />

using <strong>SQL</strong> control statements. <strong>SQL</strong> control statements consist of the following:<br />

v an assignment statement<br />

v a CALL statement<br />

v a C<strong>AS</strong>E statement<br />

v a compound statement<br />

v a FOR statement<br />

v an IF statement<br />

v a LOOP statement<br />

v a REPEAT statement<br />

v a WHILE statement<br />

The following example takes as input the employee number and a rating that was<br />

received on the last evaluation. The procedure uses a C<strong>AS</strong>E statement to determine<br />

the appropriate increase and bonus <strong>for</strong> the update:<br />

EXEC <strong>SQL</strong> CREATE PROCEDURE UPDATE_SALARY_2<br />

(IN EMPLOYEE_NUMBER CHAR(6),<br />

IN RATING INT)<br />

LANGUAGE <strong>SQL</strong> MODIFIES <strong>SQL</strong> DATA<br />

C<strong>AS</strong>E RATING<br />

WHEN 1 THEN<br />

UPDATE CORPDATA.EMPLOYEE<br />

SET SALARY = SALARY * 1.10,<br />

BONUS = 1000<br />

WHERE EMPNO = EMPLOYEE_NUMBER;<br />

WHEN 2 THEN<br />

UPDATE CORPDATA.EMPLOYEE<br />

SET SALARY = SALARY * 1.05,<br />

BONUS = 500<br />

WHERE EMPNO = EMPLOYEE_NUMBER;<br />

ELSE<br />

UPDATE CORPDATA.EMPLOYEE<br />

SET SALARY = SALARY * 1.03,<br />

BONUS = 0<br />

WHERE EMPNO = EMPLOYEE_NUMBER;<br />

END C<strong>AS</strong>E;<br />

Chapter 7. Stored Procedures 119


|<br />

This CREATE PROCEDURE statement:<br />

v Names the procedure UPDATE_SALARY_2.<br />

v Defines parameter EMPLOYEE_NUMBER which is an input parameter and is a<br />

character data type of length 6 and parameter RATING which is an input<br />

parameter and is an integer data type.<br />

v Indicates the procedure is an <strong>SQL</strong> procedure that modifies <strong>SQL</strong> data.<br />

v Defines the procedure body. When the procedure is called, input parameter<br />

RATING is checked and the appropriate update statement is executed.<br />

Multiple statements can be added to a procedure body by adding a compound<br />

statement. Within a compound statement, any number of <strong>SQL</strong> statements can be<br />

specified. In addition, <strong>SQL</strong> variables, cursors, and handlers can be declared.<br />

The following example takes as input the department number. It returns the total<br />

salary of all the employees in that department and the number of employees in<br />

that department who get a bonus.<br />

EXEC <strong>SQL</strong><br />

CREATE PROCEDURE RETURN_DEPT_SALARY<br />

(IN DEPT_NUMBER CHAR(3),<br />

OUT DEPT_SALARY DECIMAL(15,2),<br />

OUT DEPT_BONUS_CNT INT)<br />

LANGUAGE <strong>SQL</strong> READS <strong>SQL</strong> DATA<br />

P1: BEGIN<br />

DECLARE EMPLOYEE_SALARY DECIMAL(9,2);<br />

DECLARE EMPLOYEE_BONUS DECIMAL(9,2);<br />

DECLARE TOTAL_SALARY DECIMAL(15,2)DEFAULT 0<br />

DECLARE BONUS_CNT INT DEFAULT 0;<br />

DECLARE END_TABLE INT DEFAULT 0;<br />

DECLARE C1 CURSOR FOR<br />

SELECT SALARY, BONUS FROM CORPDATA.EMPLOYEE<br />

WHERE WORKDEPT = DEPT_NUMBER;<br />

DECLARE CONTINUE HANDLER FOR NOT FOUND<br />

SET END_TABLE = 1;<br />

DECLARE EXIT HANDLER FOR <strong>SQL</strong>EXCEPTION<br />

SET DEPT_SALARY = NULL;<br />

OPEN C1;<br />

FETCH C1 INTO EMPLOYEE_SALARY, EMPLOYEE_BONUS;<br />

WHILE END_TABLE = 0 DO<br />

SET TOTAL_SALARY = TOTAL_SALARY + EMPLOYEE_SALARY + EMPLOYEE_BONUS;<br />

IF EMPLOYEE_BONUS > 0 THEN<br />

SET BONUS_CNT = BONUS_CNT + 1;<br />

END IF;<br />

FETCH C1 INTO EMPLOYEE_SALARY, EMPLOYEE_BONUS;<br />

END WHILE;<br />

CLOSE C1;<br />

SET DEPT_SALARY = TOTAL_SALARY;<br />

SET DEPT_BONUS_CNT = BONUS_CNT;<br />

END P1;<br />

This CREATE PROCEDURE statement:<br />

v Names the procedure RETURN_DEPT_SALARY.<br />

v Defines parameter DEPT_NUMBER which is an input parameter and is a<br />

character data type of length 3, parameter DEPT_SALARY which is an output<br />

parameter and is a decimal data type, and parameter DEPT_BONUS_CNT which<br />

is an output parameter and is an integer data type.<br />

v Indicates the procedure is an <strong>SQL</strong> procedure that reads <strong>SQL</strong> data<br />

v Defines the procedure body.<br />

– Declares <strong>SQL</strong> variables EMPLOYEE_SALARY and TOTAL_SALARY as<br />

decimal fields.<br />

120 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


|<br />

|<br />

|<br />

|<br />

– Declares <strong>SQL</strong> variables BONUS_CNT and END_TABLE which are integers<br />

and are initialized to 0.<br />

– Declares cursor C1 that selects the columns from the employee table.<br />

– Declares a continue handler <strong>for</strong> NOT FOUND, which, when invoked sets<br />

variable END_TABLE to 1. This handler is invoked when the FETCH has no<br />

more rows to return. When the handler is invoked, <strong>SQL</strong>CODE and<br />

<strong>SQL</strong>STATE are reinitialized to 0.<br />

– Declares an exit handler <strong>for</strong> <strong>SQL</strong>EXCEPTION. If invoked, DEPT_SALARY is<br />

set to NULL and the processing of the compound statement is terminated.<br />

This handler is invoked if any errors occur, ie, the <strong>SQL</strong>STATE class is not ’00’,<br />

’01’ or ’02’. Since indicators are always passed to <strong>SQL</strong> procedures, the<br />

indicator value <strong>for</strong> DEPT_SALARY is −1 when the procedure returns. If this<br />

handler is invoked, <strong>SQL</strong>CODE and <strong>SQL</strong>STATE are reinitialized to 0.<br />

If the handler <strong>for</strong> <strong>SQL</strong>EXCEPTION is not specified and an error occurs that is<br />

not handled in another handler, execution of the compound statement is<br />

terminated and the error is returned in the <strong>SQL</strong>CA. Similar to indicators, the<br />

<strong>SQL</strong>CA is always returned from <strong>SQL</strong> procedures.<br />

– Includes an OPEN, FETCH, and CLOSE of cursor C1. If a CLOSE of the<br />

cursor is not specified, the cursor is closed at the end of the compound<br />

statement since SET RESULT SETS is not specified in the CREATE<br />

PROCEDURE statement.<br />

– Includes a WHILE statement which loops until the last record is fetched. For<br />

each row retrieved, the TOTAL_SALARY is incremented and, if the<br />

employee’s bonus is more than 0, the BONUS_CNT is incremented.<br />

– Returns DEPT_SALARY and DEPT_BONUS_CNT as output parameters.<br />

Compound statements can be made atomic so if an error occurs that is not<br />

expected, the statements within the atomic statement are rolled back. When a<br />

procedure that contains an atomic compound statement is called, the transaction<br />

must be at a commit boundary. If the compound statement is successful, the<br />

transaction is committed.<br />

The following example takes as input the department number. It ensures the<br />

EMPLOYEE_BONUS table exists, and inserts the name of all employees in the<br />

department who get a bonus. The procedure returns the total count of all<br />

employees who get a bonus.<br />

EXEC <strong>SQL</strong><br />

CREATE PROCEDURE CREATE_BONUS_TABLE<br />

(IN DEPT_NUMBER CHAR(3),<br />

INOUT CNT INT)<br />

LANGUAGE <strong>SQL</strong> MODIFIES <strong>SQL</strong> DATA<br />

CS1: BEGIN ATOMIC<br />

DECLARE NAME VARCHAR(30) DEFAULT NULL;<br />

DECLARE CONTINUE HANDLER FOR <strong>SQL</strong>STATE '42710'<br />

SELECT COUNT(*) INTO CNT<br />

FROM DATALIB.EMPLOYEE_BONUS;<br />

DECLARE CONTINUE HANDLER FOR <strong>SQL</strong>STATE '23505'<br />

SET CNT=CNT+1;<br />

DECLARE UNDO HANDLER FOR <strong>SQL</strong>EXCEPTION<br />

SET CNT = NULL;<br />

IF DEPT_NUMBER IS NOT NULL THEN<br />

CREATE TABLE DATALIB.EMPLOYEE_BONUS<br />

(FULLNAME VARCHAR(30),<br />

BONUS DECIMAL(10,2),<br />

PRIMARY KEY (FULLNAME));<br />

FOR_1:FOR V1 <strong>AS</strong> C1 CURSOR FOR<br />

SELECT FIRSTNME, MIDINIT, L<strong>AS</strong>TNAME, BONUS<br />

FROM CORPDATA.EMPLOYEE<br />

Chapter 7. Stored Procedures 121


|<br />

|<br />

|<br />

WHERE WORKDEPT = CREATE_BONUS_TABLE.DEPT_NUMBER;<br />

DO<br />

IF BONUS > 0 THEN<br />

SET NAME = FIRSTNME CONCAT ''CONCAT<br />

MIDINIT CONCAT ''CONCAT L<strong>AS</strong>TNAME;<br />

INSERT INTO DATALIB.EMPLOYEE_BONUS<br />

VALUES(CS1.NAME, FOR_1.BONUS);<br />

SET CNT=CNT+1;<br />

END IF;<br />

END FOR FOR_1;<br />

END IF;<br />

END CS1;<br />

This CREATE PROCEDURE statement:<br />

v Names the procedure CREATE_BONUS_TABLE.<br />

v Defines parameter DEPT_NUMBER which is an input parameter and is a<br />

character data type of length 3 and parameter CNT which is an input/output<br />

parameter and is an integer data type.<br />

v Indicates the procedure is an <strong>SQL</strong> procedure that modifies <strong>SQL</strong> data<br />

v Defines the procedure body.<br />

– Declares <strong>SQL</strong> variable NAME as varying character.<br />

– Declares a continue handler <strong>for</strong> <strong>SQL</strong>STATE 42710, table already exists. If the<br />

EMPLOYEE_BONUS table already exists, the handler is invoked and retrieves<br />

the number of records in the table. The <strong>SQL</strong>CODE and <strong>SQL</strong>STATE are reset to<br />

0 and processing continues with the FOR statement.<br />

– Declares a continue handler <strong>for</strong> <strong>SQL</strong>STATE 23505, duplicate key. If the<br />

procedure attempts to insert a name that already exists in the table, the<br />

handler is invoked and decrements CNT. Processing continues on the SET<br />

statement following the INSERT statement.<br />

– Declares an UNDO handler <strong>for</strong> <strong>SQL</strong>EXCEPTION. If invoked, the previous<br />

statements are rolled back, CNT is set to 0, and processing continues after the<br />

compound statement. In this case, since there is no statement following the<br />

compound statement, the procedure returns.<br />

– Uses the FOR statement to declare cursor C1 to read the records from the<br />

EMPLOYEE table. Within the FOR statement, the column names from the<br />

select list are used as <strong>SQL</strong> variables that contain the data from the row<br />

fetched. For each row, data from columns FIRSTNME, MIDINIT, and<br />

L<strong>AS</strong>TNAME are concatenated together with a blank in between and the result<br />

is put in <strong>SQL</strong> variable NAME. <strong>SQL</strong> variables NAME and BONUS are inserted<br />

into the EMPLOYEE_BONUS table. Because the data type of the select list<br />

items must be known when the procedure is created, the table specified in the<br />

FOR statement must exist when the procedure is created.<br />

An <strong>SQL</strong> variable name can be qualified with the label name of the FOR<br />

statement or compound statement in which it is defined. In the example,<br />

FOR_1.BONUS refers to the <strong>SQL</strong> variable that contains the value of column<br />

BONUS <strong>for</strong> each row selected. CS1.NAME is the variable NAME defined in<br />

the compound statement with the beginning label CS1. Parameter names can<br />

also be qualified with the procedure name.<br />

CREATE_BONUS_TABLE.DEPT_NUMBER is the DEPT_NUMBER parameter<br />

<strong>for</strong> the procedure CREATE_BONUS_TABLE. If unqualified <strong>SQL</strong> variable<br />

names are used in <strong>SQL</strong> statements where column names are also allowed, and<br />

the variable name is the same as a column name, the name will be used to<br />

refer to the column.<br />

122 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


|<br />

|<br />

|<br />

|<br />

|<br />

|<br />

You can also use dynamic <strong>SQL</strong> in an <strong>SQL</strong> procedure. The following example<br />

creates a table that contains all employees in a specific department. The<br />

department number is passed as input to the procedure and is concatenated to the<br />

table name.<br />

CREATE PROCEDURE CREATE_DEPT_TABLE (IN P_DEPT CHAR(3))<br />

LANGUAGE <strong>SQL</strong><br />

BEGIN<br />

DECLARE STMT CHAR(1000);<br />

DECLARE MESSAGE CHAR(20);<br />

DECLARE TABLE_NAME CHAR(30);<br />

DECLARE CONTINUE HANDLER FOR <strong>SQL</strong>EXCEPTION<br />

SET MESSAGE = 'ok';<br />

SET TABLE_NAME = 'CORPDATA.DEPT_' CONCAT P_DEPT CONCAT '_T';<br />

SET STMT = 'DROP TABLE ' CONCAT TABLE_NAME;<br />

PREPARE S1 FROM STMT;<br />

EXECUTE S1;<br />

SET STMT = 'CREATE TABLE ' CONCAT TABLE_NAME CONCAT<br />

'(EMPNO CHAR(6) NOT NULL,<br />

FIRSTNME VARCHAR(12) NOT NULL,<br />

MIDINIT CHAR(1) NOT NULL,<br />

L<strong>AS</strong>TNAME CHAR(15) NOT NULL,<br />

SALARY DECIMAL(9,2))';<br />

PREPARE S2 FROM STMT;<br />

EXECUTE S2;<br />

SET STMT = 'INSERT INTO ' CONCAT TABLE_NAME CONCAT<br />

'SELECT EMPNO, FIRSTNME, MIDINIT, L<strong>AS</strong>TNAME, SALARY<br />

FROM CORPDATA.EMPLOYEE<br />

WHERE WORKDEPT = ?';<br />

PREPARE S3 FROM STMT;<br />

EXECUTE S3 USING P_DEPT;<br />

END;<br />

This CREATE PROCEDURE statement:<br />

v Names the procedure CREATE_DEPT_TABLE<br />

v Defines parameter P_DEPT which is an input parameter and is a character data<br />

type of length 3.<br />

v Indicates the procedure is an <strong>SQL</strong> procedure.<br />

v Defines the procedure body.<br />

– Declares <strong>SQL</strong> variable STMT and an <strong>SQL</strong> variable TABLE_NAME as character.<br />

– Declares a CONTINUE handler. The procedure attempts to DROP the table in<br />

case it already exists. If the table does not exist, the first EXECUTE would fail.<br />

With the handler, processing will continue.<br />

– Sets variable TABLE_NAME to ’DEPT_’ followed by the characters passed in<br />

parameter P_DEPT, followed by ’_T’.<br />

– Sets variable STMT to the DROP statement, and prepares and executes the<br />

statement.<br />

– Sets variable STMT to the CREATE statement, and prepares and executes the<br />

statement.<br />

– Sets variable STMT to the INSERT statement, and prepares and executes the<br />

statement. A parameter marker is specified in the where clause. When the<br />

statement is executed, the variable P_DEPT is passed on the USING clause.<br />

If the procedure is called passing value ’D21’ <strong>for</strong> the department, table<br />

DEPT_D21_T is created and the table is initialized with all the employees that are<br />

in department ’D21’.<br />

Chapter 7. Stored Procedures 123


Invoking a stored procedure<br />

The CALL statement invokes a stored procedure. On the CALL statement, the<br />

name of the stored procedure and any arguments are specified. Arguments may be<br />

constants, special registers, or host variables. The external stored procedure<br />

specified in the CALL statement does not need to have a corresponding CREATE<br />

PROCEDURE statement. Programs created by <strong>SQL</strong> procedures can only be called<br />

by invoking the procedure name specified on the CREATE PROCEDURE<br />

statement. There are three types of CALL statements which need to be addressed<br />

since <strong>DB2</strong> <strong>SQL</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> has different rules <strong>for</strong> each type. They are:<br />

v Embedded or dynamic CALL statement where a procedure definition exists<br />

v Embedded CALL statement where no procedure definition exists<br />

v Dynamic CALL statement where no CREATE PROCEDURE exists<br />

Note: Dynamic here refers to:<br />

v A dynamically prepared and executed CALL statement<br />

v A CALL statement issued in an interactive environment (<strong>for</strong> example,<br />

through STR<strong>SQL</strong> or Query Manager)<br />

v A CALL statement executed in an EXECUTE IMMEDIATE statement.<br />

Following is a discussion of each type.<br />

Using CALL Statement where procedure definition exists<br />

This type of CALL statement gets all the in<strong>for</strong>mation about the procedure and the<br />

argument attributes from the CREATE PROCEDURE catalog definition. The<br />

following PL/I example shows a CALL statement which corresponds to the<br />

CREATE PROCEDURE statement shown.<br />

DCL HV1 CHAR(10);<br />

DCL IND1 FIXED BIN(15);<br />

:<br />

EXEC <strong>SQL</strong> CREATE P1 PROCEDURE<br />

(INOUT PARM1 CHAR(10))<br />

EXTERNAL NAME MYLIB.PROC1<br />

LANGUAGE C<br />

GENERAL WITH NULLS;<br />

:<br />

EXEC <strong>SQL</strong> CALL P1 (:HV1 :IND1);<br />

:<br />

When this CALL statement is invoked, a call to program MYLIB/PROC1 is made<br />

and two arguments are passed. Since the language of the program is ILE C, the<br />

first argument is a C NUL-terminated string eleven characters long containing the<br />

contents of host variable HV1. Note that on a call to an ILE C procedure, <strong>DB2</strong> <strong>SQL</strong><br />

<strong>for</strong> <strong>AS</strong>/<strong>400</strong> adds one character to the parameter declaration if the parameter is<br />

declared to be a character, graphic, date, time, or timestamp variable. The second<br />

argument is the indicator array. In this case, it is one short integer since there is<br />

only one parameter in the CREATE PROCEDURE statement. This argument<br />

contains the contents of indicator variable IND1 on entry to the procedure.<br />

Since the first parameter is declared as INOUT, <strong>SQL</strong> updates the host variable HV1<br />

and the indicator variable IND1 with the values returned from MYLIB.PROC1<br />

be<strong>for</strong>e returning to the user program.<br />

124 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


Note: The procedure names specified on the CREATE PROCEDURE and CALL<br />

statements must match EXACTLY in order <strong>for</strong> the link between the two to<br />

be made during the <strong>SQL</strong> precompile of the program.<br />

Note: For an embedded CALL statement where both a CREATE PROCEDURE and<br />

a DECLARE PROCEDURE statement exist, the DECLARE PROCEDURE<br />

statement will be used.<br />

Using Embedded CALL Statement where no procedure<br />

definition exists<br />

A static CALL statement without a corresponding CREATE PROCEDURE<br />

statement is processed with the following rules:<br />

v All host variable arguments are treated as INOUT type parameters.<br />

v The CALL type is GENERAL (no indicator argument is passed).<br />

v The program to call is determined based on the procedure name specified on the<br />

CALL, and, if necessary, the naming convention.<br />

v The language of the program to call is determined based on in<strong>for</strong>mation<br />

retrieved from the system about the program.<br />

Example: Embedded CALL Statement Where No Procedure<br />

Definition Exists<br />

The following is a PL/I example of an embedded CALL statement where no<br />

procedure definition exists:<br />

DCL HV2 CHAR(10);<br />

:<br />

EXEC <strong>SQL</strong> CALL P2 (:HV2);<br />

:<br />

When the CALL statement is invoked, <strong>DB2</strong> <strong>SQL</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> attempts to find the<br />

program based on standard <strong>SQL</strong> naming conventions. For the above example,<br />

assume that the naming option of *SYS (system naming) is used and that a<br />

DFTRDBCOL parameter was not specified on the CRT<strong>SQL</strong>PLI command. In this<br />

case, the library list is searched <strong>for</strong> a program named P2. Since the call type is<br />

GENERAL, no additional argument is passed to the program <strong>for</strong> indicator<br />

variables.<br />

Note: If an indicator variable is specified on the CALL statement and its value is<br />

less than zero when the CALL statement is executed, an error results<br />

because there is no way to pass the indicator to the procedure.<br />

Assuming program P2 is found in the library list, the contents of host variable<br />

HV2 are passed in to the program on the CALL and the argument returned from<br />

P2 is mapped back to the host variable after P2 has completed execution.<br />

Using Embedded CALL statement with an <strong>SQL</strong>DA<br />

In either type of embedded CALL (where a procedure definition may or may not<br />

exist), an <strong>SQL</strong>DA may be passed rather than a parameter list, as illustrated in the<br />

following C example. Assume that the stored procedure is expecting 2 parameters,<br />

the first of type SHORT INT and the second of type CHAR with a length of 4.<br />

Chapter 7. Stored Procedures 125


#define <strong>SQL</strong>DA_HV_ENTRIES 2<br />

#define SHORTINT 500<br />

#define NUL_TERM_CHAR 460<br />

exec sql include sqlca;<br />

exec sql include sqlda;<br />

...<br />

typedef struct sqlda Sqlda;<br />

typedef struct sqlda* Sqldap;<br />

...<br />

main()<br />

{<br />

Sqldap dap;<br />

short col1;<br />

char col2[4];<br />

int bc;<br />

dap = (Sqldap) malloc(bc=<strong>SQL</strong>D<strong>AS</strong>IZE(<strong>SQL</strong>DA_HV_ENTRIES));<br />

/* <strong>SQL</strong>D<strong>AS</strong>IZE is a macro defined in the sqlda include */<br />

col1 = 431;<br />

strcpy(col2,"abc");<br />

strncpy(dap->sqldaid,"<strong>SQL</strong>DA ",8);<br />

dap->sqldabc = bc; /* bc set in the malloc statement above */<br />

dap->sqln = <strong>SQL</strong>DA_HV_ENTRIES;<br />

dap->sqld = <strong>SQL</strong>DA_HV_ENTRIES;<br />

dap->sqlvar[0].sqltype = SHORTINT;<br />

dap->sqlvar[0].sqllen = 2;<br />

dap->sqlvar[0].sqldata = (char*) &col1;<br />

dap->sqlvar[0].sqlname.length = 0;<br />

dap->sqlvar[1].sqltype = NUL_TERM_CHAR;<br />

dap->sqlvar[1].sqllen = 4;<br />

dap->sqlvar[1].sqldata = col2;<br />

...<br />

EXEC <strong>SQL</strong> CALL P1 USING DESCRIPTOR :*dap;<br />

...<br />

}<br />

It should be noted that the name of the called procedure may also be stored in a<br />

host variable and the host variable used in the CALL statement, instead of the<br />

hard-coded procedure name. For example:<br />

...<br />

main()<br />

{<br />

char proc_name[15];<br />

...<br />

strcpy (proc_name, "MYLIB.P3");<br />

...<br />

EXEC <strong>SQL</strong> CALL :proc_name ...;<br />

...<br />

}<br />

In the above example, if MYLIB.P3 is expecting parameters, then either a<br />

parameter list or an <strong>SQL</strong>DA passed with the USING DESCRIPTOR clause may be<br />

used, as shown in the previous example.<br />

When a host variable containing the procedure name is used in the CALL<br />

statement and a CREATE PROCEDURE catalog definition exists, it will be used.<br />

The procedure name cannot be specified as a parameter marker.<br />

More examples <strong>for</strong> calling stored procedures may be found later in this chapter<br />

and also in the DATAB<strong>AS</strong>E 2 Advanced Database Functions book.<br />

126 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


Using Dynamic CALL Statement where no CREATE<br />

PROCEDURE exists<br />

The following rules pertain to the processing of a dynamic CALL statement when<br />

there is no CREATE PROCEDURE definition:<br />

v All arguments are treated as IN type parameters.<br />

v The CALL type is GENERAL (no indicator argument is passed).<br />

v The program to call is determined based on the procedure name specified on the<br />

CALL and the naming convention.<br />

v The language of the program to call is determined based on in<strong>for</strong>mation<br />

retrieved from the system about the program.<br />

Example: Dynamic CALL statement where no CREATE<br />

PROCEDURE exists<br />

The following is a C example of a dynamic CALL statement:<br />

char hv3[10],string[100];<br />

:<br />

strcpy(string,"CALL MYLIB.P3 ('P3 TEST')");<br />

EXEC <strong>SQL</strong> EXECUTE IMMEDIATE :string;<br />

:<br />

This example shows a dynamic CALL statement executed through an EXECUTE<br />

IMMEDIATE statement. The call is made to program MYLIB.P3 with one<br />

parameter passed as a character variable containing ’P3 TEST’.<br />

When executing a CALL statement and passing a constant, as in the previous<br />

example, the length of the expected argument in the program must be kept in<br />

mind. If program MYLIB.P3 expected an argument of only 5 characters, the last 2<br />

characters of the constant specified in the example would be lost to the program.<br />

Note: For this reason, it is always safer to use host variables on the CALL<br />

statement so that the attributes of the procedure can be matched exactly and<br />

so that characters are not lost. For dynamic <strong>SQL</strong>, host variables can be<br />

specified <strong>for</strong> CALL statement arguments if the PREPARE and EXECUTE<br />

statements are used to process it.<br />

For numeric constants passed on a CALL statement, the following rules apply:<br />

v All integer constants are passed as fullword binary integers.<br />

v All decimal constants are passed as packed decimal values. Precision and scale<br />

are determined based on the constant value. For instance, a value of 123.45 is<br />

passed as a packed decimal(5,2). Likewise, a value of 001.01 is also passed with<br />

a precision and scale of 5 and 2, respectively.<br />

v All floating point constants are passed as double-precision floating point.<br />

Special registers specified on a dynamic CALL statement are passed as follows:<br />

v CURRENT DATE<br />

Passed as a 10-byte character string in ISO <strong>for</strong>mat.<br />

v CURRENT TIME<br />

Passed as an 8-byte character string in ISO <strong>for</strong>mat.<br />

v CURRENT TIMESTAMP<br />

Passed as a 26-byte character string in IBM <strong>SQL</strong> <strong>for</strong>mat.<br />

Chapter 7. Stored Procedures 127


|<br />

|<br />

|<br />

v CURRENT TIMEZONE<br />

Passed as a packed decimal number with a precision of 6 and a scale of 0.<br />

v CURRENT SERVER<br />

Passed as an 18-byte varying length character string.<br />

v USER<br />

Passed as an 18-byte varying length character string.<br />

v CURRENT PATH<br />

Passed as a 558-byte varying character length character string.<br />

Parameter passing conventions <strong>for</strong> stored procedures<br />

The CALL statement can pass arguments to programs written in all supported host<br />

languages and REXX procedures. Each language supports different data types<br />

which are tailored to it. The <strong>SQL</strong> data type is contained in the leftmost column of<br />

the following table. Other columns in that row contain an indication of whether<br />

that data type is supported as a parameter type <strong>for</strong> a particular language. If the<br />

column contains a dash (-), the data type is not supported as a parameter type <strong>for</strong><br />

that language. A host variable declaration indicates that <strong>DB2</strong> <strong>SQL</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong><br />

supports this data type as a parameter in this language. The declaration indicates<br />

how host variables must be declared to be received and set properly by the<br />

procedure. When calling an <strong>SQL</strong> procedure, all <strong>SQL</strong> data types are supported so no<br />

column is provided in the table.<br />

Table 19. Data Types of Parameters<br />

COBOL <strong>for</strong> <strong>AS</strong>/<strong>400</strong> and<br />

<strong>SQL</strong> Data Type C and C++ CL<br />

ILE COBOL <strong>for</strong> <strong>AS</strong>/<strong>400</strong><br />

SMALLINT short - PIC S9(4) BINARY<br />

INTEGER long - PIC S9(9) BINARY<br />

BIGINT long long - PIC S9(18) BINARY Note:<br />

DECIMAL(p,s) decimal(p,s) TYPE(*DEC) LEN(p s)<br />

Only supported <strong>for</strong> ILE<br />

COBOL <strong>for</strong> <strong>AS</strong>/<strong>400</strong>.<br />

PIC S9(p-s)V9(s)<br />

PACKED-DECIMAL Note:<br />

Precision must not be<br />

greater than 18.<br />

NUMERIC(p,s) - - PIC S9(p-s)V9(s) DISPLAY<br />

SIGN LEADING<br />

SEPARATE Note: Precision<br />

must not be greater than<br />

18.<br />

REAL or FLOAT(p) float - COMP-1 Note: Only<br />

supported <strong>for</strong> ILE COBOL<br />

<strong>for</strong> <strong>AS</strong>/<strong>400</strong>.<br />

DOUBLE PRECISION or double - COMP-2 Note: Only<br />

FLOAT or FLOAT(p)<br />

supported <strong>for</strong> ILE COBOL<br />

<strong>for</strong> <strong>AS</strong>/<strong>400</strong>.<br />

CHARACTER(n) char ... [n+1] TYPE(*CHAR) LEN(n) PIC X(n)<br />

VARCHAR(n) char ... [n+1] - Varying-Length Character<br />

String (see COBOL chapter)<br />

Note: Only supported <strong>for</strong><br />

ILE COBOL <strong>for</strong> <strong>AS</strong>/<strong>400</strong>.<br />

128 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


|<br />

|<br />

Table 19. Data Types of Parameters (continued)<br />

<strong>SQL</strong> Data Type C and C++ CL<br />

VARCHAR(n) FOR BIT<br />

DATA<br />

VARCHAR structured <strong>for</strong>m<br />

(see C chapter)<br />

COBOL <strong>for</strong> <strong>AS</strong>/<strong>400</strong> and<br />

ILE COBOL <strong>for</strong> <strong>AS</strong>/<strong>400</strong><br />

- Varying-Length Character<br />

String (see COBOL chapter)<br />

Note: Only supported <strong>for</strong><br />

ILE COBOL <strong>for</strong> <strong>AS</strong>/<strong>400</strong>.<br />

GRAPHIC(n) wchar_t ... [n+1] - PIC G(n) DISPLAY-1 or PIC<br />

N(n) Note: Only<br />

supported <strong>for</strong> ILE COBOL<br />

<strong>for</strong> <strong>AS</strong>/<strong>400</strong>.<br />

VARGRAPHIC(n) VARGRAPHIC structured<br />

<strong>for</strong>m (see C chapter)<br />

- Varying-Length Graphic<br />

String (see COBOL chapter)<br />

Note: Only supported <strong>for</strong><br />

ILE COBOL <strong>for</strong> <strong>AS</strong>/<strong>400</strong>.<br />

DATE char ... [11] TYPE(*CHAR) LEN(10) PIC X(10)<br />

For ILE COBOL <strong>for</strong> <strong>AS</strong>/<strong>400</strong><br />

only, FORMAT DATE.<br />

TIME char ... [9] TYPE(*CHAR) LEN(8) PIC X(8)<br />

For ILE COBOL <strong>for</strong> <strong>AS</strong>/<strong>400</strong><br />

only, FORMAT TIME.<br />

TIMESTAMP char ... [27] TYPE(*CHAR) LEN(26) PIC X(26)<br />

For ILE COBOL <strong>for</strong> <strong>AS</strong>/<strong>400</strong><br />

only, FORMAT<br />

TIMESTAMP.<br />

Indicator Variable short - PIC S9(4) BINARY<br />

CLOB CLOB structured <strong>for</strong>m (see<br />

C chapter in <strong>SQL</strong><br />

<strong>Programming</strong> with Host<br />

Languages)<br />

BLOB BLOB structured <strong>for</strong>m (see<br />

C chapter in <strong>SQL</strong><br />

<strong>Programming</strong> with Host<br />

Languages)<br />

DBCLOB DBCLOB structured <strong>for</strong>m<br />

(see C chapter in <strong>SQL</strong><br />

<strong>Programming</strong> with Host<br />

Languages)<br />

- CLOB structured <strong>for</strong>m (see<br />

COBOL chapter in <strong>SQL</strong><br />

<strong>Programming</strong> with Host<br />

Languages). Note: only<br />

supported <strong>for</strong> ILE COBOL<br />

<strong>for</strong> <strong>AS</strong>/<strong>400</strong>.<br />

- BLOB structured <strong>for</strong>m (see<br />

COBOL chapter in <strong>SQL</strong><br />

<strong>Programming</strong> with Host<br />

Languages). Note: only<br />

supported <strong>for</strong> ILE COBOL<br />

<strong>for</strong> <strong>AS</strong>/<strong>400</strong>.<br />

- DBCLOB structured <strong>for</strong>m<br />

(see COBOL chapter in <strong>SQL</strong><br />

<strong>Programming</strong> with Host<br />

Languages). Note: only<br />

supported <strong>for</strong> ILE COBOL<br />

<strong>for</strong> <strong>AS</strong>/<strong>400</strong>.<br />

DataLink - - -<br />

Table 20. Data Types of Parameters<br />

Java Parameter Style Java Parameter Style<br />

<strong>SQL</strong> Data Type FORTRAN<br />

JAVA<br />

<strong>DB2</strong>GENERAL PL/I<br />

SMALLINT INTEGER*2 short short FIXED BIN(15)<br />

INTEGER INTEGER*4 int int FIXED BIN(31)<br />

BIGINT - long long -<br />

DECIMAL(p,s) - BigDecimal BigDecimal FIXED DEC(p,s)<br />

Chapter 7. Stored Procedures 129


|<br />

|<br />

|<br />

|<br />

|<br />

|<br />

|<br />

|<br />

|<br />

|<br />

Table 20. Data Types of Parameters (continued)<br />

Java Parameter Style Java Parameter Style<br />

<strong>SQL</strong> Data Type FORTRAN<br />

JAVA<br />

<strong>DB2</strong>GENERAL PL/I<br />

NUMERIC(p,s) - BigDecimal BigDecimal -<br />

REAL or FLOAT(p) REAL*4 float float FLOAT BIN(p)<br />

DOUBLE PRECISION<br />

or FLOAT or<br />

FLOAT(p)<br />

REAL*8 double double FLOAT BIN(p)<br />

CHARACTER(n) CHARACTER*n String String CHAR(n)<br />

VARCHAR(n) - String String CHAR(n) VAR<br />

VARCHAR(n) FOR<br />

BIT DATA<br />

- - com.ibm.db2.app.Blob CHAR(n) VAR<br />

GRAPHIC(n) - String String -<br />

VARGRAPHIC(n) - String String -<br />

DATE CHARACTER*10 Date String CHAR(10)<br />

TIME CHARACTER*8 Time String CHAR(8)<br />

TIMESTAMP CHARACTER*26 Timestamp String CHAR(26)<br />

Indicator Variable INTEGER*2 - - FIXED BIN(15)<br />

CLOB - - com.ibm.db2.app.Clob CLOB structured<br />

<strong>for</strong>m (see PL/I<br />

chapter in <strong>SQL</strong><br />

<strong>Programming</strong> with<br />

Host Languages)<br />

BLOB - - com.ibm.db2.app.Blob BLOB structured <strong>for</strong>m<br />

(see PL/I chapter in<br />

<strong>SQL</strong> <strong>Programming</strong><br />

with Host Languages)<br />

DBCLOB - - com.ibm.db2.app.Clob DBCLOB structured<br />

<strong>for</strong>m (see PL/I<br />

chapter in <strong>SQL</strong><br />

<strong>Programming</strong> with<br />

Host Languages)<br />

DataLink - - - -<br />

Table 21. Data Types of Parameters<br />

<strong>SQL</strong> Data Type REXX RPG ILE RPG<br />

SMALLINT - Data structure that contains a Data specification. B in position<br />

single sub-field. B in position 43, 40, length must be


Table 21. Data Types of Parameters (continued)<br />

<strong>SQL</strong> Data Type REXX RPG ILE RPG<br />

| INTEGER numeric string with Data structure that contains a Data specification. B in position<br />

|<br />

no decimal (and an single sub-field. B in position 43, 40, length must be =05, and 00 in positions 41-42<br />

|<br />

position 52 of the sub-field of the sub-field specification.<br />

|<br />

specification.<br />

or<br />

|<br />

Data specification. I in position<br />

|<br />

40, length must be 10, and 00 in<br />

|<br />

positions 41-42 of the sub-field<br />

|<br />

specification.<br />

| BIGINT - - Data specification. I in position<br />

|<br />

40, length must be 20, and 00 in<br />

|<br />

positions 41-42 of the sub-field<br />

|<br />

specification.<br />

DECIMAL(p,s) numeric string with a Data structure that contains a Data specification. P in position<br />

decimal (and an single sub-field. P in position 43 40 and 00 through 31 in positions<br />

optional leading sign) and 0 through 9 in position 52 of 41-42 of the sub-field<br />

the sub-field specification. or A<br />

numeric input field or calculation<br />

result field.<br />

specification.<br />

NUMERIC(p,s) - Data structure that contains a<br />

single sub-field. Blank in<br />

position 43 and 0 through 9 in<br />

position 52 of the sub-field<br />

specification.<br />

REAL or FLOAT(p) string with digits,<br />

then an E, (then an<br />

optional sign), then<br />

digits<br />

DOUBLE PRECISION<br />

or FLOAT or<br />

FLOAT(p)<br />

string with digits,<br />

then an E, (then an<br />

optional sign), then<br />

digits<br />

CHARACTER(n) string with n<br />

characters within two<br />

apostrophes<br />

VARCHAR(n) string with n<br />

characters within two<br />

apostrophes<br />

VARCHAR(n) FOR<br />

BIT DATA<br />

string with n<br />

characters within two<br />

apostrophes<br />

GRAPHIC(n) string starting with<br />

G’, then n double<br />

byte characters, then ’<br />

Data specification. S in position<br />

40, or Blank in position 40 and<br />

00 through 31 in position 41-42<br />

of the sub-field specification.<br />

- Data specification. F in position<br />

40, length must be 4.<br />

- Data specification. F in position<br />

40, length must be 8.<br />

Data structure field without<br />

sub-fields or data structure that<br />

contains a single sub-field. Blank<br />

in position 43 and 52 of the<br />

sub-field specification. or A<br />

character input field or<br />

calculation result field.<br />

Data specification. A in position<br />

40, or Blank in position 40 and<br />

41-42 of the sub-field<br />

specification.<br />

- Data specification. A in position<br />

40, or Blank in position 40 and<br />

41-42 of the sub-field<br />

specification and the keyword<br />

VARYING in positions 44-80.<br />

- Data specification. A in position<br />

40, or Blank in position 40 and<br />

41-42 of the sub-field<br />

specification and the keyword<br />

VARYING in positions 44-80.<br />

- Data specification. G in position<br />

40 of the sub-field specification.<br />

Chapter 7. Stored Procedures 131


|<br />

Table 21. Data Types of Parameters (continued)<br />

<strong>SQL</strong> Data Type REXX RPG ILE RPG<br />

VARGRAPHIC(n) string starting with - Data specification. G in position<br />

G’, then n double<br />

40 of the sub-field specification<br />

byte characters, then ’<br />

and the keyword VARYING in<br />

positions 44-80.<br />

DATE string with 10 Data structure field without Data specification. D in position<br />

characters within two sub-fields or data structure that 40 of the sub-field specification.<br />

apostrophes<br />

contains a single sub-field. Blank<br />

in position 43 and 52 of the<br />

sub-field specification. Length is<br />

10. or A character input field or<br />

calculation result field.<br />

DATFMT(*ISO) in position 44-80.<br />

TIME string with 8<br />

characters within two<br />

apostrophes<br />

TIMESTAMP string with 26<br />

characters within two<br />

apostrophes<br />

Indicator Variable numeric string with<br />

no decimal (and an<br />

optional leading sign).<br />

Data structure field without<br />

sub-fields or data structure that<br />

contains a single sub-field. Blank<br />

in position 43 and 52 of the<br />

sub-field specification. Length is<br />

8. or A character input field or<br />

calculation result field.<br />

Data structure field without<br />

sub-fields or data structure that<br />

contains a single sub-field. Blank<br />

in position 43 and 52 of the<br />

sub-field specification. Length is<br />

26. or A character input field or<br />

calculation result field.<br />

Data structure that contains a<br />

single sub-field. B in position 43,<br />

length must be 2, and 0 in<br />

position 52 of the sub-field<br />

specification.<br />

Data specification. T in position<br />

40 of the sub-field specification.<br />

TIMFMT(*ISO) in position 44-80.<br />

Data specification. Z in position<br />

40 of the sub-field specification.<br />

Data specification. B in position<br />

40, length must be


To indicate that an associated host variable contains the null value, the indicator<br />

variable, which is a two-byte integer, is set to a negative value. A CALL statement<br />

with indicator variables is processed as follows:<br />

v If the indicator variable is negative, this denotes the null value. A default value<br />

is passed <strong>for</strong> the associated host variable on the CALL and the indicator variable<br />

is passed unchanged.<br />

v If the indicator variable is not negative, this denotes that the host variable<br />

contains a non-null value. In this case, the host variable and the indicator<br />

variable are passed unchanged.<br />

Note that these rules of processing are the same <strong>for</strong> input parameters to the<br />

procedure as well as output parameters returned from the procedure. When<br />

indicator variables are used with stored procedures, the correct method of coding<br />

their handling is to check the value of the indicator variable first be<strong>for</strong>e using the<br />

associated host variable.<br />

The following example illustrates the handling of indicator variables in CALL<br />

statements. Notice that the logic checks the value of the indicator variable be<strong>for</strong>e<br />

using the associated variable. Also note the method that the indicator variables are<br />

passed into procedure PROC1 (as a third argument consisting of an array of<br />

two-byte values).<br />

Assume a procedure was defined as follows:<br />

CREATE PROCEDURE PROC1<br />

(INOUT DECIMALOUT DECIMAL(7,2), INOUT DECOUT2 DECIMAL(7,2))<br />

EXTERNAL NAME LIB1.PROC1 LANGUAGE RPGLE<br />

GENERAL WITH NULLS)<br />

Chapter 7. Stored Procedures 133


++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++<br />

Program CRPG<br />

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++<br />

D INOUT1 S 7P 2<br />

D INOUT1IND S 4B 0<br />

D INOUT2 S 7P 2<br />

D INOUT2IND S 4B 0<br />

C EVAL INOUT1 = 1<br />

C EVAL INOUT1IND = 0<br />

C EVAL INOUT2 = 1<br />

C EVAL INOUT2IND = -2<br />

C/EXEC <strong>SQL</strong> CALL PROC1 (:INOUT1 :INOUT1IND , :INOUT2<br />

C+ :INOUT2IND)<br />

C/END-EXEC<br />

C EVAL INOUT1 = 1<br />

C EVAL INOUT1IND = 0<br />

C EVAL INOUT2 = 1<br />

C EVAL INOUT2IND = -2<br />

C/EXEC <strong>SQL</strong> CALL PROC1 (:INOUT1 :INOUT1IND , :INOUT2<br />

C+ :INOUT2IND)<br />

C/END-EXEC<br />

C INOUT1IND IFLT 0<br />

C* :<br />

C* HANDLE NULL INDICATOR<br />

C* :<br />

C ELSE<br />

C* :<br />

C* INOUT1 CONTAINS VALID DATA<br />

C* :<br />

C ENDIF<br />

C* :<br />

C* HANDLE ALL OTHER PARAMETERS<br />

C* IN A SIMILAR F<strong>AS</strong>HION<br />

C* :<br />

C RETURN<br />

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++<br />

End of PROGRAM CRPG<br />

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++<br />

Figure 3. Handling of Indicator Variables in CALL Statements (Part 1 of 2)<br />

134 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++<br />

Program PROC1<br />

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++<br />

D INOUTP S 7P 2<br />

D INOUTP2 S 7P 2<br />

D NULLARRAY S 4B 0 DIM(2)<br />

C *ENTRY PLIST<br />

C PARM INOUTP<br />

C PARM INOUTP2<br />

C PARM NULLARRAY<br />

C NULLARRAY(1) IFLT 0<br />

C* :<br />

C* INOUTP DOES NOT CONTAIN MEANINGFUL DATA<br />

C*<br />

C ELSE<br />

C* :<br />

C* INOUTP CONTAINS MEANINGFUL DATA<br />

C* :<br />

C ENDIF<br />

C* PROCESS ALL REMAINING VARIABLES<br />

C*<br />

C* BEFORE RETURNING, SET OUTPUT VALUE FOR FIRST<br />

C* PARAMETER AND SET THE INDICATOR TO A NON-NEGATIV<br />

C* VALUE SO THAT THE DATA IS RETURNED TO THE CALLING<br />

C* PROGRAM<br />

C*<br />

C EVAL INOUTP2 = 20.5<br />

C EVAL NULLARRAY(2) = 0<br />

C*<br />

C* INDICATE THAT THE SECOND PARAMETER IS TO CONTAIN<br />

C* THE NULL VALUE UPON RETURN. THERE IS NO POINT<br />

C* IN SETTING THE VALUE IN INOUTP SINCE IT WON'T BE<br />

C* P<strong>AS</strong>SED BACK TO THE CALLER.<br />

C EVAL NULLARRAY(1) = -5<br />

C RETURN<br />

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++<br />

End of PROGRAM PROC1<br />

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++<br />

Figure 3. Handling of Indicator Variables in CALL Statements (Part 2 of 2)<br />

Returning a completion status to the calling program<br />

One method of returning a status to the <strong>SQL</strong> program issuing the CALL statement<br />

is to code an extra INOUT type parameter and set it prior to returning from the<br />

procedure. When the procedure being called is an existing program, this is not<br />

always possible.<br />

Another method of returning a status to the <strong>SQL</strong> program issuing the CALL<br />

statement is to send an escape message to the calling program (operating system<br />

program QSQCALL) which invokes the procedure. The calling program that<br />

invokes the procedure is QSQCALL. Each language has methods <strong>for</strong> signalling<br />

conditions and sending messages. Refer to the respective language reference to<br />

determine the proper way to signal a message. When the message is signalled,<br />

QSQCALL turns the error into <strong>SQL</strong>CODE/<strong>SQL</strong>STATE -443/38501.<br />

Chapter 7. Stored Procedures 135


Examples of CALL statements<br />

These examples show how the arguments of the CALL statement are passed to the<br />

procedure <strong>for</strong> several languages. They also show how to receive the arguments<br />

into local variables in the procedure.<br />

The first example shows the calling ILE C program that uses the CREATE<br />

PROCEDURE definitions to call the P1 and P2 procedures. Procedure P1 is written<br />

in C and has 10 parameters. Procedure P2 is written in PL/I and also has 10<br />

parameters.<br />

Assume two procedures are defined as follows:<br />

EXEC <strong>SQL</strong> CREATE PROCEDURE P1 (INOUT PARM1 CHAR(10),<br />

INOUT PARM2 INTEGER,<br />

INOUT PARM3 SMALLINT,<br />

INOUT PARM4 FLOAT(22),<br />

INOUT PARM5 FLOAT(53),<br />

INOUT PARM6 DECIMAL(10,5),<br />

INOUT PARM7 VARCHAR(10),<br />

INOUT PARM8 DATE,<br />

INOUT PARM9 TIME,<br />

INOUT PARM10 TIMESTAMP)<br />

EXTERNAL NAME TEST12.CALLPROC2<br />

LANGUAGE C GENERAL WITH NULLS<br />

EXEC <strong>SQL</strong> CREATE PROCEDURE P2 (INOUT PARM1 CHAR(10),<br />

INOUT PARM2 INTEGER,<br />

INOUT PARM3 SMALLINT,<br />

INOUT PARM4 FLOAT(22),<br />

INOUT PARM5 FLOAT(53),<br />

INOUT PARM6 DECIMAL(10,5),<br />

INOUT PARM7 VARCHAR(10),<br />

INOUT PARM8 DATE,<br />

INOUT PARM9 TIME,<br />

INOUT PARM10 TIMESTAMP)<br />

EXTERNAL NAME TEST12.CALLPROC<br />

LANGUAGE PLI GENERAL WITH NULLS<br />

136 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


Example 1: ILE C and PL/I procedures called from ILE C<br />

applications<br />

/**************************************************************/<br />

/*********** START OF <strong>SQL</strong> C Application ***********************/<br />

#include <br />

#include <br />

#include <br />

main()<br />

{<br />

EXEC <strong>SQL</strong> INCLUDE <strong>SQL</strong>CA;<br />

char PARM1[10];<br />

signed long int PARM2;<br />

signed short int PARM3;<br />

float PARM4;<br />

double PARM5;<br />

decimal(10,5) PARM6;<br />

struct { signed short int parm7l;<br />

char parm7c[10];<br />

} PARM7;<br />

char PARM8[10]; /* FOR DATE */<br />

char PARM9[8]; /* FOR TIME */<br />

char PARM10[26]; /* FOR TIMESTAMP */<br />

Figure 4. Sample of CREATE PROCEDURE and CALL (Part 1 of 2)<br />

Chapter 7. Stored Procedures 137


*******************************************************/<br />

/* Initialize variables <strong>for</strong> the call to the procedures */<br />

/*******************************************************/<br />

strcpy(PARM1,"PARM1");<br />

PARM2 = 7000;<br />

PARM3 = -1;<br />

PARM4 = 1.2;<br />

PARM5 = 1.0;<br />

PARM6 = 10.555;<br />

PARM7.parm7l = 5;<br />

strcpy(PARM7.parm7c,"PARM7");<br />

strncpy(PARM8,"1994-12-31",10); /* FOR DATE */<br />

strncpy(PARM9,"12.00.00",8); /* FOR TIME */<br />

strncpy(PARM10,"1994-12-31-12.00.00.000000",26);<br />

/* FOR TIMESTAMP */<br />

/***********************************************/<br />

/* Call the C procedure */<br />

/* */<br />

/* */<br />

/***********************************************/<br />

EXEC <strong>SQL</strong> CALL P1 (:PARM1, :PARM2, :PARM3,<br />

:PARM4, :PARM5, :PARM6,<br />

:PARM7, :PARM8, :PARM9,<br />

:PARM10 );<br />

if (strncmp(<strong>SQL</strong>STATE,"00000",5))<br />

{<br />

/* Handle error or warning returned on CALL statement */<br />

}<br />

/* Process return values from the CALL. */<br />

:<br />

/***********************************************/<br />

/* Call the PLI procedure */<br />

/* */<br />

/* */<br />

/***********************************************/<br />

/* Reset the host variables prior to making the CALL */<br />

/* */<br />

:<br />

EXEC <strong>SQL</strong> CALL P2 (:PARM1, :PARM2, :PARM3,<br />

:PARM4, :PARM5, :PARM6,<br />

:PARM7, :PARM8, :PARM9,<br />

:PARM10 );<br />

if (strncmp(<strong>SQL</strong>STATE,"00000",5))<br />

{<br />

/* Handle error or warning returned on CALL statement */<br />

}<br />

/* Process return values from the CALL. */<br />

:<br />

}<br />

/******** END OF C APPLICATION **********************************/<br />

/****************************************************************/<br />

Figure 4. Sample of CREATE PROCEDURE and CALL (Part 2 of 2)<br />

138 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


******** START OF C PROCEDURE P1 *******************************/<br />

/* PROGRAM TEST12/CALLPROC2 */<br />

/****************************************************************/<br />

#include <br />

#include <br />

#include <br />

main(argc,argv)<br />

int argc;<br />

char *argv[];<br />

{<br />

char parm1[11];<br />

long int parm2;<br />

short int parm3,i,j,*ind,ind1,ind2,ind3,ind4,ind5,ind6,ind7,<br />

ind8,ind9,ind10;<br />

float parm4;<br />

double parm5;<br />

decimal(10,5) parm6;<br />

char parm7[11];<br />

char parm8[10];<br />

char parm9[8];<br />

char parm10[26];<br />

/* *********************************************************/<br />

/* Receive the parameters into the local variables - */<br />

/* Character, date, time, and timestamp are passed as */<br />

/* NUL terminated strings - cast the argument vector to */<br />

/* the proper data type <strong>for</strong> each variable. Note that */<br />

/* the argument vector could be used directly instead of */<br />

/* copying the parameters into local variables - the copy */<br />

/* is done here just to illustrate the method. */<br />

/* *********************************************************/<br />

/* Copy 10 byte character string into local variable */<br />

strcpy(parm1,argv[1]);<br />

/* Copy 4 byte integer into local variable */<br />

parm2 = *(int *) argv[2];<br />

/* Copy 2 byte integer into local variable */<br />

parm3 = *(short int *) argv[3];<br />

/* Copy floating point number into local variable */<br />

parm4 = *(float *) argv[4];<br />

/* Copy double precision number into local variable */<br />

parm5 = *(double *) argv[5];<br />

/* Copy decimal number into local variable */<br />

parm6 = *(decimal(10,5) *) argv[6];<br />

Figure 5. Sample Procedure P1 (Part 1 of 2)<br />

Chapter 7. Stored Procedures 139


**********************************************************/<br />

/* Copy NUL terminated string into local variable. */<br />

/* Note that the parameter in the CREATE PROCEDURE was */<br />

/* declared as varying length character. For C, varying */<br />

/* length are passed as NUL terminated strings unless */<br />

/* FOR BIT DATA is specified in the CREATE PROCEDURE */<br />

/**********************************************************/<br />

strcpy(parm7,argv[7]);<br />

/**********************************************************/<br />

/* Copy date into local variable. */<br />

/* Note that date and time variables are always passed in */<br />

/* ISO <strong>for</strong>mat so that the lengths of the strings are */<br />

/* known. strcpy would work here just as well. */<br />

/**********************************************************/<br />

strncpy(parm8,argv[8],10);<br />

/* Copy time into local variable */<br />

strncpy(parm9,argv[9],8);<br />

/**********************************************************/<br />

/* Copy timestamp into local variable. */<br />

/* IBM <strong>SQL</strong> timestamp <strong>for</strong>mat is always passed so the length*/<br />

/* of the string is known. */<br />

/**********************************************************/<br />

strncpy(parm10,argv[10],26);<br />

/**********************************************************/<br />

/* The indicator array is passed as an array of short */<br />

/* integers. There is one entry <strong>for</strong> each parameter passed */<br />

/* on the CREATE PROCEDURE (10 <strong>for</strong> this example). */<br />

/* Below is one way to set each indicator into separate */<br />

/* variables. */<br />

/**********************************************************/<br />

ind = (short int *) argv[11];<br />

ind1 = *(ind++);<br />

ind2 = *(ind++);<br />

ind3 = *(ind++);<br />

ind4 = *(ind++);<br />

ind5 = *(ind++);<br />

ind6 = *(ind++);<br />

ind7 = *(ind++);<br />

ind8 = *(ind++);<br />

ind9 = *(ind++);<br />

ind10 = *(ind++);<br />

:<br />

/* Per<strong>for</strong>m any additional processing here */<br />

:<br />

return;<br />

}<br />

/******** END OF C PROCEDURE P1 *******************************/<br />

Figure 5. Sample Procedure P1 (Part 2 of 2)<br />

140 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


******** START OF PL/I PROCEDURE P2 **************************/<br />

/******** PROGRAM TEST12/CALLPROC *****************************/<br />

/**************************************************************/<br />

CALLPROC :PROC(PARM1,PARM2,PARM3,PARM4,PARM5,PARM6,PARM7,<br />

PARM8,PARM9,PARM10,PARM11);<br />

DCL SYSPRINT FILE STREAM OUTPUT EXTERNAL;<br />

OPEN FILE(SYSPRINT);<br />

DCL PARM1 CHAR(10);<br />

DCL PARM2 FIXED BIN(31);<br />

DCL PARM3 FIXED BIN(15);<br />

DCL PARM4 BIN FLOAT(22);<br />

DCL PARM5 BIN FLOAT(53);<br />

DCL PARM6 FIXED DEC(10,5);<br />

DCL PARM7 CHARACTER(10) VARYING;<br />

DCL PARM8 CHAR(10); /* FOR DATE */<br />

DCL PARM9 CHAR(8); /* FOR TIME */<br />

DCL PARM10 CHAR(26); /* FOR TIMESTAMP */<br />

DCL PARM11(10) FIXED BIN(15); /* Indicators */<br />

/* PERFORM LOGIC - Variables can be set to other values <strong>for</strong> */<br />

/* return to the calling program. */<br />

:<br />

END CALLPROC;<br />

Figure 6. Sample Procedure P2<br />

The next example shows a REXX procedure called from an ILE C program.<br />

Assume a procedure is defined as follows:<br />

EXEC <strong>SQL</strong> CREATE PROCEDURE REXXPROC<br />

(IN PARM1 CHARACTER(20),<br />

IN PARM2 INTEGER,<br />

IN PARM3 DECIMAL(10,5),<br />

IN PARM4 DOUBLE PRECISION,<br />

IN PARM5 VARCHAR(10),<br />

IN PARM6 GRAPHIC(4),<br />

IN PARM7 VARGRAPHIC(10),<br />

IN PARM8 DATE,<br />

IN PARM9 TIME,<br />

IN PARM10 TIMESTAMP)<br />

EXTERNAL NAME 'TEST.CALLSRC(CALLREXX)'<br />

LANGUAGE REXX GENERAL WITH NULLS<br />

Chapter 7. Stored Procedures 141


Example 2. Sample REXX Procedure Called From C Application<br />

/**************************************************************/<br />

/*********** START OF <strong>SQL</strong> C Application ***********************/<br />

#include <br />

#include <br />

#include <br />

#include <br />

/*-----------------------------------------------------------*/<br />

exec sql include sqlca;<br />

exec sql include sqlda;<br />

/* ***********************************************************/<br />

/* Declare host variable <strong>for</strong> the CALL statement */<br />

/* ***********************************************************/<br />

char parm1[20];<br />

signed long int parm2;<br />

decimal(10,5) parm3;<br />

double parm4;<br />

struct { short dlen;<br />

char dat[10];<br />

} parm5;<br />

wchar_t parm6[4] = { 0xC1C1, 0xC2C2, 0xC3C3, 0x0000 };<br />

struct { short dlen;<br />

wchar_t dat[10];<br />

} parm7 = {0x0009, 0xE2E2,0xE3E3,0xE4E4, 0xE5E5, 0xE6E6,<br />

0xE7E7, 0xE8E8, 0xE9E9, 0xC1C1, 0x0000 };<br />

char parm8[10];<br />

char parm9[8];<br />

char parm10[26];<br />

main()<br />

{<br />

Figure 7. Sample REXX Procedure Called From C Application (Part 1 of 4)<br />

142 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


}<br />

/* *************************************************************/<br />

/* Call the procedure - on return from the CALL statement the */<br />

/* <strong>SQL</strong>CODE should be 0. If the <strong>SQL</strong>CODE is non-zero, */<br />

/* the procedure detected an error. */<br />

/* *************************************************************/<br />

strcpy(parm1,"TestingREXX");<br />

parm2 = 12345;<br />

parm3 = 5.5;<br />

parm4 = 3e3;<br />

parm5.dlen = 5;<br />

strcpy(parm5.dat,"parm6");<br />

strcpy(parm8,"1994-01-01");<br />

strcpy(parm9,"13.01.00");<br />

strcpy(parm10,"1994-01-01-13.01.00.000000");<br />

EXEC <strong>SQL</strong> CALL REXXPROC (:parm1, :parm2,<br />

:parm3,:parm4,<br />

:parm5, :parm6,<br />

:parm7,<br />

:parm8, :parm9,<br />

:parm10);<br />

if (strncpy(<strong>SQL</strong>STATE,"00000",5))<br />

{<br />

/* handle error or warning returned on CALL */<br />

:<br />

}<br />

:<br />

/****** END OF <strong>SQL</strong> C APPLICATION ************************************/<br />

/**********************************************************************/<br />

Figure 7. Sample REXX Procedure Called From C Application (Part 2 of 4)<br />

Chapter 7. Stored Procedures 143


**********************************************************************/<br />

/****** START OF REXX MEMBER TEST/CALLSRC CALLREXX ********************/<br />

/**********************************************************************/<br />

/* REXX source member TEST/CALLSRC CALLREXX */<br />

/* Note the extra parameter being passed <strong>for</strong> the indicator*/<br />

/* array. */<br />

/* */<br />

/* ACCEPT THE FOLLOWING INPUT VARIABLES SET TO THE */<br />

/* SPECIFIED VALUES : */<br />

/* AR1 CHAR(20) = 'TestingREXX' */<br />

/* AR2 INTEGER = 12345 */<br />

/* AR3 DECIMAL(10,5) = 5.5 */<br />

/* AR4 DOUBLE PRECISION = 3e3 */<br />

/* AR5 VARCHAR(10) = 'parm6' */<br />

/* AR6 GRAPHIC = G'C1C1C2C2C3C3' */<br />

/* AR7 VARGRAPHIC = */<br />

/* G'E2E2E3E3E4E4E5E5E6E6E7E7E8E8E9E9EAEA' */<br />

/* AR8 DATE = '1994-01-01' */<br />

/* AR9 TIME = '13.01.00' */<br />

/* AR10 TIMESTAMP = */<br />

/* '1994-01-01-13.01.00.000000' */<br />

/* AR11 INDICATOR ARRAY = +0+0+0+0+0+0+0+0+0+0 */<br />

/**********************************************************/<br />

/* Parse the arguments into individual parameters */<br />

/**********************************************************/<br />

parse arg ar1 ar2 ar3 ar4 ar5 ar6 ar7 ar8 ar9 ar10 ar11<br />

/**********************************************************/<br />

/* Verify that the values are as expected */<br />

/**********************************************************/<br />

if ar1"'TestingREXX'" then signal ar1tag<br />

if ar212345 then signal ar2tag<br />

if ar35.5 then signal ar3tag<br />

if ar43e3 then signal ar4tag<br />

if ar5"'parm6'" then signal ar5tag<br />

if ar6 "G'AABBCC'" then signal ar6tag<br />

if ar7 "G'SSTTUUVVWWXXYYZZAA'" then ,<br />

signal ar7tag<br />

if ar8 "'1994-01-01'" then signal ar8tag<br />

if ar9 "'13.01.00'" then signal ar9tag<br />

if ar10 "'1994-01-01-13.01.00.000000'" then signal ar10tag<br />

if ar11 "+0+0+0+0+0+0+0+0+0+0" then signal ar11tag<br />

Figure 7. Sample REXX Procedure Called From C Application (Part 3 of 4)<br />

144 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


|<br />

|<br />

|<br />

/************************************************************/<br />

/* Per<strong>for</strong>m other processing as necessary .. */<br />

/************************************************************/<br />

:<br />

/************************************************************/<br />

/* Indicate the call was successful by exiting with a */<br />

/* return code of 0 */<br />

/************************************************************/<br />

exit(0)<br />

ar1tag:<br />

say "ar1 did not match" ar1<br />

exit(1)<br />

ar2tag:<br />

say "ar2 did not match" ar2<br />

exit(1)<br />

:<br />

:<br />

/************ END OF REXX MEMBER **********************************/<br />

Figure 7. Sample REXX Procedure Called From C Application (Part 4 of 4)<br />

Considerations <strong>for</strong> stored procedures that are written in Java<br />

When using Java to write stored procedures, you can use two possible parameter<br />

passing styles. The recommended style is the JAVA parameter style, which matches<br />

the parameter style specified in the <strong>SQL</strong>j:<strong>SQL</strong> routines standard. The second style,<br />

<strong>DB2</strong>GENERAL, is a parameter style defined by <strong>DB2</strong> <strong>UDB</strong>. The parameter style also<br />

determines the conventions that you must use when coding a Java stored<br />

procedure.<br />

Coding a Java stored procedure that uses the JAVA parameter<br />

When you code a Java stored procedure that uses the JAVA parameter style, you<br />

must follow the following conventions:<br />

v The Java method must be a public void static (not instance) method.<br />

v The parameters of the Java method must be <strong>SQL</strong>-compatible types.<br />

v A Java method may test <strong>for</strong> a <strong>SQL</strong> NULL value when the parameter is a nullable<br />

type (like String).<br />

v Output parameters are returned by using single element arrays.<br />

v The Java method may access the current database using the getConnection( )<br />

method.<br />

v The compiled class file must reside in the<br />

/QIBM/UserData/OS<strong>400</strong>/<strong>SQL</strong>Lib/Function directory.<br />

Java stored procedures using the JAVA parameter style are public static methods.<br />

Within the classes, the stored procedures are identified by their method name and<br />

signature. When you call a stored procedure, its signature is generated<br />

dynamically, based on the variable types defined by the CREATE PROCEDURE<br />

statement.<br />

If a parameter is passed in a Java type that permits the null value, a Java method<br />

can compare the parameter to null to determine if an input parameter is an <strong>SQL</strong><br />

NULL. Output parameters are passed as arrays that contain one element. The Java<br />

stored procedure can set the first element of the array to set the output parameter.<br />

Chapter 7. Stored Procedures 145


A connection to the embedding application context is accessed using the following<br />

Java Database Connectivity (JDBC) call:<br />

connection=DriverManager.getConnection(″jdbc:default:connection″);<br />

This connection then runs<strong>SQL</strong> statements with JDBC APIs.<br />

The following is a small stored procedure with one input and two outputs. It<br />

executes the given <strong>SQL</strong> query, and returns the number of rows in the result, and<br />

the <strong>SQL</strong>STATE.<br />

package mystuff;<br />

import java.sql.*;<br />

public class sample2 {<br />

public static void donut(String query, int[] rowCount,<br />

String[] sqlstate) throws Exception {<br />

try {<br />

Connection c=DriverManager.getConnection("jdbc:default:connection");<br />

Statement s=c.createStatement();<br />

ResultSet r=s.executeQuery(query);<br />

int counter=0;<br />

while(r.next()){<br />

counter++;<br />

}<br />

r.close(); s.close();<br />

rowCount[0] = counter;<br />

}catch(<strong>SQL</strong>Exception x){<br />

sqlstate[0]= x.get<strong>SQL</strong>State();<br />

}<br />

}<br />

}<br />

All Java class files that are used by a Java stored procedure must reside in the<br />

/QIBM/UserData/OS<strong>400</strong>/<strong>SQL</strong>Lib/Function directory. This directory is the <strong>AS</strong>/<strong>400</strong><br />

equivalent of sqllib/function, the directory where <strong>DB2</strong> <strong>UDB</strong> stores Java stored<br />

procedures on other plat<strong>for</strong>ms.<br />

Coding a Java stored procedure using the <strong>DB2</strong>GENERAL parameter<br />

style<br />

When coding a Java stored procedure that uses the <strong>DB2</strong>GENERAL parameter style,<br />

you must follow the following conventions:<br />

v The class which defines a Java stored procedure must ″extend″, or be a subclass<br />

of, the Java com.ibm.db2.app.StoredProc class.<br />

v The Java method must be a public void instance method.<br />

v The parameters of the Java method must be <strong>SQL</strong>-compatible types.<br />

v A Java method may test <strong>for</strong> a <strong>SQL</strong> NULL value using the isNull( ) method.<br />

v The Java method must explicitly set the return parameters using the set( )<br />

method.<br />

v The Java method may access the current database using the getConnection ( )<br />

method.<br />

v The compiled class file must reside in the<br />

/QIBM/UserData/OS<strong>400</strong>/<strong>SQL</strong>Lib/Function directory.<br />

A class which includes a Java stored procedure must extend the class,<br />

com.ibm.db2.app.StoredProc. Java stored procedures are public instance methods.<br />

146 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


Within the classes, the stored procedures are identified by their method name and<br />

signature. When you call a stored procedure, its signature is generated<br />

dynamically, based on the variable types defined by the CREATE PROCEDURE<br />

statement.<br />

The com.ibm.db2.app.StoredProc class provides the isNull( ) method which permits<br />

a Java method to determine if an input parameter is an <strong>SQL</strong> NULL. The<br />

com.ibm.db2.app.StoredProc class also provides set...( ) methods that set output<br />

parameters. You must use these methods to set output parameters. If you do not<br />

set an output parameter, then the output parameter will return the <strong>SQL</strong> NULL<br />

value.<br />

The com.ibm.db2.app.StoredProc class provides the following routine to fetch a<br />

JDBC connection to the embedding application context. A connection to the<br />

embedding application context is accessed using the following JDBC call:<br />

public Java.sql.Connection getConnection()<br />

This connection then runs <strong>SQL</strong> statements with JDBC APIs.<br />

The following is a small stored procedure with one input and two outputs. It<br />

executes the given <strong>SQL</strong> query, and returns the number of rows in the result, and<br />

the <strong>SQL</strong>STATE.<br />

package mystuff;<br />

import com.ibm.db2.app.*;<br />

import java.sql.*;<br />

public class sample2 extends StoredProc {<br />

public void donut(String query, int rowCount,<br />

String sqlstate) throws Exception {<br />

try {<br />

Statement s=getConnection().createStatement();<br />

ResultSet r=s.executeQuery(query);<br />

int counter=0;<br />

while(r.next()){<br />

counter++;<br />

}<br />

r.close(); s.close();<br />

set(2, counter);<br />

}catch(<strong>SQL</strong>Exception x){<br />

set(3, x.get<strong>SQL</strong>State());<br />

}<br />

}<br />

}<br />

All Java class files that are used by a Java stored procedure must reside in the<br />

/QIBM/UserData/OS<strong>400</strong>/<strong>SQL</strong>Lib/Function directory. This directory is the <strong>AS</strong>/<strong>400</strong><br />

equivalent of sqllib/function, the directory where <strong>DB2</strong> <strong>UDB</strong> stores Java stored<br />

procedures on other plat<strong>for</strong>ms.<br />

When compiling a Java stored procedure that uses the <strong>DB2</strong>GENERAL parameter<br />

style, the user must add /QIBM/ProdData/Java<strong>400</strong>/ext/db2routines_classes.jar to<br />

the CL<strong>AS</strong>SPATH.<br />

Restrictions on Java stored procedures<br />

The following restrictions apply to Java Stored Procedures.<br />

v A Java stored procedure should not create additional threads. An additional<br />

thread may be created in a job only if the job is multithread capable. Since there<br />

Chapter 7. Stored Procedures 147


is no guaranteed that a job that calls an <strong>SQL</strong> stored procedure is multithread<br />

capable, a Java stored procedure should not create additional threads.<br />

v Like stored procedures that are written in other programming languages, Java<br />

stored procedures may not execute the following <strong>SQL</strong> statements: COMMIT,<br />

ROLLBACK, SET TRANSACTION, CONNECT, DISCONNECT, RELE<strong>AS</strong>E, or<br />

SET CONNECTION.<br />

v Java stored procedures do no have the ability to return RESULT SETS.<br />

v Since there is not a program object associated with a Java class file, the CREATE<br />

PROCEDURE in<strong>for</strong>mation associated with the database is not stored with the<br />

program object. There<strong>for</strong>e, it is not restored when a Java class is restored.<br />

v You cannot use adopted authority to access Java class files.<br />

v A Java stored procedure always uses the latest version of the Java Development<br />

Kit that is installed on the system.<br />

v Since Blob and Clob classes reside in both the java.sql and com.ibm.db2.app<br />

packages, the programmer must use the entire name of these classes if both<br />

classes are used in the same program. The program must ensure that the Blob<br />

and Clob classes from the com.ibm.db2.app are used as the parameters passed to<br />

the stored procedure.<br />

v Java stored procedures are stored in Java class files instead of *PGM objects or<br />

*SRVPGM objects. There<strong>for</strong>e, the REVOKE and GRANT <strong>SQL</strong> commands cannot<br />

be used to revoke or grant authority to the Java class files.<br />

148 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


Chapter 8. Using the Object-Relational Capabilities<br />

This chapter discusses the object-oriented capabilities of <strong>DB2</strong>.<br />

v Why use the <strong>DB2</strong> object extensions?<br />

v <strong>DB2</strong> approach to supporting objects<br />

v Using Large Objects (LOBs)<br />

v User-defined functions (UDF)<br />

v User-defined distinct types (UDT)<br />

v Synergy between UDTs, UDFs, and LOBs<br />

One of the most important recent developments in modern programming language<br />

technology is object-orientation. Object orientation is the notion that entities in the<br />

application domain can be modeled as independent objects that are related to one<br />

another by means of classification. Object-orientation lets you capture the<br />

similarities and differences among objects in your application domain and group<br />

those objects together into related types. Objects of the same type behave in the<br />

same way because they share the same set of type-specific functions. These<br />

functions reflect the behavior of your objects in the application domain.<br />

Why use the <strong>DB2</strong> object extensions?<br />

With the object extensions of <strong>DB2</strong>, you can incorporate object-oriented (OO)<br />

concepts and methodologies into your relational database. You accomplish this by<br />

extending it with richer sets of types and functions. With these extensions, you can<br />

store instances of object-oriented data types in columns of tables, and operate on<br />

them by means of functions in <strong>SQL</strong> statements. In addition, you can make the<br />

semantic behavior of stored objects an important resource that can be shared<br />

among all your applications by means of the database.<br />

To incorporate object-orientation into your relational database systems, you can<br />

define new types and functions of your own. These new types and functions<br />

should reflect the semantics of the objects in your application domain. Some of the<br />

data objects you want to model may be large and complex (<strong>for</strong> example, text,<br />

voice, image, and financial data). There<strong>for</strong>e, you may also need mechanisms <strong>for</strong> the<br />

storage and manipulation of large objects. User-defined Distinct types (UDTs),<br />

user-defined functions (UDFs), and Large Objects (LOBs) are the mechanisms that<br />

are provided by <strong>DB2</strong>. With <strong>DB2</strong>, you can now define new types and functions of<br />

your own to store and manipulate application objects within the database.<br />

As described in subsequent sections, there is an important synergy among these<br />

object-oriented features. You can model a complex object in the application domain<br />

as a UDT. The UDT may in turn be internally represented as a LOB. In turn, the<br />

UDT’s behavior may be implemented in terms of UDFs. This section shows you<br />

how to use LOBs along with the steps that are required to define UDTs and UDFs.<br />

You will also learn how UDTs, UDFs, and LOBs can better represent the objects in<br />

your application and thus work together.<br />

Note: The use of the <strong>DB2</strong> object-oriented mechanisms (UDTs, UDFs, and LOBs) is<br />

not restricted to the support of object-oriented applications. Just as the C++<br />

programming language implements all sorts of non-object-oriented<br />

applications, the object-oriented mechanisms provided by <strong>DB2</strong> can also<br />

support all kinds of non-object-oriented applications. UDTs, UDFs, and<br />

© Copyright IBM Corp. 2000 149


<strong>DB2</strong> approach to supporting objects<br />

Using Large Objects (LOBs)<br />

LOBs are general-purpose mechanisms that can be used to model any<br />

database application. For this reason, these <strong>DB2</strong> object extensions offer<br />

extensive support <strong>for</strong> both non-traditional, that is, object-oriented<br />

applications, in addition to improving support <strong>for</strong> traditional ones.<br />

The object extensions of <strong>DB2</strong> enable you to realize the benefits of object technology<br />

while building on the strengths of relational technology. In a relational system,<br />

data types describe the data stored in columns of tables where the instances (or<br />

objects) of these data types are stored. Operations on these instances are supported<br />

by means of operators or functions that can be invoked anywhere that expressions<br />

are allowed.<br />

The <strong>DB2</strong> approach to support object extensions fits exactly into the relational<br />

paradigm. UDTs are data types that you define. UDT’s, like built-in types, can be<br />

used to describe the data that is stored in columns of tables. UDFs are functions<br />

that you define. UDFs, like built-in functions or operators, support the<br />

manipulation of UDT instances. Thus, UDT instances are stored in columns of<br />

tables and manipulated by UDFs in <strong>SQL</strong> queries. UDTs can be internally<br />

represented in different ways. LOBs are just one example of this.<br />

The VARCHAR and VARGRAPHIC data types have a limit of 32K bytes of<br />

storage. While this may be sufficient <strong>for</strong> small to medium size text data,<br />

applications often need to store large text documents. They may also need to store<br />

a wide variety of additional data types such as audio, video, drawings, mixed text<br />

and graphics, and images. <strong>DB2</strong> provides three data types to store these data objects<br />

as strings of up to fifteen (15) megabytes (MB) in size. The three data types are:<br />

Binary Large OBjects (BLOBs), single-byte Character Large OBjects (CLOBs), and<br />

Double-Byte Character Large OBjects (DBCLOBs).<br />

Along with storing large objects (LOBs), you will also need a method to refer to,<br />

use, and modify each LOB in the database. Each <strong>DB2</strong> table may have a large<br />

amount of associated LOB data. Although a single row containing one or more<br />

LOB values cannot exceed 15 megabytes, a table may contain nearly 256 gigabytes<br />

of LOB data. The content of the LOB column of a particular row at any point in<br />

time has a large object value.<br />

You can refer to and manipulate LOBs using host variables just as you would any<br />

other data type. However, host variables use the client memory buffer which may<br />

not be large enough to hold LOB values. Other means are necessary to manipulate<br />

these large values. Locators are useful to identify and manipulate a large object<br />

value at the database server and <strong>for</strong> extracting pieces of the LOB value. File<br />

reference variables are useful <strong>for</strong> physically moving a large object value (or a large<br />

part of it) to and from the client.<br />

The subsections that follow discuss the topics that are introduced above in more<br />

detail.<br />

150 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


Understanding large object data types (BLOB, CLOB,<br />

DBCLOB)<br />

Large object data types store data ranging in size from zero bytes to 15 megabytes.<br />

The three large object data types have the following definitions:<br />

v Character Large OBjects (CLOBs) — A character string made up of single-byte<br />

characters with an associated code page. This data type is best <strong>for</strong> holding<br />

text-oriented in<strong>for</strong>mation where the amount of in<strong>for</strong>mation could grow beyond<br />

the limits of a regular VARCHAR data type (upper limit of 32K bytes). Code<br />

page conversion of the in<strong>for</strong>mation is supported as well as compatibility with<br />

the other character types.<br />

v Double-Byte Character Large OBjects (DBCLOBs) — A character string made up<br />

of double-byte characters with an associated code page. This data type is best<br />

<strong>for</strong> holding text-oriented in<strong>for</strong>mation where double-byte character sets are used.<br />

Again, code page conversion of the in<strong>for</strong>mation is supported as well as<br />

compatibility with the other double-byte character types.<br />

v Binary Large OBjects (BLOBs) — A binary string made up of bytes with no<br />

associated code page. This data type may be the most useful because it can store<br />

binary data. There<strong>for</strong>e, it is a perfect source type <strong>for</strong> use by User-defined<br />

Distinct Types (UDTs). UDTs using BLOBs as the source type are created to store<br />

image, voice, graphical, and other types of business or application-specific data.<br />

For more in<strong>for</strong>mation on UDTs, see “User-defined distinct types (UDT)” on<br />

page 173.<br />

Understanding large object locators<br />

Conceptually, LOB locators represent a simple idea that has been around <strong>for</strong> a<br />

while; use a small, easily managed value to refer to a much larger value.<br />

Specifically, a LOB locator is a 4-byte value stored in a host variable that a<br />

program uses to refer to a LOB value (or LOB expression) held in the database<br />

system. Using a LOB locator, a program can manipulate the LOB value as if the<br />

LOB value was stored in a regular host variable. When you use the LOB locator,<br />

there is no need to transport the LOB value from the server to the application (and<br />

possibly back again).<br />

The LOB locator is associated with a LOB value or LOB expression, not a row or<br />

physical storage location in the database. There<strong>for</strong>e, after selecting a LOB value<br />

into a locator, you cannot per<strong>for</strong>m an operation on the original row(s) or tables(s)<br />

that would have any effect on the value referenced by the locator. The value<br />

associated with the locator is valid until the unit of work ends, or the locator is<br />

explicitly freed, whichever comes first. The FREE LOCATOR statement releases a<br />

locator from its associated value. In a similar way, a commit or roll-back operation<br />

frees all LOB locators associated with the transaction.<br />

LOB locators can also be passed between <strong>DB2</strong> and UDFs. Within the UDF, those<br />

functions that work on LOB data are available to manipulate the LOB values using<br />

LOB locators.<br />

When selecting a LOB value, you have three options.<br />

v Select the entire LOB value into a host variable. The entire LOB value is copied<br />

into the host variable.<br />

Chapter 8. Using the Object-Relational Capabilities 151


v Select the LOB value into a LOB locator. The LOB value remains on the server; it<br />

is not copied to the host variable.<br />

v Select the entire LOB value into a file reference variable. The LOB value is<br />

moved to an Integrated File System (IFS) file.<br />

The use of the LOB value within the program can help the programmer determine<br />

which method is best. If the LOB value is very large and is needed only as an<br />

input value <strong>for</strong> one or more subsequent <strong>SQL</strong> statements, keep the value in a<br />

locator.<br />

If the program needs the entire LOB value regardless of the size, then there is no<br />

choice but to transfer the LOB. Even in this case, there are still three options<br />

available to you. You can select the entire value into a regular or file reference host<br />

variable. You may also select the LOB value into a locator and read it piecemeal<br />

from the locator into a regular host variable, as suggested in the following<br />

example.<br />

Example: Using a locator to work with a CLOB value<br />

In this example, the application program retrieves a locator <strong>for</strong> a LOB value; then<br />

it uses the locator to extract the data from the LOB value. Using this method, the<br />

program allocates only enough storage <strong>for</strong> one piece of LOB data (the size is<br />

determined by the program). In addition, the program needs to issue only one<br />

fetch call using the cursor.<br />

How the sample LOBLOC program works<br />

1. Declare host variables. The BEGIN DECLARE SECTION and END DECLARE<br />

SECTION statements delimit the host variable declarations. Host variables are<br />

prefixed with a colon (:) when referenced in an <strong>SQL</strong> statement. CLOB<br />

LOCATOR host variables are declared.<br />

2. Fetch the LOB value into the locator host variable. A CURSOR and FETCH<br />

routine is used to obtain the location of a LOB field in the database to a locator<br />

host variable.<br />

3. Free the LOB LOCATORS. The LOB LOCATORS used in this example are<br />

freed, releasing the locators from their previously associated values.<br />

The CHECKERR macro/function is an error checking utility which is external to the<br />

program. The location of this error checking utility depends on the programming<br />

language that is used:<br />

C check_error is redefined as CHECKERR and is located in the util.c<br />

file.<br />

152 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


C Sample: LOBLOC.SQC<br />

#include <br />

#include <br />

#include <br />

#include "util.h"<br />

EXEC <strong>SQL</strong> INCLUDE <strong>SQL</strong>CA;<br />

#define CHECKERR(CE_STR) if (check_error (CE_STR, &sqlca) != 0) return 1;<br />

int main(int argc, char *argv[]) {<br />

#ifdef <strong>DB2</strong>MAC<br />

char * bufptr;<br />

#endif<br />

EXEC <strong>SQL</strong> BEGIN DECLARE SECTION; ▌1▐<br />

char number[7];<br />

long deptInfoBeginLoc;<br />

long deptInfoEndLoc;<br />

<strong>SQL</strong> TYPE IS CLOB_LOCATOR resume;<br />

<strong>SQL</strong> TYPE IS CLOB_LOCATOR deptBuffer;<br />

short lobind;<br />

char buffer[1000]="";<br />

char userid[9];<br />

char passwd[19];<br />

EXEC <strong>SQL</strong> END DECLARE SECTION;<br />

printf("Sample C program: LOBLOC\n" );<br />

if (argc == 1) {<br />

EXEC <strong>SQL</strong> CONNECT TO sample;<br />

CHECKERR ("CONNECT TO SAMPLE");<br />

}<br />

else if (argc == 3) {<br />

strcpy (userid, argv[1]);<br />

strcpy (passwd, argv[2]);<br />

EXEC <strong>SQL</strong> CONNECT TO sample USER :userid USING :passwd;<br />

CHECKERR ("CONNECT TO SAMPLE");<br />

}<br />

else {<br />

printf ("\nUSAGE: lobloc [userid passwd]\n\n");<br />

return 1;<br />

} /* endif */<br />

/* Employee A10030 is not included in the following select, because<br />

the lobeval program manipulates the record <strong>for</strong> A10030 so that it is<br />

not compatible with lobloc */<br />

EXEC <strong>SQL</strong> DECLARE c1 CURSOR FOR<br />

SELECT empno, resume FROM emp_resume WHERE resume_<strong>for</strong>mat='ascii'<br />

AND empno 'A00130';<br />

EXEC <strong>SQL</strong> OPEN c1;<br />

CHECKERR ("OPEN CURSOR");<br />

do {<br />

EXEC <strong>SQL</strong> FETCH c1 INTO :number, :resume :lobind; ▌2▐<br />

if (<strong>SQL</strong>CODE != 0) break;<br />

if (lobind < 0) {<br />

printf ("NULL LOB indicated\n");<br />

} else {<br />

/* EVALUATE the LOB LOCATOR */<br />

/* Locate the beginning of "Department In<strong>for</strong>mation" section */<br />

EXEC <strong>SQL</strong> VALUES (POSSTR(:resume, 'Department In<strong>for</strong>mation'))<br />

INTO :deptInfoBeginLoc;<br />

CHECKERR ("VALUES1");<br />

/* Locate the beginning of "Education" section (end of "Dept.Info" */<br />

EXEC <strong>SQL</strong> VALUES (POSSTR(:resume, 'Education'))<br />

INTO :deptInfoEndLoc;<br />

CHECKERR ("VALUES2");<br />

/* Obtain ONLY the "Department In<strong>for</strong>mation" section by using SUBSTR */<br />

EXEC <strong>SQL</strong> VALUES(SUBSTR(:resume, :deptInfoBeginLoc,<br />

:deptInfoEndLoc - :deptInfoBeginLoc)) INTO :deptBuffer;<br />

CHECKERR ("VALUES3");<br />

/* Append the "Department In<strong>for</strong>mation" section to the :buffer var. */<br />

EXEC <strong>SQL</strong> VALUES(:buffer || :deptBuffer) INTO :buffer;<br />

CHECKERR ("VALUES4");<br />

} /* endif */<br />

} while (1 );<br />

#ifdef <strong>DB2</strong>MAC<br />

/* Need to convert the newline character <strong>for</strong> the Mac */<br />

bufptr = &(buffer[0]);<br />

while (*bufptr != '\0' ) {<br />

if (*bufptr == 0x0A ) *bufptr = 0x0D;<br />

bufptr++;<br />

}<br />

#endif<br />

printf ("%s\n",buffer);<br />

EXEC <strong>SQL</strong> FREE LOCATOR :resume, :deptBuffer; ▌3▐<br />

Chapter 8. Using the Object-Relational Capabilities 153


CHECKERR ("FREE LOCATOR");<br />

EXEC <strong>SQL</strong> CLOSE c1;<br />

CHECKERR ("CLOSE CURSOR");<br />

EXEC <strong>SQL</strong> CONNECT RESET;<br />

CHECKERR ("CONNECT RESET");<br />

return 0;<br />

}<br />

/* end of program : LOBLOC.SQC */<br />

COBOL Sample: LOBLOC.SQB<br />

Identification Division.<br />

Program-ID. "lobloc".<br />

Data Division.<br />

Working-Storage Section.<br />

copy "sqlenv.cbl".<br />

copy "sql.cbl".<br />

copy "sqlca.cbl".<br />

EXEC <strong>SQL</strong> BEGIN DECLARE SECTION END-EXEC. ▌1▐<br />

01 userid pic x(8).<br />

01 passwd.<br />

49 passwd-length pic s9(4) comp-5 value 0.<br />

49 passwd-name pic x(18).<br />

01 empnum pic x(6).<br />

01 di-begin-loc pic s9(9) comp-5.<br />

01 di-end-loc pic s9(9) comp-5.<br />

01 resume USAGE IS <strong>SQL</strong> TYPE IS CLOB-LOCATOR.<br />

01 di-buffer USAGE IS <strong>SQL</strong> TYPE IS CLOB-LOCATOR.<br />

01 lobind pic s9(4) comp-5.<br />

01 buffer USAGE IS <strong>SQL</strong> TYPE IS CLOB(1K).<br />

EXEC <strong>SQL</strong> END DECLARE SECTION END-EXEC.<br />

77 errloc pic x(80).<br />

Procedure Division.<br />

Main Section.<br />

display "Sample COBOL program: LOBLOC".<br />

* Get database connection in<strong>for</strong>mation.<br />

display "Enter your user id (default none): "<br />

with no advancing.<br />

accept userid.<br />

if userid = spaces<br />

EXEC <strong>SQL</strong> CONNECT TO sample END-EXEC<br />

else<br />

display "Enter your password : " with no advancing<br />

accept passwd-name.<br />

* Passwords in a CONNECT statement must be entered in a VARCHAR<br />

* <strong>for</strong>mat with the length of the input string.<br />

inspect passwd-name tallying passwd-length <strong>for</strong> characters<br />

be<strong>for</strong>e initial " ".<br />

EXEC <strong>SQL</strong> CONNECT TO sample USER :userid USING :passwd<br />

END-EXEC.<br />

move "CONNECT TO" to errloc.<br />

call "checkerr" using <strong>SQL</strong>CA errloc.<br />

* Employee A10030 is not included in the following select, because<br />

* the lobeval program manipulates the record <strong>for</strong> A10030 so that it is<br />

* not compatible with lobloc<br />

EXEC <strong>SQL</strong> DECLARE c1 CURSOR FOR<br />

SELECT empno, resume FROM emp_resume<br />

WHERE resume_<strong>for</strong>mat = 'ascii'<br />

AND empno 'A00130' END-EXEC.<br />

EXEC <strong>SQL</strong> OPEN c1 END-EXEC.<br />

move "OPEN CURSOR" to errloc.<br />

call "checkerr" using <strong>SQL</strong>CA errloc.<br />

Move 0 to buffer-length.<br />

per<strong>for</strong>m Fetch-Loop thru End-Fetch-Loop<br />

until <strong>SQL</strong>CODE not equal 0.<br />

* display contents of the buffer.<br />

display buffer-data(1:buffer-length).<br />

EXEC <strong>SQL</strong> FREE LOCATOR :resume, :di-buffer END-EXEC. ▌3▐<br />

move "FREE LOCATOR" to errloc.<br />

call "checkerr" using <strong>SQL</strong>CA errloc.<br />

EXEC <strong>SQL</strong> CLOSE c1 END-EXEC.<br />

move "CLOSE CURSOR" to errloc.<br />

call "checkerr" using <strong>SQL</strong>CA errloc.<br />

EXEC <strong>SQL</strong> CONNECT RESET END-EXEC.<br />

move "CONNECT RESET" to errloc.<br />

call "checkerr" using <strong>SQL</strong>CA errloc.<br />

End-Main.<br />

154 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


go to End-Prog.<br />

Fetch-Loop Section.<br />

EXEC <strong>SQL</strong> FETCH c1 INTO :empnum, :resume :lobind ▌2▐<br />

END-EXEC.<br />

if <strong>SQL</strong>CODE not equal 0<br />

go to End-Fetch-Loop.<br />

* check to see if the host variable indicator returns NULL.<br />

if lobind less than 0 go to NULL-lob-indicated.<br />

* Value exists. Evaluate the LOB locator.<br />

* Locate the beginning of "Department In<strong>for</strong>mation" section.<br />

EXEC <strong>SQL</strong> VALUES (POSSTR(:resume, 'Department In<strong>for</strong>mation'))<br />

INTO :di-begin-loc END-EXEC.<br />

move "VALUES1" to errloc.<br />

call "checkerr" using <strong>SQL</strong>CA errloc.<br />

* Locate the beginning of "Education" section (end of Dept.Info)<br />

EXEC <strong>SQL</strong> VALUES (POSSTR(:resume, 'Education'))<br />

INTO :di-end-loc END-EXEC.<br />

move "VALUES2" to errloc.<br />

call "checkerr" using <strong>SQL</strong>CA errloc.<br />

subtract di-begin-loc from di-end-loc.<br />

* Obtain ONLY the "Department In<strong>for</strong>mation" section by using SUBSTR<br />

EXEC <strong>SQL</strong> VALUES (SUBSTR(:resume, :di-begin-loc,<br />

:di-end-loc))<br />

INTO :di-buffer END-EXEC.<br />

move "VALUES3" to errloc.<br />

call "checkerr" using <strong>SQL</strong>CA errloc.<br />

* Append the "Department In<strong>for</strong>mation" section to the :buffer var<br />

EXEC <strong>SQL</strong> VALUES (:buffer || :di-buffer) INTO :buffer<br />

END-EXEC.<br />

move "VALUES4" to errloc.<br />

call "checkerr" using <strong>SQL</strong>CA errloc.<br />

go to End-Fetch-Loop.<br />

NULL-lob-indicated.<br />

display "NULL LOB indicated".<br />

End-Fetch-Loop. exit.<br />

End-Prog.<br />

stop run.<br />

Indicator variables and LOB locators<br />

For normal host variables in an application program, when selecting a NULL value<br />

into a host variable, a negative value is assigned to the indicator variable<br />

signifying that the value is NULL. In the case of LOB locators, however, the<br />

meaning of indicator variables is slightly different. Since a locator host variable<br />

itself can never be NULL, a negative indicator variable value indicates that the<br />

LOB value represented by the LOB locator is NULL. The NULL in<strong>for</strong>mation is kept<br />

local to the client using the indicator variable value — the server does not track<br />

NULL values with valid locators.<br />

LOB file reference variables<br />

File reference variables are similar to host variables except they are used to transfer<br />

data to and from IFS files (not to and from memory buffers). A file reference<br />

variable represents (rather than contains) the file, just as a LOB locator represents<br />

(rather than contains) the LOB value. Database queries, updates, and inserts may<br />

use file reference variables to store, or to retrieve, single LOB values.<br />

For very large objects, files are natural containers. It is likely that most LOBs begin<br />

as data stored in files on the client be<strong>for</strong>e they are moved to the database on the<br />

server. The use of file reference variables assists in moving LOB data. Programs<br />

use file reference variables to transfer LOB data from the IFS file directly to the<br />

database engine. To carry out the movement of LOB data, the application does not<br />

have to write utility routines to read and write files using host variables.<br />

Chapter 8. Using the Object-Relational Capabilities 155


Note: The file referenced by the file reference variable must be accessible from (but<br />

not necessarily resident on) the system on which the program runs. For a<br />

stored procedure, this would be the server.<br />

A file reference variable has a data type of BLOB, CLOB, or DBCLOB. It is used<br />

either as the source of data (input) or as the target of data (output). The file<br />

reference variable may have a relative file name or a complete path name of the<br />

file (the latter is advised). The file name length is specified within the application<br />

program. The data length portion of the file reference variable is unused during<br />

input. During output, the data length is set by the application requestor code to<br />

the length of the new data that is written to the file.<br />

When using file reference variables there are different options on both input and<br />

output. You must choose an action <strong>for</strong> the file by setting the file_options field in<br />

the file reference variable structure. Choices <strong>for</strong> assignment to the field covering<br />

both input and output values are shown below.<br />

Values (shown <strong>for</strong> C) and options when using input file reference variables are as<br />

follows:<br />

v <strong>SQL</strong>_FILE_READ (Regular file) — This option has a value of 2. This is a file<br />

that can be open, read, and closed. <strong>DB2</strong> determines the length of the data in the<br />

file (in bytes) when opening the file. <strong>DB2</strong> then returns the length through the<br />

data_length field of the file reference variable structure. (The value <strong>for</strong> COBOL<br />

is <strong>SQL</strong>-FILE-READ.)<br />

Values and options when using output file reference variables are as follows:<br />

v <strong>SQL</strong>_FILE_CREATE (New file) — This option has a value of 8. This option<br />

creates a new file. Should the file already exist, an error message is returned.<br />

(The value <strong>for</strong> COBOL is <strong>SQL</strong>-FILE-CREATE.)<br />

v <strong>SQL</strong>_FILE_OVERWRITE (Overwrite file) — This option has a value of 16. This<br />

option creates a new file if none already exists. If the file already exists, the new<br />

data overwrites the data in the file. (The value <strong>for</strong> COBOL is<br />

<strong>SQL</strong>-FILE-OVERWRITE.)<br />

v <strong>SQL</strong>_FILE_APPEND (Append file) — This option has a value of 32. This option<br />

has the output appended to the file, if it exists. Otherwise, it creates a new file.<br />

(The value <strong>for</strong> COBOL is <strong>SQL</strong>-FILE-APPEND.)<br />

Note: If a LOB file reference variable is used in an OPEN statement, do not delete<br />

the file associated with the LOB file reference variable until the cursor is<br />

closed.<br />

For more in<strong>for</strong>mation about integrated file system, see Integrated File System.<br />

Example: Extracting a document to a file<br />

This program example shows how CLOB elements can be retrieved from a table<br />

into an external file.<br />

How the sample LOBFILE program works<br />

1. Declare host variables. The BEGIN DECLARE SECTION and END DECLARE<br />

SECTION statements delimit the host variable declarations. Host variables are<br />

prefixed with a colon (:) when referenced in an <strong>SQL</strong> statement. A CLOB FILE<br />

REFERENCE host variable is declared.<br />

156 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


2. CLOB FILE REFERENCE host variable is set up. The attributes of the FILE<br />

REFERENCE are set up. A file name without a fully declared path is, by<br />

default, placed in the user’s current directory. If the pathname does not begin<br />

with the <strong>for</strong>ward slash (/) character, it is not qualified.<br />

3. Select into the CLOB FILE REFERENCE host variable. The data from the<br />

resume field is selected into the filename that is referenced by the host variable.<br />

The CHECKERR macro/function is an error checking utility which is external to the<br />

program. The location of this error checking utility depends upon the<br />

programming language used:<br />

C check_error is redefined as CHECKERR and is located in the util.c<br />

file.<br />

COBOL CHECKERR is an external program named checkerr.cbl<br />

C Sample: LOBFILE.SQC<br />

#include <br />

#include <br />

#include <br />

#include <br />

#include "util.h"<br />

EXEC <strong>SQL</strong> INCLUDE <strong>SQL</strong>CA;<br />

#define CHECKERR(CE_STR) if (check_error (CE_STR, &sqlca) != 0) return 1;<br />

int main(int argc, char *argv[]) {<br />

EXEC <strong>SQL</strong> BEGIN DECLARE SECTION; ▌1▐<br />

<strong>SQL</strong> TYPE IS CLOB_FILE resume;<br />

short lobind;<br />

char userid[9];<br />

char passwd[19];<br />

EXEC <strong>SQL</strong> END DECLARE SECTION;<br />

printf("Sample C program: LOBFILE\n" );<br />

if (argc == 1) {<br />

EXEC <strong>SQL</strong> CONNECT TO sample;<br />

CHECKERR ("CONNECT TO SAMPLE");<br />

}<br />

else if (argc == 3) {<br />

strcpy (userid, argv[1]);<br />

strcpy (passwd, argv[2]);<br />

EXEC <strong>SQL</strong> CONNECT TO sample USER :userid USING :passwd;<br />

CHECKERR ("CONNECT TO SAMPLE");<br />

}<br />

else {<br />

printf ("\nUSAGE: lobfile [userid passwd]\n\n");<br />

return 1;<br />

} /* endif */<br />

strcpy (resume.name, "RESUME.TXT"); ▌2▐<br />

resume.name_length = strlen("RESUME.TXT");<br />

resume.file_options = <strong>SQL</strong>_FILE_OVERWRITE;<br />

EXEC <strong>SQL</strong> SELECT resume INTO :resume :lobind FROM emp_resume ▌3▐<br />

WHERE resume_<strong>for</strong>mat='ascii' AND empno='000130';<br />

if (lobind < 0) {<br />

printf ("NULL LOB indicated \n");<br />

} else {<br />

printf ("Resume <strong>for</strong> EMPNO 000130 is in file : RESUME.TXT\n");<br />

} /* endif */<br />

EXEC <strong>SQL</strong> CONNECT RESET;<br />

CHECKERR ("CONNECT RESET");<br />

return 0;<br />

}<br />

/* end of program : LOBFILE.SQC */<br />

COBOL Sample: LOBFILE.SQB<br />

Identification Division.<br />

Program-ID. "lobfile".<br />

Data Division.<br />

Working-Storage Section.<br />

copy "sqlenv.cbl".<br />

copy "sql.cbl".<br />

copy "sqlca.cbl".<br />

EXEC <strong>SQL</strong> BEGIN DECLARE SECTION END-EXEC. ▌1▐<br />

Chapter 8. Using the Object-Relational Capabilities 157


01 userid pic x(8).<br />

01 passwd.<br />

49 passwd-length pic s9(4) comp-5 value 0.<br />

49 passwd-name pic x(18).<br />

01 resume USAGE IS <strong>SQL</strong> TYPE IS CLOB-FILE.<br />

01 lobind pic s9(4) comp-5.<br />

EXEC <strong>SQL</strong> END DECLARE SECTION END-EXEC.<br />

77 errloc pic x(80).<br />

Procedure Division.<br />

Main Section.<br />

display "Sample COBOL program: LOBFILE".<br />

* Get database connection in<strong>for</strong>mation.<br />

display "Enter your user id (default none): "<br />

with no advancing.<br />

accept userid.<br />

if userid = spaces<br />

EXEC <strong>SQL</strong> CONNECT TO sample END-EXEC<br />

else<br />

display "Enter your password : " with no advancing<br />

accept passwd-name.<br />

* Passwords in a CONNECT statement must be entered in a VARCHAR<br />

* <strong>for</strong>mat with the length of the input string.<br />

inspect passwd-name tallying passwd-length <strong>for</strong> characters<br />

be<strong>for</strong>e initial " ".<br />

EXEC <strong>SQL</strong> CONNECT TO sample USER :userid USING :passwd<br />

END-EXEC.<br />

move "CONNECT TO" to errloc.<br />

call "checkerr" using <strong>SQL</strong>CA errloc.<br />

move "RESUME.TXT" to resume-NAME. ▌2▐<br />

move 10 to resume-NAME-LENGTH.<br />

move <strong>SQL</strong>-FILE-OVERWRITE to resume-FILE-OPTIONS.<br />

EXEC <strong>SQL</strong> SELECT resume INTO :resume :lobind ▌3▐<br />

FROM emp_resume<br />

WHERE resume_<strong>for</strong>mat = 'ascii'<br />

AND empno = '000130' END-EXEC.<br />

if lobind less than 0 go to NULL-LOB-indicated.<br />

display "Resume <strong>for</strong> EMPNO 000130 is in file : RESUME.TXT".<br />

go to End-Main.<br />

NULL-LOB-indicated.<br />

display "NULL LOB indicated".<br />

End-Main.<br />

EXEC <strong>SQL</strong> CONNECT RESET END-EXEC.<br />

move "CONNECT RESET" to errloc.<br />

call "checkerr" using <strong>SQL</strong>CA errloc.<br />

End-Prog.<br />

stop run.<br />

Example: Inserting data into a CLOB column<br />

In the path description of the following C program segment:<br />

v userid represents the directory <strong>for</strong> one of your users.<br />

v dirname represents a subdirectory name of “userid”.<br />

v filnam.1 can become the name of one of your documents that you wish to insert<br />

into the table.<br />

v clobtab is the name of the table with the CLOB data type.<br />

The following example shows how to insert data from a regular file referenced by<br />

:hv_text_file into a CLOB column:<br />

strcpy(hv_text_file.name, "/home/userid/dirname/filnam.1");<br />

hv_text_file.name_length = strlen("/home/userid/dirname/filnam.1");<br />

hv_text_file.file_options = <strong>SQL</strong>_FILE_READ; /* this is a 'regular' file */<br />

EXEC <strong>SQL</strong> INSERT INTO CLOBTAB<br />

VALUES(:hv_text_file);<br />

Display layout of LOB columns<br />

When a row of data from a table holding LOB columns is displayed using CL<br />

commands such as Display Physical File Member (DSPPFM), the LOB data stored<br />

158 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


in that row will not be displayed. Instead, the Database will show a special value<br />

<strong>for</strong> the LOB columns. The layout of this special value is as follows:<br />

v 13 to 28 bytes of hex zeros.<br />

v 16 bytes beginning with *POINTER and followed by blanks.<br />

The number of bytes in the first portion of the value is set to the number needed<br />

to 16 byte boundary align the second part of the value.<br />

For example, say you have a table that holds three columns: ColumnOne Char(10),<br />

ColumnTwo CLOB(40K), and ColumnThree BLOB(10M). If you were to issue a<br />

DSPPFM of this table, each row of data would look as follows.<br />

v For ColumnOne: 10 bytes filled with character data.<br />

v For ColumnTwo: 22 bytes filled with hex zeros and 16 bytes filled with<br />

’*POINTER ’.<br />

v For ColumnThree: 16 bytes filled with hex zeros and 16 bytes filled with<br />

’*POINTER ’.<br />

The full set of commands that display LOB columns in this way is:<br />

v Display Physical File Member (DSPPFM)<br />

v Copy File (CPYF) when the value *PRINT is specified <strong>for</strong> the TOFILE keyword<br />

v Display Journal (DSPJRN)<br />

v Retrieve Journal Entry (RTVJRNE)<br />

v Receive Journal Entry (RCVJRNE) when the values *TYPE1, *TYPE2, *TYPE3<br />

and *TYPE4 are specified <strong>for</strong> the ENTFMT keyword.<br />

Journal entry layout of LOB columns<br />

Two commands return a buffer that gives the user addressability to LOB data that<br />

had been journaled:<br />

v Receive Journal Entry (RCVJRNE) CL command, when the value *TYPEPTR is<br />

specified <strong>for</strong> the ENTFMT keyword<br />

v Retrieve Journal Entries (QjoRetrieveJournalEntries) API<br />

The layout of the LOB columns in these entries is as follows:<br />

v 0 to 15 bytes of hex zeros<br />

v 1 byte of system in<strong>for</strong>mation set to ’00’x<br />

v 4 bytes holding the length of the LOB data addressed by the pointer, below<br />

v 8 bytes of hex zeros<br />

v 16 bytes holding a pointer to the LOB data stored in the Journal Entry.<br />

The first part of this layout is intended to 16 byte boundary align the pointer to<br />

the LOB data. The number of bytes in this area depends on the length of the<br />

columns that proceed the LOB column. Refer to the section above on the Display<br />

Layout of LOB Columns <strong>for</strong> an example of how the length of this first part is<br />

calculated.<br />

For more in<strong>for</strong>mation on the Journal handling of LOB columns, refer to the<br />

″Working with Journal Entries, Journals and Journal Receivers″ chapter of the<br />

Backup and Recovery book.<br />

Chapter 8. Using the Object-Relational Capabilities 159


User-defined functions (UDF)<br />

A user-defined function is a mechanism with which you can write your own<br />

extensions to <strong>SQL</strong>. The built-in functions supplied with <strong>DB2</strong> are a useful set of<br />

functions, but they may not satisfy all of your requirements. Thus, you may need<br />

to extend <strong>SQL</strong> <strong>for</strong> the following reasons:<br />

v Customization.<br />

The function specific to your application does not exist in <strong>DB2</strong>. Whether the<br />

function is a simple trans<strong>for</strong>mation, a trivial calculation, or a complicated<br />

multivariate analysis, you can probably use a UDF to do the job.<br />

v Flexibility.<br />

The <strong>DB2</strong> built-in function does not quite permit the variations that you wish to<br />

include in your application.<br />

v Standardization.<br />

Many of the programs at your site implement the same basic set of functions,<br />

but there are minor differences in all the implementations. Thus, you are unsure<br />

about the consistency of the results you receive. If you correctly implement these<br />

functions once, in a UDF, then all these programs can use the same<br />

implementation directly in <strong>SQL</strong> and provide consistent results.<br />

v Object-relational support.<br />

As discussed in “User-defined distinct types (UDT)” on page 173, UDTs can be<br />

very useful in extending the capability and increasing the safety of <strong>DB2</strong>. UDFs<br />

act as the methods <strong>for</strong> UDTs, by providing behavior and encapsulating the types.<br />

In addition, <strong>SQL</strong> UDFs provide the support to manipulate Large Objects and<br />

DataLink types. While the database provides several built-in functions which are<br />

useful in working with these datatypes, <strong>SQL</strong> UDFs provide a way <strong>for</strong> users to<br />

further manipulate and enhance the capabilities of the database (to the<br />

specialization required) in this area.<br />

Why use UDFs?<br />

In writing <strong>DB2</strong> applications, you have a choice when implementing desired actions<br />

or operations:<br />

v As a UDF<br />

v As a subroutine or function in your application.<br />

Although it appears easier to implement new operations as subroutines or<br />

functions in your application, you should still consider:<br />

v Re-use.<br />

If the new operation is something of which other users or programs at your site<br />

can take advantage, then UDFs can help to reuse it. In addition, the function can<br />

be invoked directly in <strong>SQL</strong> wherever an expression can be used by any user of<br />

the database. The database will take care of many data type promotions of the<br />

function arguments automatically. For example, with DECIMAL to DOUBLE, the<br />

database will allow your function to be applied to different, but compatible data<br />

types.<br />

It may seem easier to implement your new function as a normal function. (You<br />

would not have to define the function to <strong>DB2</strong>.) If you did this, you would have<br />

to in<strong>for</strong>m all other interested application developers, and package the function<br />

effectively <strong>for</strong> their use. However, this process ignores the interactive users like<br />

those who normally use the Command Line Processor (CLP) to access the<br />

160 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


database. However, functions written <strong>for</strong> use only within programs ignores those<br />

(interactive) users who do not have associated programs. This includes<br />

commands such as STR<strong>SQL</strong>, STRQM, and RUN<strong>SQL</strong>STM, in addition to many<br />

clients such as ODBC, JDBC, etc. CLP users cannot use your function unless it is<br />

a UDF in the database. This also applies to any other tools that use <strong>SQL</strong> (such as<br />

Visualizer), that do not get recompiled.<br />

v Per<strong>for</strong>mance.<br />

In certain cases, invoking the UDF directly from the database engine instead of<br />

from your application can have a considerable per<strong>for</strong>mance advantage. You willl<br />

notice this advantage when the function may be used in the qualification of data<br />

<strong>for</strong> further processing. These cases occur when the function is used in record<br />

selection processing. Consider a simple scenario where you want to process<br />

some data. You can meet some selection criteria which can be expressed as a<br />

function SELECTION_CRITERIA(). Your application could issue the following select<br />

statement:<br />

SELECT A, B, C FROM T<br />

When it receives each row, it runs SELECTION_CRITERIA against the data to decide<br />

if it is interested in processing the data further. Here, every row of table T must<br />

be passed back to the application. But, if SELECTION_CRITERIA() is implemented<br />

as a UDF, your application can issue the following statement:<br />

SELECT C FROM T WHERE SELECTION_CRITERIA(A,B)=1<br />

In this case, only the rows and column of interest are passed across the interface<br />

between the application and the database.<br />

Another case where a UDF can offer a per<strong>for</strong>mance benefit is when dealing with<br />

Large Objects (LOB). Suppose you have a function that extracts some<br />

in<strong>for</strong>mation from a value of one of the LOB types. You can per<strong>for</strong>m this<br />

extraction right on the database server and pass only the extracted value back to<br />

the application. This is more efficient than passing the entire LOB value back to<br />

the application and then per<strong>for</strong>ming the extraction. The per<strong>for</strong>mance value of<br />

packaging this function as a UDF could be enormous, depending on the<br />

particular situation. (Note that you can also extract a portion of a LOB by using<br />

a LOB locator. See “Indicator variables and LOB locators” on page 155 <strong>for</strong> an<br />

example of a similar scenario.)<br />

v Object Orientation.<br />

You can implement the behavior of a user-defined distinct type (UDT), also<br />

called distinct type, using a UDF. For more in<strong>for</strong>mation on UDTs, see<br />

“User-defined distinct types (UDT)” on page 173. For additional details on UDTs<br />

and the important concept of castability discussed herein, see the CREATE<br />

DISTINCT TYPE statement in the <strong>SQL</strong> Reference. When you create a distinct<br />

type, you are automatically provided cast functions between the distinct type<br />

and its source type. You may also be provided comparison operators such as =,<br />

>,


UDF concepts<br />

a BLOB source type, you do not get the comparison operations automatically<br />

generated <strong>for</strong> you. You can implement a BOAT_COMPARE function which<br />

decides if one boat is bigger than another based on a measure that you choose.<br />

These could be: displacement, length over all, metric tonnage, or another<br />

calculation based on the BOAT object. You create the BOAT_COMPARE function<br />

as follows:<br />

CREATE <strong>SQL</strong> FUNCTION BOAT_COMPARE (BOAT, BOAT) RETURNS INTEGER ...<br />

If your function returns:<br />

– 1 the first BOAT is bigger<br />

– 2 the second is bigger and<br />

– 0 they are equal.<br />

You could use this function in your <strong>SQL</strong> code to compare boats. Suppose you<br />

create the following tables:<br />

CREATE TABLE BOATS_INVENTORY (<br />

BOAT_ID CHAR(5),<br />

BOAT_TYPE VARCHAR(25),<br />

DESIGNER VARCHAR(40),<br />

OWNER VARCHAR(40),<br />

DESIGN_DATE DATE,<br />

SPEC BOAT,<br />

... )<br />

CREATE TABLE MY_BOATS (<br />

BOAT_ID CHAR(5),<br />

BOAT_TYPE VARCHAR(25),<br />

DESIGNER VARCHAR(40),<br />

DESIGN_DATE DATE,<br />

ACQUIRE_DATE DATE,<br />

ACQUIRE_PRICE CANADIAN_DOLLAR,<br />

CURR_APPRAISL CANADIAN_DOLLAR,<br />

SPEC BOAT,<br />

... )<br />

You can execute the following <strong>SQL</strong> SELECT statement:<br />

SELECT INV.BOAT_ID, INV.BOAT_TYPE, INV.DESIGNER,<br />

INV.OWNER, INV.DESIGN_DATE<br />

FROM BOATS_INVENTORY INV, MY_BOATS MY<br />

WHERE MY.BOAT_ID = '19GCC'<br />

AND BOAT_COMPARE(INV.SPEC, MY.SPEC) = 1<br />

AND INV.DESIGNER = MY.DESIGNER<br />

This simple example returns all the boats from BOATS_INVENTORY from the<br />

same designer that are bigger than a particular boat in MY_BOATS. Note that<br />

the example only passes the rows of interest back to the application because the<br />

comparison occurs in the database server. In fact, it completely avoids passing<br />

any values of data type BOAT. This is a significant improvement in storage and<br />

per<strong>for</strong>mance as BOAT is based on a one megabyte BLOB data type.<br />

The following is a discussion of the important concepts you need to know prior to<br />

coding UDFs:<br />

Function Name<br />

v Full name of a function.<br />

The full name of a function using *<strong>SQL</strong> naming is ..<br />

162 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


The full name of a function in *SYS naming is /.<br />

Function names cannot be qualified using *SYS naming in DML statements.<br />

You can use this full name anywhere you refer to a function. For example:<br />

QGPL.SNOWBLOWER_SIZE SMITH.FOO QSYS2.SUBSTR QSYS2.FLOOR<br />

However, you may also omit the ., in which case, <strong>DB2</strong> must<br />

determine the function to which you are referring. For example:<br />

SNOWBLOWER_SIZE FOO SUBSTR FLOOR<br />

v Path<br />

The concept of path is central to <strong>DB2</strong>’s resolution of unqualified references that<br />

occur when schema-name is not specified. For the use of path in DDL statements<br />

that refer to functions, see the description of the corresponding CREATE<br />

FUNCTION statement in the <strong>SQL</strong> Reference. The path is an ordered list of<br />

schema names. It provides a set of schemas <strong>for</strong> resolving unqualified references<br />

to UDFs as well as UDTs. In cases where a function reference matches functions<br />

in more than one schema in the path, the order of the schemas in the path is<br />

used to resolve this match. The path is established by means of the <strong>SQL</strong>PATH<br />

option on the precompile and bind commands <strong>for</strong> static <strong>SQL</strong>. The path is set by<br />

the SET PATH statement <strong>for</strong> dynamic <strong>SQL</strong>. When the first <strong>SQL</strong> statement that<br />

runs in an activation group runs with <strong>SQL</strong> naming, the path has the following<br />

default value:<br />

"QSYS","QSYS2",""<br />

This applies to both static and dynamic <strong>SQL</strong>, where represents the current<br />

statement authorization ID.<br />

When the first <strong>SQL</strong> statement in an activation group runs with system naming,<br />

the default path is *LIBL.<br />

v Overloaded function names.<br />

Function names can be overloaded, which means that multiple functions, even in<br />

the same schema, can have the same name. Two functions cannot, however, have<br />

the same signature, which can be defined to be the qualified function name<br />

concatenated with the defined data types of all the function parameters in the<br />

order in which they are defined. For an example of an overloaded function, see<br />

“Example: BLOB string search” on page 166. See the <strong>SQL</strong> Reference book <strong>for</strong><br />

more in<strong>for</strong>mation on signature and function resolution.<br />

v Function resolution.<br />

It is the function resolution algorithm that takes into account the facts of<br />

overloading and function path to choose the best fit <strong>for</strong> every function reference,<br />

whether it is a qualified or an unqualified reference. All functions, even built-in<br />

functions, are processed through the function selection algorithm.<br />

v Types of function.<br />

There are several types of functions:<br />

– Built-in. These are functions provided by and shipped with the database.<br />

SUBSTR() is an example.<br />

– System-generated. These are functions implicitly generated by the database<br />

engine when a DISTINCT TYPE is created. These functions provide casting<br />

operations between the DISTINCT TYPE and its base type.<br />

– User-defined. These are functions created by users and registered to the<br />

database.<br />

Chapter 8. Using the Object-Relational Capabilities 163


In addition, each function can be further classified as a scalar or column function.<br />

A scalar function returns a single value answer each time it is called. For<br />

example, the built-in function SUBSTR() is a scalar function, as are many built-in<br />

functions. System-generated functions are always scalar functions. Scalar UDFs<br />

can either be external (coded in a programming language such as C, or in<br />

<strong>SQL</strong>—an <strong>SQL</strong> function), or sourced (using the implementation of an existing<br />

function).<br />

A column function receives a set of like values (a column of data) and returns a<br />

single value answer from this set of values. These are also called aggregating<br />

functions in <strong>DB2</strong>. Some built-in functions are column functions. An example of a<br />

column function is the built-in function AVG(). An external UDF cannot be<br />

defined as a column function. However, a sourced UDF is defined to be a<br />

column function if it is sourced on one of the built-in column functions. The<br />

latter is useful <strong>for</strong> distinct types. For example, if a distinct type SHOESIZE exists<br />

that is defined with base type INTEGER, you could define a UDF,<br />

AVG(SHOESIZE), as a column function sourced on the existing built-in column<br />

function, AVG(INTEGER).<br />

The concept of path, the SET PATH statement, and the function resolution<br />

algorithm are discussed in detail in the <strong>SQL</strong> Reference. The <strong>SQL</strong>PATH precompile<br />

option is discussed in the command appendix.<br />

Implementing UDFs<br />

There are three types of UDFs: sourced, external, and <strong>SQL</strong>. The implementation of<br />

each type is considerably different.<br />

v Sourced UDFs. These are simply functions registered to the database that<br />

themselves reference another function. They, in effect, map the sourced function.<br />

As such, nothing more is required in implementing these functions than<br />

registering them to the database using the CREATE FUNCTION statement.<br />

v External functions. These are references to programs and service programs<br />

written in a high level language such as C, COBOL, or RPG. Once the function<br />

is registered to the database, the database will invoke the program or service<br />

program whenever the function is referenced in a DML statement. As such,<br />

external UDFs require that the UDF writer, besides knowing the high level<br />

language and how to develop code in it, must understand the interface between<br />

the program and the database. See “Chapter 9. Writing User-Defined Functions<br />

(UDFs)” on page 189 <strong>for</strong> more in<strong>for</strong>mation on writing external functions.<br />

v <strong>SQL</strong> UDFs. <strong>SQL</strong> UDFs are functions written entirely in the <strong>SQL</strong> language. Their<br />

’code’ is actually <strong>SQL</strong> statements embedded within the CREATE FUNCTION<br />

statement itself. <strong>SQL</strong> UDFs provide several advantages:<br />

– They are written in <strong>SQL</strong>, making them quite portable.<br />

– Defining the interface between the database and the function is by use of <strong>SQL</strong><br />

declares, with no need to worry about details of actual parameter passing.<br />

– They allow the passing of large objects, datalinks, and UDTs as parameters,<br />

and subsequent manipulation of them in the function itself. More in<strong>for</strong>mation<br />

about <strong>SQL</strong> functions can be found in “Chapter 9. Writing User-Defined<br />

Functions (UDFs)” on page 189.<br />

1. Registering the UDF with <strong>DB2</strong>. Regardless of which type of UDF is being<br />

created, they all need to be registered to the database using the CREATE<br />

FUNCTION statement. In the case of source functions, this registration step<br />

does everything necessary to define the function to the database. For <strong>SQL</strong><br />

UDFs, the CREATE FUNCTION statement contains everything necessary to<br />

164 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


define the function as well, except that the syntax of the CREATE statement is<br />

much more complex (contains actual <strong>SQL</strong> executable code). For external UDFs,<br />

the CREATE FUNCTION statement only registers the function to the database;<br />

the supporting code that actually implements the function must be written<br />

separately. See “Registering UDFs” <strong>for</strong> more in<strong>for</strong>mation.<br />

2. Debugging the UDF. See “Chapter 9. Writing User-Defined Functions (UDFs)”<br />

on page 189.<br />

After these steps are successfully completed, your UDF is ready <strong>for</strong> use in data<br />

manipulation language (DML) or data definition language (DDL) statements such<br />

as CREATE VIEW.<br />

Registering UDFs<br />

A UDF must be registered in the database be<strong>for</strong>e the function can be recognized<br />

and used by the database. You can register a UDF using the CREATE FUNCTION<br />

statement.<br />

The statement allows you to specify the language and name of the program, along<br />

with options such as DETERMINISTIC, ALLOW PARALLEL, and RETURNS<br />

NULL ON NULL INPUT. These options help to more specifically identify to the<br />

database the intention of the function and how calls to the database can be<br />

optimized.<br />

You should register the UDF to <strong>DB2</strong> after you have written and completely tested<br />

the actual code. It is possible to define the UDF prior to actually writing it.<br />

However, to avoid any problems with running your UDF, you are encouraged to<br />

write and test it extensively be<strong>for</strong>e registering it. For in<strong>for</strong>mation on testing your<br />

UDF, see “Chapter 9. Writing User-Defined Functions (UDFs)” on page 189.<br />

Examples: Registering UDFs<br />

The examples which follow illustrate a variety of typical situations where UDFs<br />

can be registered. The examples include:<br />

v Example: Exponentiation<br />

v Example: String search<br />

v Example: String search over UDT<br />

v Example: External function with UDT parameter<br />

v Example: AVG over a UDT<br />

v Example: Counting<br />

Example: Exponentiation<br />

Suppose you have written an external UDF to per<strong>for</strong>m exponentiation of floating<br />

point values, and wish to register it in the MATH schema.<br />

CREATE FUNCTION MATH.EXPON (DOUBLE, DOUBLE)<br />

RETURNS DOUBLE<br />

EXTERNAL NAME 'MYLIB/MYPGM(MYENTRY)'<br />

LANGUAGE C<br />

PARAMETER STYLE <strong>DB2</strong><strong>SQL</strong><br />

NO <strong>SQL</strong><br />

DETERMINISTIC<br />

NO EXTERNAL ACTION<br />

RETURNS NULL ON NULL INPUT<br />

ALLOW PARALLEL<br />

Chapter 8. Using the Object-Relational Capabilities 165


In this example, the system uses the RETURNS NULL ON NULL INPUT default<br />

value. This is desirable since you want the result to be NULL if either argument is<br />

NULL. Since you do not require a scratchpad and no final call is necessary, the NO<br />

SCRATCHPAD and NO FINAL CALL default values are used. As there is no<br />

reason why EXPON cannot be parallel, the ALLOW PARALLEL value is specified.<br />

Example: String search<br />

Your associate, Willie, has written a UDF to look <strong>for</strong> the existence of a given short<br />

string, passed as an argument, within a given CLOB value, which is also passed as<br />

an argument. The UDF returns the position of the string within the CLOB if it<br />

finds the string, or zero if it does not.<br />

Additionally, Willie has written the function to return a FLOAT result. Suppose<br />

you know that when it is used in <strong>SQL</strong>, it should always return an INTEGER. You<br />

can create the following function:<br />

CREATE FUNCTION FINDSTRING (CLOB(500K), VARCHAR(200))<br />

RETURNS INTEGER<br />

C<strong>AS</strong>T FROM FLOAT<br />

SPECIFIC "willie_find_feb95"<br />

EXTERNAL NAME 'MYLIB/MYPGM(FINDSTR)'<br />

LANGUAGE C<br />

PARAMETER STYLE <strong>DB2</strong><strong>SQL</strong><br />

NO <strong>SQL</strong><br />

DETERMINISTIC<br />

NO EXTERNAL ACTION<br />

RETURNS NULL ON NULL INPUT<br />

Note that a C<strong>AS</strong>T FROM clause is used to specify that the UDF body really returns<br />

a FLOAT value but you want to cast this to INTEGER be<strong>for</strong>e returning the value to<br />

the statement which used the UDF. As discussed in the <strong>SQL</strong> Reference, the<br />

INTEGER built-in function can per<strong>for</strong>m this cast <strong>for</strong> you. Also, you wish to<br />

provide your own specific name <strong>for</strong> the function and later reference it in DDL (see<br />

“Example: String search over UDT” on page 167). Because the UDF was not written<br />

to handle NULL values, you use the RETURNS NULL ON NULL INPUT. And<br />

because there is no scratchpad, you use the NO SCRATCHPAD and NO FINAL<br />

CALL default values. As there is no reason why FINDSTRING cannot be parallel,<br />

the ALLOW PARALLELISM default value is used.<br />

Example: BLOB string search<br />

Because you want this function to work on BLOBs as well as on CLOBs, you<br />

define another FINDSTRING taking BLOB as the first parameter:<br />

CREATE FUNCTION FINDSTRING (BLOB(500K), VARCHAR(200))<br />

RETURNS INTEGER<br />

C<strong>AS</strong>T FROM FLOAT<br />

SPECIFIC "willie_fblob_feb95"<br />

EXTERNAL NAME 'MYLIB/MYPGM(FINDSTR)'<br />

LANGUAGE C<br />

PARAMETER STYLE <strong>DB2</strong><strong>SQL</strong><br />

NO <strong>SQL</strong><br />

DETERMINISTIC<br />

NO EXTERNAL ACTION<br />

This example illustrates overloading of the UDF name, and shows that multiple<br />

UDFs can share the same body. Note that although a BLOB cannot be assigned to a<br />

CLOB, the same source code can be used. There is no programming problem in the<br />

above example as the programming interface <strong>for</strong> BLOB and CLOB between <strong>DB2</strong><br />

166 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


and UDF is the same; length followed by data. <strong>DB2</strong> does not check if the UDF<br />

using a particular function body is in any way consistent with any other UDF<br />

using the same body.<br />

Example: String search over UDT<br />

This example is a continuation of the previous example. Say you are satisfied with<br />

the FINDSTRING functions from “Example: BLOB string search” on page 166, but<br />

now you have defined a distinct type BOAT with source type BLOB. You also want<br />

FINDSTRING to operate on values having data type BOAT, so you create another<br />

FINDSTRING function. This function is sourced on the FINDSTRING which<br />

operates on BLOB values in “Example: BLOB string search” on page 166. Note the<br />

further overloading of FINDSTRING in this example:<br />

CREATE FUNCTION FINDSTRING (BOAT, VARCHAR(200))<br />

RETURNS INT<br />

SPECIFIC "slick_fboat_mar95"<br />

SOURCE SPECIFIC "willie_fblob_feb95"<br />

Note that this FINDSTRING function has a different signature from the<br />

FINDSTRING functions in “Example: BLOB string search” on page 166, so there is<br />

no problem overloading the name. You wish to provide your own specific name<br />

<strong>for</strong> possible later reference in DDL. Because you are using the SOURCE clause, you<br />

cannot use the EXTERNAL NAME clause or any of the related keywords<br />

specifying function attributes. These attributes are taken from the source function.<br />

Finally, observe that in identifying the source function you are using the specific<br />

function name explicitly provided in “Example: BLOB string search” on page 166.<br />

Because this is an unqualified reference, the schema in which this source function<br />

resides must be in the function path, or the reference will not be resolved.<br />

Example: External function with UDT parameter<br />

You have written another UDF to take a BOAT and examine its design attributes<br />

and generate a cost <strong>for</strong> the boat in Canadian dollars. Even though internally, the<br />

labor cost may be priced in German marks, or Japanese yen, or US dollars, this<br />

function needs to generate the cost to build the boat in the required currency,<br />

Canadian dollars. This means it has to get current exchange rate in<strong>for</strong>mation from<br />

the exchange_rate file, managed outside of <strong>DB2</strong>, and the answer depends on what<br />

it finds in this file. This makes the function NOT DETERMINISTIC.<br />

CREATE FUNCTION BOAT_COST (BOAT)<br />

RETURNS INTEGER<br />

EXTERNAL NAME 'MYLIB/COSTS(BOATCOST)'<br />

LANGUAGE C<br />

PARAMETER STYLE <strong>DB2</strong><strong>SQL</strong><br />

NO <strong>SQL</strong><br />

NOT DETERMINISTIC<br />

NO EXTERNAL ACTION<br />

Observe that C<strong>AS</strong>T FROM and SPECIFIC are not specified, but that NOT<br />

DETERMINISTIC is specified.<br />

Example: AVG over a UDT<br />

This example implements the AVG column function over the<br />

CANADIAN_DOLLAR distinct type. See “Example: Money” on page 175 <strong>for</strong> the<br />

definition of CANADIAN_DOLLAR. Strong typing prevents you from using the<br />

built-in AVG function on a distinct type. It turns out that the source type <strong>for</strong><br />

CANADIAN_DOLLAR was DECIMAL, and so you implement the AVG by<br />

Chapter 8. Using the Object-Relational Capabilities 167


Using UDFs<br />

sourcing it on the AVG(DECIMAL) built-in function. The ability to do this depends<br />

on being able to cast from DECIMAL to CANADIAN_DOLLAR and vice versa,<br />

but since DECIMAL is the source type <strong>for</strong> CANADIAN_DOLLAR you know these<br />

casts will work.<br />

CREATE FUNCTION AVG (CANADIAN_DOLLAR)<br />

RETURNS CANADIAN_DOLLAR<br />

SOURCE "QSYS2".AVG(DECIMAL(9,2))<br />

Note that in the SOURCE clause you have qualified the function name, just in case<br />

there might be some other AVG function lurking in your <strong>SQL</strong> path.<br />

Example: Counting<br />

Your simple counting function returns a 1 the first time and increments the result<br />

by one each time it is called. This function takes no <strong>SQL</strong> arguments, and by<br />

definition it is a NOT DETERMINISTIC function since its answer varies from call<br />

to call. It uses the scratchpad to save the last value returned, and each time it is<br />

invoked it increments this value and returns it.<br />

CREATE FUNCTION COUNTER ()<br />

RETURNS INT<br />

EXTERNAL NAME 'MYLIB/MYFUNCS(CTR)'<br />

LANGUAGE C<br />

PARAMETER STYLE <strong>DB2</strong><strong>SQL</strong><br />

NO <strong>SQL</strong><br />

NOT DETERMINISTIC<br />

NOT FENCED<br />

SCRATCHPAD 4<br />

DISALLOW PARALLEL<br />

Note that no parameter definitions are provided, just empty parentheses. The<br />

above function specifies SCRATCHPAD, and uses the default specification of NO<br />

FINAL CALL. In this case, the size of the scratchpad is set to only 4 bytes, which<br />

is sufficient <strong>for</strong> a counter. Since the COUNTER function requires that a single<br />

scratchpad be used to operate properly, DISALLOW PARALLEL is added to<br />

prevent <strong>DB2</strong> from operating it in parallel.<br />

Scalar and column UDFs can be invoked within an <strong>SQL</strong> statement almost<br />

everywhere that an expression is valid. There are a few restrictions of UDF usage,<br />

however:<br />

v UDFs and system generated functions cannot be specified in check constraints.<br />

Check constraints also cannot contain references to the built-in functions<br />

DLVALUE, DLURLPATH, DLURLPATHONLY, DLURLSCHEME,<br />

DLURLCOMPLETE, or DLURLSERVER.<br />

v External UDFs, <strong>SQL</strong> UDFS and the built-in functions DLVALUE, DLURLPATH,<br />

DLURLPATHONLY, DLURLSCHEME, DLURLCOMPLETE, and DLURLSERVER<br />

cannot be referenced in an ORDER BY or GROUP BY clause, unless the <strong>SQL</strong><br />

statement is read-only and allows temporary processing (ALWCPYDTA(*YES) or<br />

(*OPTIMIZE).<br />

The <strong>SQL</strong> Reference discusses all these contexts in detail. The discussion and<br />

examples used in this section focus on relatively simple SELECT statement<br />

contexts, but note that their use is not restricted to these contexts.<br />

Refer to “UDF concepts” on page 162 <strong>for</strong> a summary of the use and importance of<br />

the path and the function resolution algorithm. You can find the details <strong>for</strong> both of<br />

168 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


these concepts in the <strong>SQL</strong> Reference. The resolution of any Data Manipulation<br />

Language (DML) reference to a function uses the function resolution algorithm, so<br />

it is important to understand how it works.<br />

Referring to functions<br />

Each reference to a function, whether it is a UDF, or a built-in function, contains<br />

the following syntax:<br />

►►<br />

function_name ( )<br />

ALL<br />

DISTINCT<br />

,<br />

▼ expression<br />

In the above, function_name can be either an unqualified or a qualified function<br />

name. Note that when using the *SYS naming convention, functions cannot be<br />

qualified. The arguments can number from 0 to 90, and are expressions which may<br />

contain:<br />

v A column name, qualified or unqualified<br />

v A constant<br />

v A host variable<br />

v A special register<br />

v A parameter marker with a C<strong>AS</strong>T function<br />

v An expression<br />

v A function<br />

The position of the arguments is important and must con<strong>for</strong>m to the function<br />

definition <strong>for</strong> the semantics to be correct. Both the position of the arguments and<br />

the function definition must con<strong>for</strong>m to the function body itself. <strong>DB2</strong> does not<br />

attempt to shuffle arguments to better match a function definition, and <strong>DB2</strong> does<br />

not attempt to determine the semantics of the individual function parameters.<br />

Examples of function invocations<br />

Some valid examples of function invocations are:<br />

AVG(FLOAT_COLUMN)<br />

BLOOP(COLUMN1)<br />

BLOOP(FLOAT_COLUMN + C<strong>AS</strong>T(? <strong>AS</strong> INTEGER))<br />

BLOOP(:hostvar :indicvar)<br />

BRIAN.PARSE(CONCAT(CHAR_COLUMN,USER, 1, 0, 0, 1)<br />

CTR()<br />

FLOOR(FLOAT_COLUMN)<br />

PABLO.BLOOP(A+B)<br />

PABLO.BLOOP(:hostvar)<br />

"search_schema"(CURRENT PATH, 'GENE')<br />

SUBSTR(COLUMN2,8,3)<br />

QSYS2.FLOOR(AVG(EMP.SALARY))<br />

QSYS2.AVG(QSYS2.FLOOR(EMP.SALARY))<br />

QSYS2.SUBSTR(COLUMN2,11,LENGTH(COLUMN3))<br />

Using parameter markers in functions<br />

An important restriction involves parameter markers; you cannot simply code the<br />

following:<br />

BLOOP(?)<br />

Chapter 8. Using the Object-Relational Capabilities 169<br />

►◄


As the function selection logic does not know what data type the argument may<br />

turn out to be, it cannot resolve the reference. You can use the C<strong>AS</strong>T specification<br />

to provide a type <strong>for</strong> the parameter marker, <strong>for</strong> example INTEGER, and then the<br />

function selection logic can proceed:<br />

BLOOP(C<strong>AS</strong>T(? <strong>AS</strong> INTEGER))<br />

Using qualified function reference<br />

If you use a qualified function reference, you restrict <strong>DB2</strong>’s search <strong>for</strong> a matching<br />

function to that schema. For example, you have the following statement:<br />

SELECT PABLO.BLOOP(COLUMN1) FROM T<br />

Only the BLOOP functions in schema PABLO are considered. It does not matter<br />

that user SERGE has defined a BLOOP function, or whether or not there is a<br />

built-in BLOOP function. Now suppose that user PABLO has defined two BLOOP<br />

functions in his schema:<br />

CREATE FUNCTION BLOOP (INTEGER) RETURNS ...<br />

CREATE FUNCTION BLOOP (DOUBLE) RETURNS ...<br />

BLOOP is thus overloaded within the PABLO schema, and the function selection<br />

algorithm would choose the best BLOOP, depending on the data type of the<br />

argument, column1. In this case, both of the PABLO.BLOOPs take numeric<br />

arguments, and if column1 is not one of the numeric types, the statement will fail.<br />

On the other hand if column1 is either SMALLINT or INTEGER, function selection<br />

will resolve to the first BLOOP, while if column1 is DECIMAL or DOUBLE, the<br />

second BLOOP will be chosen.<br />

Several points about this example:<br />

1. It illustrates argument promotion. The first BLOOP is defined with an<br />

INTEGER parameter, yet you can pass it a SMALLINT argument. The function<br />

selection algorithm supports promotions among the built-in data types (<strong>for</strong><br />

details, see the <strong>SQL</strong> Reference) and <strong>DB2</strong> per<strong>for</strong>ms the appropriate data value<br />

conversions.<br />

2. If <strong>for</strong> some reason you want to invoke the second BLOOP with a SMALLINT<br />

or INTEGER argument, you have to take an explicit action in your statement as<br />

follows:<br />

SELECT PABLO.BLOOP(DOUBLE(COLUMN1)) FROM T<br />

3. Alternatively, if you want to invoke the first BLOOP with a DECIMAL or<br />

DOUBLE argument, you have your choice of explicit actions, depending on<br />

your exact intent:<br />

SELECT PABLO.BLOOP(INTEGER(COLUMN1)) FROM T<br />

SELECT PABLO.BLOOP(FLOOR(COLUMN1)) FROM T<br />

You should investigate these other functions in the <strong>SQL</strong> Reference. The<br />

INTEGER function is a built-in function in the QSYS2 schema.<br />

Using unqualified function reference<br />

If, instead of a qualified function reference, you use an unqualified function<br />

reference, <strong>DB2</strong>’s search <strong>for</strong> a matching function normally uses the function path to<br />

qualify the reference. In the case of the DROP FUNCTION or COMMENT ON<br />

FUNCTION functions, the reference is qualified using the current authorization ID,<br />

if they are unqualified <strong>for</strong> *<strong>SQL</strong> naming, or *LIBL <strong>for</strong> *SYS naming. Thus, it is<br />

important that you know what your function path is, and what, if any, conflicting<br />

170 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


functions exist in the schemas of your current function path. For example, suppose you<br />

are PABLO and your static <strong>SQL</strong> statement is as follows, where COLUMN1 is data type<br />

INTEGER:<br />

SELECT BLOOP(COLUMN1) FROM T<br />

You have created the two BLOOP functions cited in “Using qualified function<br />

reference” on page 170, and you want and expect one of them to be chosen. If the<br />

following default function path is used, the first BLOOP is chosen (since column1<br />

is INTEGER), if there is no conflicting BLOOP in QSYS or QSYS2:<br />

"QSYS","QSYS2","PABLO"<br />

However, suppose you have <strong>for</strong>gotten that you are using a script <strong>for</strong> precompiling<br />

and binding which you previously wrote <strong>for</strong> another purpose. In this script, you<br />

explicitly coded your <strong>SQL</strong>PATH parameter to specify the following function path<br />

<strong>for</strong> another reason that does not apply to your current work:<br />

"KATHY","QSYS","QSYS2","PABLO"<br />

If Kathy has written a BLOOP function <strong>for</strong> her own purposes, the function<br />

selection could very well resolve to Kathy’s function, and your statement would<br />

execute without error. You are not notified because <strong>DB2</strong> assumes that you know<br />

what you are doing. It becomes your responsibility to identify the incorrect output<br />

from your statement and make the required correction.<br />

Summary of function references<br />

For both qualified and unqualified function references, the function selection<br />

algorithm looks at all the applicable functions, both built-in and user-defined, that<br />

have:<br />

v The given name<br />

v The same number of defined parameters as arguments in the function reference<br />

v Each parameter identical to or promotable from the type of the corresponding<br />

argument.<br />

(Applicable functions means functions in the named schema <strong>for</strong> a qualified reference, or<br />

functions in the schemas of the function path <strong>for</strong> an unqualified reference.) The<br />

algorithm looks <strong>for</strong> an exact match, or failing that, a best match among these<br />

functions. The current function path is used, in the case of an unqualified reference<br />

only, as the deciding factor if two identically good matches are found in different<br />

schemas. The details of the algorithm can be found in the <strong>SQL</strong> Reference.<br />

An interesting feature, illustrated by the examples at the end of “Using qualified<br />

function reference” on page 170, is the fact that function references can be nested, even<br />

references to the same function. This is generally true <strong>for</strong> built-in functions as well<br />

as UDFs; however, there are some limitations when column functions are involved.<br />

Refining an earlier example:<br />

CREATE FUNCTION BLOOP (INTEGER) RETURNS INTEGER ...<br />

CREATE FUNCTION BLOOP (DOUBLE) RETURNS INTEGER ...<br />

Now consider the following DML statement:<br />

SELECT BLOOP(BLOOP(COLUMN1)) FROM T<br />

If column1 is a DECIMAL or DOUBLE column, the inner BLOOP reference<br />

resolves to the second BLOOP defined above. Because this BLOOP returns an<br />

INTEGER, the outer BLOOP resolves to the first BLOOP.<br />

Chapter 8. Using the Object-Relational Capabilities 171


Alternatively, if column1 is a SMALLINT or INTEGER column, the inner bloop<br />

reference resolves to the first BLOOP defined above. Because this BLOOP returns<br />

an INTEGER, the outer BLOOP also resolves to the first BLOOP. In this case, you<br />

are seeing nested references to the same function.<br />

A few additional points important <strong>for</strong> function references are:<br />

v You can define a function with the name of one of the <strong>SQL</strong> operators. For<br />

example, suppose you can attach some meaning to the "+" operator <strong>for</strong> values<br />

which have distinct type BOAT. You can define the following UDF:<br />

CREATE FUNCTION "+" (BOAT, BOAT) RETURNS ...<br />

Then you can write the following valid <strong>SQL</strong> statement:<br />

SELECT "+"(BOAT_COL1, BOAT_COL2)<br />

FROM BIG_BOATS<br />

WHERE BOAT_OWNER = 'Nelson Mattos'<br />

Note that you are not permitted to overload the built-in conditional operators<br />

such as >, =, LIKE, IN, and so on, in this way.<br />

v The function selection algorithm does not consider the context of the reference in<br />

resolving to a particular function. Look at these BLOOP functions, modified a bit<br />

from be<strong>for</strong>e:<br />

CREATE FUNCTION BLOOP (INTEGER) RETURNS INTEGER ...<br />

CREATE FUNCTION BLOOP (DOUBLE) RETURNS CHAR(10)...<br />

Now suppose you write the following SELECT statement:<br />

SELECT 'ABCDEFG' CONCAT BLOOP(SMALLINT_COL) FROM T<br />

v<br />

Because the best match, resolved using the SMALLINT argument, is the first<br />

BLOOP defined above, the second operand of the CONCAT resolves to data<br />

type INTEGER. The statement fails because CONCAT demands string<br />

arguments. If the first BLOOP was not present, the other BLOOP would be<br />

chosen and the statement execution would be successful.<br />

UDFs can be defined with parameters or results having any of the LOB types:<br />

BLOB, CLOB, or DBCLOB. <strong>DB2</strong> will materialize the entire LOB value in storage<br />

be<strong>for</strong>e invoking such a function, even if the source of the value is a LOB locator<br />

host variable. For example, consider the following fragment of a C language<br />

application:<br />

EXEC <strong>SQL</strong> BEGIN DECLARE SECTION;<br />

<strong>SQL</strong> TYPE IS CLOB(150K) clob150K ; /* LOB host var */<br />

<strong>SQL</strong> TYPE IS CLOB_LOCATOR clob_locator1; /* LOB locator host var */<br />

char string[40]; /* string host var */<br />

EXEC <strong>SQL</strong> END DECLARE SECTION;<br />

Either host variable :clob150K or :clob_locator1 is valid as an argument <strong>for</strong> a<br />

function whose corresponding parameter is defined as CLOB(500K). Thus,<br />

referring to the FINDSTRING defined in “Example: String search” on page 166,<br />

both of the following are valid in the program:<br />

... SELECT FINDSTRING (:clob150K, :string) FROM ...<br />

... SELECT FINDSTRING (:clob_locator1, :string) FROM ...<br />

v Non-<strong>SQL</strong> UDF parameters or results which have one of the LOB types can be<br />

created with the <strong>AS</strong> LOCATOR modifier. In this case, the entire LOB value is not<br />

materialized prior to invocation. Instead, a LOB LOCATOR is passed to the UDF.<br />

You can also use this capability on UDF parameters or results which have a<br />

distinct type that is based on a LOB. This capability is limited to non-<strong>SQL</strong> UDFs.<br />

Note that the argument to such a function can be any LOB value of the defined<br />

172 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


type; it does not have to be a host variable defined as one of the LOCATOR<br />

types. The use of host variable locators as arguments is completely unrelated to<br />

the use of <strong>AS</strong> LOCATOR in UDF parameters and result definitions.<br />

v UDFs can be defined with distinct types as parameters or as the result. (Earlier<br />

examples have illustrated this.) <strong>DB2</strong> will pass the value to the UDF in the <strong>for</strong>mat<br />

of the source data type of the distinct type.<br />

Distinct type values which originate in a host variable and which are used as<br />

arguments to a UDF which has its corresponding parameter defined as a distinct<br />

type, must be explicitly cast to the distinct type by the user. There is no host<br />

language type <strong>for</strong> distinct types. <strong>DB2</strong>’s strong typing necessitates this. Otherwise<br />

your results may be ambiguous. So, consider the BOAT distinct type which is<br />

defined over a BLOB, and consider the BOAT_COST UDF from “Example:<br />

External function with UDT parameter” on page 167, which takes an object of<br />

type BOAT as its argument. In the following fragment of a C language<br />

application, the host variable :ship holds the BLOB value that is to passed to<br />

the BOAT_COST function:<br />

EXEC <strong>SQL</strong> BEGIN DECLARE SECTION;<br />

<strong>SQL</strong> TYPE IS BLOB(150K) ship;<br />

EXEC <strong>SQL</strong> END DECLARE SECTION;<br />

Both of the following statements correctly resolve to the BOAT_COST function,<br />

because both cast the :ship host variable to type BOAT:<br />

... SELECT BOAT_COST (BOAT(:ship)) FROM ...<br />

... SELECT BOAT_COST (C<strong>AS</strong>T(:ship <strong>AS</strong> BOAT)) FROM ...<br />

If there are multiple BOAT distinct types in the database, or BOAT UDFs in<br />

other schema, you must exercise care with your function path. Otherwise your<br />

results may be ambiguous.<br />

User-defined distinct types (UDT)<br />

A user-defined distinct type is a mechanism that allows you to extend <strong>DB2</strong><br />

capabilities beyond the built-in data types available. User-defined distinct types<br />

enable you to define new data types to <strong>DB2</strong> which gives you considerable power<br />

since you are no longer restricted to using the system-supplied built-in data types<br />

to model your business and capture the semantics of your data. Distinct data types<br />

allow you to map on a one-to-one basis to existing database types.<br />

The following topics describe UDTs in more detail:<br />

v “Why use UDTs?”<br />

v “Defining a UDT” on page 174<br />

v “Defining tables with UDTs” on page 175<br />

v “Manipulating UDTs” on page 176<br />

v “Synergy between UDTs, UDFs, and LOBs” on page 181<br />

Why use UDTs?<br />

There are several benefits associated with UDTs:<br />

1. Extensibility.<br />

By defining new types, you can indefinitely increase the set of types provided<br />

by <strong>DB2</strong> to support your applications.<br />

Chapter 8. Using the Object-Relational Capabilities 173


2. Flexibility.<br />

You can specify any semantics and behavior <strong>for</strong> your new type by using<br />

user-defined functions (UDFs) to augment the diversity of the types available in<br />

the system.<br />

3. Consistent behavior.<br />

Strong typing insures that your UDTs will behave appropriately. It guarantees<br />

that only functions defined on your UDT can be applied to instances of the<br />

UDT.<br />

4. Encapsulation.<br />

The behavior of your UDTs is restricted by the functions and operators that can<br />

be applied on them. This provides flexibility in the implementation since<br />

running applications do not depend on the internal representation that you<br />

chose <strong>for</strong> your type.<br />

5. Extensible behavior.<br />

The definition of user-defined functions on types can augment the functionality<br />

provided to manipulate your UDT at any time. (See “User-defined functions<br />

(UDF)” on page 160)<br />

6. Foundation <strong>for</strong> object-oriented extensions.<br />

UDTs are the foundation <strong>for</strong> most object-oriented features. They represent the<br />

most important step towards object-oriented extensions.<br />

Defining a UDT<br />

UDTs, like other objects such as tables, indexes, and UDFs, need to be defined with<br />

a CREATE statement.<br />

Use the CREATE DISTINCT TYPE statement to define your new UDT. Detailed<br />

explanations <strong>for</strong> the statement syntax and all its options are found in the <strong>SQL</strong><br />

Reference.<br />

For the CREATE DISTINCT TYPE statement, note that:<br />

1. The name of the new UDT can be a qualified or an unqualified name.<br />

2. The source type of the UDT is the type used by <strong>DB2</strong> to internally represent the<br />

UDT. For this reason, it must be a built-in data type. Previously defined UDTs<br />

cannot be used as source types of other UDTs.<br />

As part of a UDT definition, <strong>DB2</strong> always generates cast functions to:<br />

v Cast from the UDT to the source type, using the standard name of the source<br />

type. For example, if you create a distinct type based on FLOAT, the cast<br />

function called DOUBLE is created.<br />

v Cast from the source type to the UDT. See the <strong>SQL</strong> Reference <strong>for</strong> a discussion of<br />

when additional casts to the UDTs are generated.<br />

These functions are important <strong>for</strong> the manipulation of UDTs in queries.<br />

Resolving unqualified UDTs<br />

The function path is used to resolve any references to an unqualified type name or<br />

function, except if the type name or function is<br />

v Created<br />

v Dropped<br />

v Commented on.<br />

174 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


For in<strong>for</strong>mation on how unqualified function references are resolved, see “Using<br />

qualified function reference” on page 170.<br />

Examples: Using CREATE DISTINCT TYPE<br />

The following are examples of using CREATE DISTINCT TYPE:<br />

v Example: Money<br />

v Example: Resume<br />

Example: Money<br />

Suppose you are writing applications that need to handle different currencies and<br />

wish to ensure that <strong>DB2</strong> does not allow these currencies to be compared or<br />

manipulated directly with one another in queries. Remember that conversions are<br />

necessary whenever you want to compare values of different currencies. So you<br />

define as many UDTs as you need; one <strong>for</strong> each currency that you may need to<br />

represent:<br />

CREATE DISTINCT TYPE US_DOLLAR <strong>AS</strong> DECIMAL (9,2)<br />

CREATE DISTINCT TYPE CANADIAN_DOLLAR <strong>AS</strong> DECIMAL (9,2)<br />

CREATE DISTINCT TYPE GERMAN_MARK <strong>AS</strong> DECIMAL (9,2)<br />

Example: Resume<br />

Suppose you would like to keep the <strong>for</strong>m filled by applicants to your company in<br />

a <strong>DB2</strong> table and you are going to use functions to extract the in<strong>for</strong>mation from<br />

these <strong>for</strong>ms. Because these functions cannot be applied to regular character strings<br />

(because they are certainly not able to find the in<strong>for</strong>mation they are supposed to<br />

return), you define a UDT to represent the filled <strong>for</strong>ms:<br />

CREATE DISTINCT TYPE PERSONAL.APPLICATION_FORM <strong>AS</strong> CLOB(32K)<br />

Defining tables with UDTs<br />

After you have defined several UDTs, you can start defining tables with columns<br />

whose types are UDTs. Following are examples using CREATE TABLE:<br />

v Example: Sales<br />

v Example: Application <strong>for</strong>ms<br />

Example: Sales<br />

Suppose you want to define tables to keep your company’s sales in different<br />

countries as follows:<br />

CREATE TABLE US_SALES<br />

(PRODUCT_ITEM INTEGER,<br />

MONTH INTEGER CHECK (MONTH BETWEEN 1 AND 12),<br />

YEAR INTEGER CHECK (YEAR > 1985),<br />

TOTAL US_DOLLAR)<br />

CREATE TABLE CANADIAN_SALES<br />

(PRODUCT_ITEM INTEGER,<br />

MONTH INTEGER CHECK (MONTH BETWEEN 1 AND 12),<br />

YEAR INTEGER CHECK (YEAR > 1985),<br />

TOTAL CANADIAN_DOLLAR)<br />

CREATE TABLE GERMAN_SALES<br />

(PRODUCT_ITEM INTEGER,<br />

MONTH INTEGER CHECK (MONTH BETWEEN 1 AND 12),<br />

YEAR INTEGER CHECK (YEAR > 1985),<br />

TOTAL GERMAN_MARK)<br />

Chapter 8. Using the Object-Relational Capabilities 175


The UDTs in the above examples are created using the same CREATE DISTINCT<br />

TYPE statements in “Example: Money” on page 175. Note that the above examples<br />

use check constraints. For in<strong>for</strong>mation on check constraints see the <strong>SQL</strong> Reference.<br />

Example: Application <strong>for</strong>ms<br />

Suppose you need to define a table where you keep the <strong>for</strong>ms filled out by<br />

applicants as follows:<br />

CREATE TABLE APPLICATIONS<br />

(ID INTEGER,<br />

NAME VARCHAR (30),<br />

APPLICATION_DATE DATE,<br />

FORM PERSONAL.APPLICATION_FORM)<br />

You have fully qualified the UDT name because its qualifier is not the same as<br />

your authorization ID and you have not changed the default function path.<br />

Remember that whenever type and function names are not fully qualified, <strong>DB2</strong><br />

searches through the schemas listed in the current function path and looks <strong>for</strong> a<br />

type or function name matching the given unqualified name.<br />

.<br />

Manipulating UDTs<br />

One of the most important concepts associated with UDTs is strong typing. Strong<br />

typing guarantees that only functions and operators defined on the UDT can be<br />

applied to its instances.<br />

Strong typing is important to ensure that the instances of your UDTs are correct.<br />

For example, if you have defined a function to convert US dollars to Canadian<br />

dollars according to the current exchange rate, you do not want this same function<br />

to be used to convert German marks to Canadian dollars because it will certainly<br />

return the wrong amount.<br />

As a consequence of strong typing, <strong>DB2</strong> does not allow you to write queries that<br />

compare, <strong>for</strong> example, UDT instances with instances of the UDT source type. For<br />

the same reason, <strong>DB2</strong> will not let you apply functions defined on other types to<br />

UDTs. If you want to compare instances of UDTs with instances of another type,<br />

you have to cast the instances of one or the other type. In the same sense, you<br />

have to cast the UDT instance to the type of the parameter of a function that is not<br />

defined on a UDT if you want to apply this function to a UDT instance.<br />

Examples of manipulating UDTs<br />

The following are examples of manipulating UDTs:<br />

v Example: Comparisons between UDTs and constants<br />

v Example: Casting between UDTs<br />

v Example: Comparisons involving UDTs<br />

v Example: Sourced UDFs involving UDTs<br />

v Example: Assignments involving UDTs<br />

v Example: Assignments in dynamic <strong>SQL</strong><br />

v Example: Assignments involving different UDTs<br />

v Example: Use of UDTs in UNION<br />

176 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


Example: Comparisons between UDTs and constants<br />

Suppose you want to know which products sold more than US $100 000.00 in the<br />

US in the month of July, 1992 (7/92).<br />

SELECT PRODUCT_ITEM<br />

FROM US_SALES<br />

WHERE TOTAL > US_DOLLAR (100000)<br />

AND month = 7<br />

AND year = 1992<br />

Because you cannot compare US dollars with instances of the source type of US<br />

dollars (that is, DECIMAL) directly, you have used the cast function provided by<br />

<strong>DB2</strong> to cast from DECIMAL to US dollars. You can also use the other cast function<br />

provided by <strong>DB2</strong> (that is, the one to cast from US dollars to DECIMAL) and cast<br />

the column total to DECIMAL. Either way you decide to cast, from or to the UDT,<br />

you can use the cast specification notation to per<strong>for</strong>m the casting, or the functional<br />

notation. That is, you could have written the above query as:<br />

SELECT PRODUCT_ITEM<br />

FROM US_SALES<br />

WHERE TOTAL > C<strong>AS</strong>T (100000 <strong>AS</strong> us_dollar)<br />

AND MONTH = 7<br />

AND YEAR = 1992<br />

Example: Casting between UDTs<br />

Suppose you want to define a UDF that converts Canadian dollars to U.S. dollars.<br />

Suppose you can obtain the current exchange rate from a file managed outside of<br />

<strong>DB2</strong>. You would then define a UDF that obtains a value in Canadian dollars,<br />

accesses the exchange rate file, and returns the corresponding amount in U.S.<br />

dollars.<br />

At first glance, such a UDF may appear easy to write. However, not all C<br />

compilers support DECIMAL values. The UDTs representing different currencies<br />

have been defined as DECIMAL. Your UDF will need to receive and return<br />

DOUBLE values, since this is the only data type provided by C that allows the<br />

representation of a DECIMAL value without losing the decimal precision. Thus,<br />

your UDF should be defined as follows:<br />

CREATE FUNCTION CDN_TO_US_DOUBLE(DOUBLE) RETURNS DOUBLE<br />

EXTERNAL NAME 'MYLIB/CURRENCIES(C_CDN_US)'<br />

LANGUAGE C<br />

PARAMETER STYLE <strong>DB2</strong><strong>SQL</strong><br />

NO <strong>SQL</strong><br />

NOT DETERMINISTIC<br />

The exchange rate between Canadian and U.S. dollars may change between two<br />

invocations of the UDF, so you declare it as NOT DETERMINISTIC.<br />

The question now is, how do you pass Canadian dollars to this UDF and get U.S.<br />

dollars from it? The Canadian dollars must be cast to DECIMAL values. The<br />

DECIMAL values must be cast to DOUBLE. You also need to have the returned<br />

DOUBLE value cast to DECIMAL and the DECIMAL value cast to U.S. dollars.<br />

Such casts are per<strong>for</strong>med automatically by <strong>DB2</strong> anytime you define sourced UDFs,<br />

whose parameter and return type do not exactly match the parameter and return<br />

type of the source function. There<strong>for</strong>e, you need to define two sourced UDFs. The<br />

first brings the DOUBLE values to a DECIMAL representation. The second brings<br />

the DECIMAL values to the UDT. That is, you define the following:<br />

Chapter 8. Using the Object-Relational Capabilities 177


CREATE FUNCTION CDN_TO_US_DEC (DECIMAL(9,2)) RETURNS DECIMAL(9,2)<br />

SOURCE CDN_TO_US_DOUBLE (DOUBLE)<br />

CREATE FUNCTION US_DOLLAR (CANADIAN_DOLLAR) RETURNS US_DOLLAR<br />

SOURCE CDN_TO_US_DEC (DECIMAL())<br />

Note that an invocation of the US_DOLLAR function as in US_DOLLAR(C1), where C1 is<br />

a column whose type is Canadian dollars, has the same effect as invoking:<br />

US_DOLLAR (DECIMAL(CDN_TO_US_DOUBLE (DOUBLE (DECIMAL (C1)))))<br />

That is, C1 (in Canadian dollars) is cast to decimal which in turn is cast to a<br />

double value that is passed to the CDN_TO_US_DOUBLE function. This function<br />

accesses the exchange rate file and returns a double value (representing the<br />

amount in U.S. dollars) that is cast to decimal, and then to U.S. dollars.<br />

A function to convert German marks to U.S. dollars would be similar to the<br />

example above:<br />

CREATE FUNCTION GERMAN_TO_US_DOUBLE(DOUBLE)<br />

RETURNS DOUBLE<br />

EXTERNAL NAME 'MYLIB/CURRENCIES(C_GER_US)'<br />

LANGUAGE C<br />

PARAMETER STYLE <strong>DB2</strong><strong>SQL</strong><br />

NO <strong>SQL</strong><br />

NOT DETERMINISTIC<br />

CREATE FUNCTION GERMAN_TO_US_DEC (DECIMAL(9,2))<br />

RETURNS DECIMAL(9,2)<br />

SOURCE GERMAN_TO_US_DOUBLE(DOUBLE)<br />

CREATE FUNCTION US_DOLLAR(GERMAN_MARK) RETURNS US_DOLLAR<br />

SOURCE GERMAN_TO_US_DEC (DECIMAL())<br />

Example: Comparisons involving UDTs<br />

Suppose you want to know which products sold more in the US than in Canada<br />

and Germany <strong>for</strong> the month of March, 1989 (3/89):<br />

SELECT US.PRODUCT_ITEM, US.TOTAL<br />

FROM US_SALES <strong>AS</strong> US, CANADIAN_SALES <strong>AS</strong> CDN, GERMAN_SALES <strong>AS</strong> GERMAN<br />

WHERE US.PRODUCT_ITEM = CDN.PRODUCT_ITEM<br />

AND US.PRODUCT_ITEM = GERMAN.PRODUCT_ITEM<br />

AND US.TOTAL > US_DOLLAR (CDN.TOTAL)<br />

AND US.TOTAL > US_DOLLAR (GERMAN.TOTAL)<br />

AND US.MONTH = 3<br />

AND US.YEAR = 1989<br />

AND CDN.MONTH = 3<br />

AND CDN.YEAR = 1989<br />

AND GERMAN.MONTH = 3<br />

AND GERMAN.YEAR = 1989<br />

Because you cannot directly compare US dollars with Canadian dollars or German<br />

Marks, you use the UDF to cast the amount in Canadian dollars to US dollars, and<br />

the UDF to cast the amount in German Marks to US dollars. You cannot cast them<br />

all to DECIMAL and compare the converted DECIMAL values because the<br />

amounts are not monetarily comparable. That is, the amounts are not in the same<br />

currency.<br />

Example: Sourced UDFs involving UDTs<br />

Suppose you have defined a sourced UDF on the built-in SUM function to support<br />

SUM on German Marks:<br />

178 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


CREATE FUNCTION SUM (GERMAN_MARKS)<br />

RETURNS GERMAN_MARKS<br />

SOURCE SYSIBM.SUM (DECIMAL())<br />

You want to know the total of sales in Germany <strong>for</strong> each product in the year of<br />

1994. You would like to obtain the total sales in US dollars:<br />

SELECT PRODUCT_ITEM, US_DOLLAR (SUM (TOTAL))<br />

FROM GERMAN_SALES<br />

WHERE YEAR = 1994<br />

GROUP BY PRODUCT_ITEM<br />

You could not write SUM (us_dollar (total)), unless you had defined a SUM<br />

function on US dollar in a manner similar to the above.<br />

Example: Assignments involving UDTs<br />

Suppose you want to store the <strong>for</strong>m filled by a new applicant into the database.<br />

You have defined a host variable containing the character string value used to<br />

represent the filled <strong>for</strong>m:<br />

EXEC <strong>SQL</strong> BEGIN DECLARE SECTION;<br />

<strong>SQL</strong> TYPE IS CLOB(32K) hv_<strong>for</strong>m;<br />

EXEC <strong>SQL</strong> END DECLARE SECTION;<br />

/* Code to fill hv_<strong>for</strong>m */<br />

INSERT INTO APPLICATIONS<br />

VALUES (134523, 'Peter Holland', CURRENT DATE, :hv_<strong>for</strong>m)<br />

You do not explicitly invoke the cast function to convert the character string to the<br />

UDT personal.application_<strong>for</strong>m . This is because <strong>DB2</strong> lets you assign instances of<br />

the source type of a UDT to targets having that UDT.<br />

Example: Assignments in dynamic <strong>SQL</strong><br />

If you want to use the same statement given in “Example: Assignments involving<br />

UDTs” in dynamic <strong>SQL</strong>, you can use parameter markers as follows:<br />

EXEC <strong>SQL</strong> BEGIN DECLARE SECTION;<br />

long id;<br />

char name[30];<br />

<strong>SQL</strong> TYPE IS CLOB(32K) <strong>for</strong>m;<br />

char command[80];<br />

EXEC <strong>SQL</strong> END DECLARE SECTION;<br />

/* Code to fill host variables */<br />

strcpy(command,"INSERT INTO APPLICATIONS VALUES");<br />

strcat(command,"(?, ?, CURRENT DATE, ?)");<br />

EXEC <strong>SQL</strong> PREPARE APP_INSERT FROM :command;<br />

EXEC <strong>SQL</strong> EXECUTE APP_INSERT USING :id, :name, :<strong>for</strong>m;<br />

You made use of <strong>DB2</strong>’s cast specification to tell <strong>DB2</strong> that the type of the parameter<br />

marker is CLOB(32K), a type that is assignable to the UDT column. Remember that<br />

you cannot declare a host variable of a UDT type, since host languages do not<br />

support UDTs. There<strong>for</strong>e, you cannot specify that the type of a parameter marker<br />

is a UDT.<br />

Chapter 8. Using the Object-Relational Capabilities 179


Example: Assignments involving different UDTs<br />

Suppose you have defined two sourced UDFs on the built-in SUM function to<br />

support SUM on US and Canadian dollars, similar to the UDF sourced on German<br />

Marks in “Example: Sourced UDFs involving UDTs” on page 178:<br />

CREATE FUNCTION SUM (CANADIAN_DOLLAR)<br />

RETURNS CANADIAN_DOLLAR<br />

SOURCE SYSIBM.SUM (DECIMAL())<br />

CREATE FUNCTION SUM (US_DOLLAR)<br />

RETURNS US_DOLLAR<br />

SOURCE SYSIBM.SUM (DECIMAL())<br />

Now suppose your supervisor requests that you maintain the annual total sales in<br />

US dollars of each product and in each country, in separate tables:<br />

CREATE TABLE US_SALES_94<br />

(PRODUCT_ITEM INTEGER,<br />

TOTAL US_DOLLAR)<br />

CREATE TABLE GERMAN_SALES_94<br />

(PRODUCT_ITEM INTEGER,<br />

TOTAL US_DOLLAR)<br />

CREATE TABLE CANADIAN_SALES_94<br />

(PRODUCT_ITEM INTEGER,<br />

TOTAL US_DOLLAR)<br />

INSERT INTO US_SALES_94<br />

SELECT PRODUCT_ITEM, SUM (TOTAL)<br />

FROM US_SALES<br />

WHERE YEAR = 1994<br />

GROUP BY PRODUCT_ITEM<br />

INSERT INTO GERMAN_SALES_94<br />

SELECT PRODUCT_ITEM, US_DOLLAR (SUM (TOTAL))<br />

FROM GERMAN_SALES<br />

WHERE YEAR = 1994<br />

GROUP BY PRODUCT_ITEM<br />

INSERT INTO CANADIAN_SALES_94<br />

SELECT PRODUCT_ITEM, US_DOLLAR (SUM (TOTAL))<br />

FROM CANADIAN_SALES<br />

WHERE YEAR = 1994<br />

GROUP BY PRODUCT_ITEM<br />

You explicitly cast the amounts in Canadian dollars and German Marks to US<br />

dollars since different UDTs are not directly assignable to each other. You cannot<br />

use the cast specification syntax because UDTs can only be cast to their own source<br />

type.<br />

Example: Use of UDTs in UNION<br />

Suppose you would like to provide your American users with a view containing<br />

all the sales of every product of your company:<br />

CREATE VIEW ALL_SALES <strong>AS</strong><br />

SELECT PRODUCT_ITEM, MONTH, YEAR, TOTAL<br />

FROM US_SALES<br />

UNION<br />

SELECT PRODUCT_ITEM, MONTH, YEAR, US_DOLLAR (TOTAL)<br />

180 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


FROM CANADIAN_SALES<br />

UNION<br />

SELECT PRODUCT_ITEM, MONTH, YEAR, US_DOLLAR (TOTAL)<br />

FROM GERMAN_SALES<br />

You cast Canadian dollars to US dollars and German Marks to US dollars because<br />

UDTs are union compatible only with the same UDT. You must use the functional<br />

notation to cast between UDTs since the cast specification only lets you cast<br />

between UDTs and their source types.<br />

Synergy between UDTs, UDFs, and LOBs<br />

In previous sections, you learned how to define and use the individual <strong>DB2</strong> object<br />

extensions (UDTs, UDFs, and LOBs). However, as you will see in this section, there<br />

is a lot of synergy between these three object extensions.<br />

Combining UDTs, UDFs, and LOBs<br />

According to the concept of object-orientation, similar objects in the application<br />

domain are grouped into related types. Each of these types have a name, an<br />

internal representation, and behavior. By using UDTs, you can tell <strong>DB2</strong> the name of<br />

your new type and how it is internally represented. A LOB is one of the possible<br />

internal representations <strong>for</strong> your new type and is the most suitable representation<br />

<strong>for</strong> large, complex structures. By using UDFs, you can define the behavior of the<br />

new type. Consequently, there is an important synergy between UDTs, UDFs, and<br />

LOBs. An application type with a complex data structure and behavior is modeled<br />

as a UDT that is internally represented as a LOB, with its behavior implemented<br />

by UDFs. The rules governing the semantic integrity of your application type will<br />

be represented as constraints and triggers. To have better control and organization<br />

of your related UDTs and UDFs, you should keep them in the same schema.<br />

Examples of complex applications<br />

The following examples show how you can use UDTs, UDFs, and LOBs together in<br />

complex applications:<br />

Example: Defining the UDT and UDFs<br />

Example: Exploiting LOB function to populate the database<br />

Example: Exploiting UDFs to query instances of UDTs<br />

Example: Exploiting LOB locators to manipulate UDT instances<br />

Example: Defining the UDT and UDFs<br />

Suppose you would like to keep the electronic mail (e-mail) sent to your company<br />

in <strong>DB2</strong> tables. Ignoring any issues of privacy, you plan to write queries over such<br />

e-mail to find out their subject, how often your e-mail service is used to receive<br />

customer orders, and so on. E-mail can be quite large, and it has a complex<br />

internal structure (a sender, a receiver, the subject, date, and the e-mail content).<br />

There<strong>for</strong>e, you decide to represent the e-mail by means of a UDT whose source<br />

type is a large object. You define a set of UDFs on your e-mail type, such as<br />

functions to extract the subject of the e-mail, the sender, the date, and so on. You<br />

also define functions that can per<strong>for</strong>m searches on the content of the e-mail. You<br />

do the above using the following CREATE statements:<br />

CREATE DISTINCT TYPE E_MAIL <strong>AS</strong> BLOB (1M)<br />

CREATE FUNCTION SUBJECT (E_MAIL)<br />

RETURNS VARCHAR (200)<br />

Chapter 8. Using the Object-Relational Capabilities 181


EXTERNAL NAME 'LIB/PGM(SUBJECT)'<br />

LANGUAGE C<br />

PARAMETER STYLE <strong>DB2</strong><strong>SQL</strong><br />

NO <strong>SQL</strong><br />

DETERMINISTIC<br />

NO EXTERNAL ACTION<br />

CREATE FUNCTION SENDER (E_MAIL)<br />

RETURNS VARCHAR (200)<br />

EXTERNAL NAME 'LIB/PGM(SENDER)'<br />

LANGUAGE C<br />

PARAMETER STYLE <strong>DB2</strong><strong>SQL</strong><br />

NO <strong>SQL</strong><br />

DETERMINISTIC<br />

NO EXTERNAL ACTION<br />

CREATE FUNCTION RECEIVER (E_MAIL)<br />

RETURNS VARCHAR (200)<br />

EXTERNAL NAME 'LIB/PGM(RECEIVER)'<br />

LANGUAGE C<br />

PARAMETER STYLE <strong>DB2</strong><strong>SQL</strong><br />

NO <strong>SQL</strong><br />

DETERMINISTIC<br />

NO EXTERNAL ACTION<br />

CREATE FUNCTION SENDING_DATE (E_MAIL)<br />

RETURNS DATE C<strong>AS</strong>T FROM VARCHAR(10)<br />

EXTERNAL NAME 'LIB/PGM(SENDING_DATE)'<br />

LANGUAGE C<br />

PARAMETER STYLE <strong>DB2</strong><strong>SQL</strong><br />

NO <strong>SQL</strong><br />

DETERMINISTIC<br />

NO EXTERNAL ACTION<br />

CREATE FUNCTION CONTENTS (E_MAIL)<br />

RETURNS BLOB (1M)<br />

EXTERNAL NAME 'LIB/PGM(CONTENTS)'<br />

LANGUAGE C<br />

PARAMETER STYLE <strong>DB2</strong><strong>SQL</strong><br />

NO <strong>SQL</strong><br />

DETERMINISTIC<br />

NO EXTERNAL ACTION<br />

CREATE FUNCTION CONTAINS (E_MAIL, VARCHAR (200))<br />

RETURNS INTEGER<br />

EXTERNAL NAME 'LIB/PGM(CONTAINS)'<br />

LANGUAGE C<br />

PARAMETER STYLE <strong>DB2</strong><strong>SQL</strong><br />

NO <strong>SQL</strong><br />

DETERMINISTIC<br />

NO EXTERNAL ACTION<br />

CREATE TABLE ELECTRONIC_MAIL<br />

(ARRIVAL_TIMESTAMP TIMESTAMP,<br />

MESSAGE E_MAIL)<br />

Example: Exploiting LOB function to populate the database<br />

Suppose you populate your table by transferring your e-mail that is maintained in<br />

files into <strong>DB2</strong>. You would execute the following INSERT statement multiple times<br />

with different values of the HV_EMAIL_FILE until you have stored all your e_mail<br />

into <strong>DB2</strong>:<br />

EXEC <strong>SQL</strong> BEGIN DECLARE SECTION<br />

<strong>SQL</strong> TYPE IS BLOB_FILE HV_EMAIL_FILE;<br />

EXEC <strong>SQL</strong> END DECLARE SECTION<br />

182 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


strcpy (HV_EMAIL_FILE.NAME, "/u/mail/email/mbox");<br />

HV_EMAIL_FILE.NAME_LENGTH = strlen(HV_EMAIL_FILE.NAME);<br />

HV_EMAIL_FILE.FILE_OPTIONS = 2;<br />

EXEC <strong>SQL</strong> INSERT INTO ELECTRONIC_MAIL<br />

VALUES (CURRENT TIMESTAMP, :hv_email_file);<br />

All the function provided by <strong>DB2</strong> LOB support is applicable to UDTs whose source<br />

type are LOBs. There<strong>for</strong>e, you have used LOB file reference variables to assign the<br />

contents of the file into the UDT column. You have not used the cast function to<br />

convert values of BLOB type into your e-mail type. This is because <strong>DB2</strong> let you<br />

assign values of the source type of a distinct type to targets of the distinct type.<br />

Example: Exploiting UDFs to query instances of UDTs<br />

Suppose you need to know how much e-mail was sent by a specific customer<br />

regarding customer orders and you have the e-mail address of your customers in<br />

the customers table.<br />

SELECT COUNT (*)<br />

FROM ELECTRONIC_MAIL <strong>AS</strong> EMAIL, CUSTOMERS<br />

WHERE SUBJECT (EMAIL.MESSAGE) = 'customer order'<br />

AND CUSTOMERS.EMAIL_ADDRESS = SENDER (EMAIL.MESSAGE)<br />

AND CUSTOMERS.NAME = 'Customer X'<br />

You have used the UDFs defined on the UDT in this <strong>SQL</strong> query since they are the<br />

only means to manipulate the UDT. In this sense, your UDT e-mail is completely<br />

encapsulated. That is, its internal representation and structure are hidden and can<br />

only be manipulated by the defined UDFs. These UDFs know how to interpret the<br />

data without the need to expose its representation.<br />

Suppose you need to know the details of all the e-mail your company received in<br />

1994 which had to do with the per<strong>for</strong>mance of your products in the marketplace.<br />

SELECT SENDER (MESSAGE), SENDING_DATE (MESSAGE), SUBJECT (MESSAGE)<br />

FROM ELECTRONIC_MAIL<br />

WHERE CONTAINS (MESSAGE,<br />

'"per<strong>for</strong>mance" AND "products" AND "marketplace"') = 1<br />

You have used the contains UDF which is capable of analyzing the contents of the<br />

message searching <strong>for</strong> relevant keywords or synonyms.<br />

Example: Exploiting LOB locators to manipulate UDT instances<br />

Suppose you would like to obtain in<strong>for</strong>mation about a specific e-mail without<br />

having to transfer the entire e-mail into a host variable in your application<br />

program. (Remember that an e-mail can be quite large.) Since your UDT is defined<br />

on a LOB, you can use LOB locators <strong>for</strong> that purpose:<br />

EXEC <strong>SQL</strong> BEGIN DECLARE SECTION<br />

long hv_len;<br />

char hv_subject[200];<br />

char hv_sender[200];<br />

char hv_buf[4096];<br />

char hv_current_time[26];<br />

<strong>SQL</strong> TYPE IS BLOB_LOCATOR hv_email_locator;<br />

EXEC <strong>SQL</strong> END DECLARE SECTION<br />

EXEC <strong>SQL</strong> SELECT MESSAGE<br />

INTO :hv_email_locator<br />

FROM ELECTRONIC MAIL<br />

Chapter 8. Using the Object-Relational Capabilities 183


Using DataLinks<br />

WHERE ARRIVAL_TIMESTAMP = :hv_current_time;<br />

EXEC <strong>SQL</strong> VALUES (SUBJECT (E_MAIL(:hv_email_locator))<br />

INTO :hv_subject;<br />

.... code that checks if the subject of the e_mail is relevant ....<br />

.... if the e_mail is relevant, then...............................<br />

EXEC <strong>SQL</strong> VALUES (SENDER (C<strong>AS</strong>T (:hv_email_locator <strong>AS</strong> E_MAIL)))<br />

INTO :hv_sender;<br />

Because your host variable is of type BLOB locator (the source type of the UDT),<br />

you have explicitly converted the BLOB locator to your UDT, whenever it was<br />

used as an argument of a UDF defined on the UDT.<br />

The DataLink data type is one of the basic building blocks <strong>for</strong> extending the types<br />

of data that can be stored in database files. The idea of a DataLink is that the<br />

actual data stored in the column is only a pointer to the object. This object can be<br />

anything, an image file, a voice recording, a text file, etc. The method used <strong>for</strong><br />

resolving to the object is to store a Uni<strong>for</strong>m Resource Locator (URL). This means<br />

that a row in a table can be used to contain in<strong>for</strong>mation about the object in<br />

traditional data types, and the object itself can be referenced using the DataLink<br />

data type. The user can use new <strong>SQL</strong> scalar functions to get back the path to the<br />

object and the server on which the object is stored. With the DataLink data type,<br />

there is a fairly loose relationship between the row and the object. For instance,<br />

deleting a row will sever the relationship to the object referenced by the DataLink,<br />

but the object itself might not be deleted.<br />

An <strong>SQL</strong> table created with a DataLink column can be used to hold in<strong>for</strong>mation<br />

about an object, without actually containing the object itself. This concept gives the<br />

user much more flexibility in the types of data that can be managed using an <strong>SQL</strong><br />

table. If, <strong>for</strong> instance, the user has thousands of video clips stored in the integrated<br />

file system of their <strong>AS</strong>/<strong>400</strong>, they may want to use an <strong>SQL</strong> table to contain<br />

in<strong>for</strong>mation about these video clips. But since the user already has the objects<br />

stored in a directory, they simply want the <strong>SQL</strong> table to contain references to the<br />

objects, not contain the actual bytes of storage. A good solution would be to use<br />

DataLinks. The <strong>SQL</strong> table would use traditional <strong>SQL</strong> data types to contain<br />

in<strong>for</strong>mation about each clip, such as title, length, date, etc. But the clip itself would<br />

be referenced using a DataLink column. Each row in the table would store a URL<br />

<strong>for</strong> the object and an optional comment. Then an application that is working with<br />

the clips can retrieve the URL using <strong>SQL</strong> interfaces, and then use a browser or<br />

other playback software to work with the URL and display the video clip.<br />

There are several advantages to using this technique:<br />

v The integrated file system can store any type of stream file.<br />

v The integrated file system can store extremely large objects, that would not fit<br />

into a character column, or perhaps even a LOB column.<br />

v The hierarchical nature of the integrated file system is well-suited to organizing<br />

and working with the stream file objects.<br />

v By leaving the bytes of the object outside the database and in the integrated file<br />

system, applications can achieve better per<strong>for</strong>mance by allowing the <strong>SQL</strong><br />

runtime engine to handle queries and reports, and allowing the file system to<br />

handle streaming of video, displaying images, text, etc.<br />

184 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


Using DataLinks also gives control over the objects while they are in ″linked″<br />

status. A DataLink column can be created such that the referenced object cannot be<br />

deleted, moved, or renamed while there is a row in the <strong>SQL</strong> table that references<br />

that object. This object would be considered linked. Once the row containing that<br />

reference is deleted, the object is unlinked. To understand this concept fully, one<br />

should know the levels of control that can be specified when creating a DataLink<br />

column. Refer to the <strong>SQL</strong> Reference <strong>for</strong> the exact syntax used when creating<br />

DataLink columns.<br />

NO LINK CONTROL<br />

When a column is created with NO LINK CONTROL, there is no linking that takes<br />

place when rows are added to the <strong>SQL</strong> table. The URL is verified to be<br />

syntactically correct, but there is no check to make sure that the server is<br />

accessible, or that the file even exists.<br />

FILE LINK CONTROL (with File System Permissions)<br />

When the DataLink column is created as FILE LINK CONTROL with file system<br />

(FS) permissions, the system will verify that any DataLink value is a valid URL,<br />

with a valid server name and file name. The file must exist at the time that row is<br />

being inserted into the <strong>SQL</strong> table. When the object is found, it will be marked as<br />

linked. This means that the object cannot be moved, deleted, or renamed during<br />

the time that it is linked. Also, an object cannot be linked more than once. If the<br />

server name portion of the URL specifies a remote system, that system must be<br />

accessible. If a row containing a DataLink value is deleted, the object is unlinked. If<br />

a DataLink value is updated to a different value, the old object is unlinked, and<br />

the new object is linked.<br />

The integrated file system is still responsible <strong>for</strong> managing permissions <strong>for</strong> the<br />

linked object. The permissions are not modified during the link or unlink<br />

processes. This option provides control of the object’s existence <strong>for</strong> the duration of<br />

time that it is linked.<br />

FILE LINK CONTROL (with Database Permissions)<br />

When the DataLink column is create as FILE LINK CONTROL with database<br />

permissions, the URL is verified, and all existing permissions to the object are<br />

removed. The ownership of the object is changed to a special system-supplied user<br />

profile. During the time that the object is linked, the only access to the object is by<br />

obtaining the URL from the <strong>SQL</strong> table that has the object linked. This is handled<br />

by using a special access token that is appended to the URL returned by <strong>SQL</strong>.<br />

Without the access token, all attempts to access the object will fail with an<br />

authority violation. If the URL with the access token is retrieved from the <strong>SQL</strong><br />

table by normal means (FETCH, SELECT INTO, etc.) the file system filter will<br />

validate the access token and allow the access to the object.<br />

This option provides the control of preventing updates to the linked object <strong>for</strong><br />

users trying to access the object by direct means. Since the only access to the object<br />

is by obtaining the access token from an <strong>SQL</strong> operation, an administrator can<br />

effectively control access to the linked objects by using the database permissions to<br />

the <strong>SQL</strong> table that contains the DataLink column.<br />

Chapter 8. Using the Object-Relational Capabilities 185


Commands used <strong>for</strong> working with DataLinks<br />

Support <strong>for</strong> the DataLink data type can be broken down into 3 different<br />

components:<br />

1. The <strong>DB2</strong> database support has a data type called DATALINK. This can be<br />

specified on <strong>SQL</strong> statements such as CREATE TABLE and ALTER TABLE. The<br />

column cannot have any default other than NULL. Access to the data must be<br />

using <strong>SQL</strong> interfaces. This is because the DATALINK itself is not compatible<br />

with any host variable type. <strong>SQL</strong> scalar functions can be used to retrieve the<br />

DATALINK value in character <strong>for</strong>m. There is a DLVALUE scalar function that<br />

must be used in <strong>SQL</strong> to INSERT and UPDATE the values in the column.<br />

2. The DataLink File Manager (DLFM) is the component that maintains the link<br />

status <strong>for</strong> the files on a server, and keeps track of meta-data <strong>for</strong> each file. This<br />

code handles linking, unlinking, and commitment control issues. An important<br />

aspect of DataLinks is that the DLFM need not be on the same physical system<br />

as the <strong>SQL</strong> table that contains the DataLink column. So an <strong>SQL</strong> table can link<br />

an object that resides in either the same system’s integrated file system, or a<br />

remote <strong>AS</strong>/<strong>400</strong>’s integrated file system.<br />

3. The DataLink filter must be executed when the file system tries operations<br />

against files that are in directories designated as containing linked objects. This<br />

component determines if the file is linked, and optionally, if the user is<br />

authorized to access the file. If the file name includes an access token, the token<br />

will be verified. Since there is extra overhead in this filter process, it is only<br />

executed when the accessed object exists in one of the directories within a<br />

DataLink ″prefix’. See the discussion below on prefixes.<br />

When working with DataLinks, there are several steps that must be taken to<br />

properly configure the system:<br />

v TCP/IP must be configured on any systems that are going to be used when<br />

working with DataLinks. This would include the systems on which the <strong>SQL</strong><br />

tables with DataLink columns are going to be created, as well as the systems<br />

that will contain the objects to be linked. In most cases, this will be the same<br />

system. Since the URL that is used to reference the object contains a TCP/IP<br />

server name, this name must be recognized by the system that is going to<br />

contain the DataLink. The command CFGTCP can be used to configure the<br />

TCP/IP names, or to register a TCP/IP name server.<br />

v The system that contains the <strong>SQL</strong> tables must have the Relational Database<br />

<strong>Directory</strong> updated to reflect the local database system, and any optional remote<br />

systems. The command WRKRDBDIRE can be used to add or modify<br />

in<strong>for</strong>mation in this directory. For consistency, it is recommended that the same<br />

names be used as the TCP/IP server name and the Relational Database name.<br />

v The DLFM server must be started on any systems that will contain objects to be<br />

linked. The command STRTCPSVR *DLFM can be used to start the DLFM<br />

server. The DLFM server can be ended by using the CL command ENDTCPSVR<br />

*DLFM.<br />

Once the DLFM has been started, there are some steps needed to configure the<br />

DLFM. These DLFM functions are available via an executable script that can be<br />

entered from the QShell interface. To get to the interactive shell interface, use the<br />

CL command QSH. This will bring up a command entry screen from which you<br />

can enter the DLFM script commands. The script command dfmadmin -help can be<br />

used to display help text and syntax diagrams. For the most commonly used<br />

functions, CL commands have also been provided. Using the CL commands, most<br />

or all of the DLFM configuration can be accomplished without using the script<br />

186 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


interface. Depending on your preferences, you can choose to use either the script<br />

commands from the QSH command entry screen or the CL commands from the CL<br />

command entry screen.<br />

Since these functions are meant <strong>for</strong> a system administrator or a database<br />

administrator, they all require the *IOSYSCFG special authority.<br />

Adding a prefix - A prefix is a path or directory that will contain objects to be<br />

linked. When setting up the DLFM on a system, the administrator must add any<br />

prefixes that will be used <strong>for</strong> DataLinks. The script command dfmadmin<br />

-add_prefix is used to add prefixes. The CL command to add prefixes is<br />

ADDPFXDLFM.<br />

For instance, on server TESTSYS1, there is a directory called /mydir/datalinks/<br />

that contains the objects that will be linked. The administrator uses the command<br />

ADDPFXDLFM PREFIX((’/mydir/datalinks/’)) to add the prefix. Now links <strong>for</strong><br />

URLs such as:<br />

http://TESTSYS1/mydir/datalinks/videos/file1.mpg<br />

or<br />

file://TESTSYS1/mydir/datalinks/text/story1.txt<br />

would be valid since their path begins with a valid prefix.<br />

It is also possible to remove a prefix using the script command dfmadmin<br />

-del_prefix. This is not a commonly used function since it can only be executed if<br />

there are no linked objects anywhere in the directory structure contained within<br />

the prefix name.<br />

Adding a Host Database - A host database is a relational database system from<br />

which a link request originates. If the DLFM is on the same system as the <strong>SQL</strong><br />

tables that will contain the DataLinks, then only the local database name needs to<br />

be added. If the DLFM will have link requests coming from remote systems, then<br />

all of their names must be registered with the DLFM. The script command to add<br />

a host database is dfmadmin -add_db and the CL command is ADDHDBDLFM.<br />

This function also requires that the libraries containing the <strong>SQL</strong> tables also be<br />

registered.<br />

For instance, on server TESTSYS1, where you have already added the<br />

/mydir/datalinks/ prefix, you want <strong>SQL</strong> tables on the local system in either<br />

library TESTDB or PRODDB to be allowed to link objects on this server. Use the<br />

following command: ADDHDBDLFM HOSTDBLIB((TESTDB) (PRODDB))<br />

HOSTDB(TESTSYS1)<br />

Once the DLFM has been started, and the prefixes and host database names have<br />

been registered, you can begin linking objects in the file system.<br />

Chapter 8. Using the Object-Relational Capabilities 187


188 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


Chapter 9. Writing User-Defined Functions (UDFs)<br />

UDF runtime environment<br />

User Defined Functions (UDFs) consist of three types: sourced, external, and <strong>SQL</strong>.<br />

Sourced function UDFs call other functions to per<strong>for</strong>m the operation. <strong>SQL</strong> and<br />

external function UDFs require that you write and execute separate code. This<br />

chapter is about writing <strong>SQL</strong> and external functions. To write external and <strong>SQL</strong><br />

functions, you need to do the following:<br />

v understand the “UDF runtime environment”<br />

v register the UDF, so that it is known to the database<br />

v write the function code to per<strong>for</strong>m the function and pass the appropriate<br />

parameters<br />

v debug and test the function.<br />

There are several things to consider about the environment in which a UDF<br />

executes and the limitations of that environment. These factors should be<br />

considered carefully if you are contemplating writing complex function code <strong>for</strong><br />

UDFs.<br />

Length of time that the UDF runs<br />

UDFs are invoked from within an <strong>SQL</strong> statement execution, which is normally a<br />

query operation that potentially runs against thousands of rows in a table. Because<br />

of this, the UDF needs to be invoked from a low level of the database.<br />

As a consequence of being invoked from such a low level, there are certain<br />

resources (locks and seizes) being held at the time the UDF is invoked and <strong>for</strong> the<br />

duration of the UDF execution. These resources are primarily locks on any tables<br />

and indexes involved in the <strong>SQL</strong> statement that is invoking the UDF. Due to these<br />

held resources, it is important that the UDF not per<strong>for</strong>m operations that may take<br />

an extended period of time (minutes or hours). Because of the critical nature of<br />

holding resources <strong>for</strong> long periods of time, the database only waits <strong>for</strong> a certain<br />

period of time <strong>for</strong> the UDF to finish. If the UDF does not finish in the time<br />

allocated, the <strong>SQL</strong> statement will fail, which can be quite aggravating to the end<br />

user.<br />

The default UDF wait time used by the database should be more than sufficient to<br />

allow a normal UDF to run to completion. However, if you have a long running<br />

UDF and wish to increase the wait time, this can be done using the<br />

UDF_TIME_OUT option in the query INI file. See Query Options File QAQQINI in<br />

the Database Per<strong>for</strong>mance and Query Optimization in<strong>for</strong>mation <strong>for</strong> details on the INI<br />

file. Note, however, that there is a maximum time limit that the database will not<br />

exceed, regardless of the value specified <strong>for</strong> UDF_TIME_OUT.<br />

Since resources are held while the UDF is run, it is important that the UDF not<br />

operate on the same tables or indexes allocated <strong>for</strong> the original <strong>SQL</strong> statement or, if<br />

it does, that it does not per<strong>for</strong>m an operation that conflicts with the one being<br />

per<strong>for</strong>med in the <strong>SQL</strong> statement. Specifically, the UDF should not try to per<strong>for</strong>m<br />

any insert, update or delete record operation on those tables.<br />

© Copyright IBM Corp. 2000 189


Threads considerations<br />

A UDF runs in the same job as the <strong>SQL</strong> statement that invoked it. However, the<br />

UDF runs in a system thread, separate from the thread that is running the <strong>SQL</strong><br />

statement. For more in<strong>for</strong>mation about threads, see Database considerations <strong>for</strong><br />

multithreaded programming in the <strong>Programming</strong> category of the In<strong>for</strong>mation<br />

Center.<br />

Because the UDF runs in the same job as the <strong>SQL</strong> statement, it shares much of the<br />

same environment as the <strong>SQL</strong> statement. However, because it runs under a<br />

separate thread, the following threads considerations apply:<br />

v the UDF will conflict with thread level resources held by the <strong>SQL</strong> statement’s<br />

thread. Primarily, these are the table resources discussed above.<br />

v UDFs do not inherit any program adopted authority that may have been active<br />

at the time the <strong>SQL</strong> statement was invoked. UDF authority comes from either<br />

the authority associated with the UDF program itself or the authority of the user<br />

running the <strong>SQL</strong> statement.<br />

v the UDF cannot per<strong>for</strong>m any operation that is blocked from being run in a<br />

secondary thread.<br />

v the UDF program must be created such that it either runs under a named<br />

activation group or in the activation group of its caller (ACTGRP parameter).<br />

Programs that specify ACTGRP(*NEW) will not be allowed to run as UDFs.<br />

Parallel processing<br />

Writing function code<br />

A UDF can be defined to allow parallel processing. This means that the same UDF<br />

program can be running in multiple threads at the same time. There<strong>for</strong>e, if<br />

ALLOW PARALLEL is specified <strong>for</strong> the UDF, ensure that it is thread safe. For<br />

more in<strong>for</strong>mation about threads, see Database considerations <strong>for</strong> multithreaded<br />

programming in the <strong>Programming</strong> category of the In<strong>for</strong>mation Center.<br />

Writing function code involves knowing how to write the <strong>SQL</strong> or external function<br />

to per<strong>for</strong>m the function. It also involves understanding the interface between the<br />

database and the function code to define it correctly, and determining packaging<br />

options when creating the executable program.<br />

Writing UDFs as <strong>SQL</strong> functions<br />

<strong>SQL</strong> functions are UDFs that you have defined, written, and registered using the<br />

CREATE FUNCTION statement. As such, they are written using only the <strong>SQL</strong><br />

language and their definition is completely contained within one (potentially large)<br />

CREATE FUNCTION statement.<br />

The CREATE FUNCTION statement <strong>for</strong> <strong>SQL</strong> functions follow the general flow of:<br />

CREATE FUNCTION function name(parameters) RETURNS return value<br />

LANGUAGE <strong>SQL</strong><br />

BEGIN<br />

sql statements<br />

END<br />

For example, a function that returns a priority based on a date:<br />

190 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


►►<br />

CREATE FUNCTION PRIORITY(indate date) RETURNS CHAR(7)<br />

LANGUAGE <strong>SQL</strong><br />

BEGIN<br />

RETURN(<br />

C<strong>AS</strong>E<br />

WHEN indate>CURRENT DATE-3 DAYS THEN 'HIGH'<br />

WHEN indate>CURRENT DATE-7 DAYS THEN 'MEDIUM'<br />

ELSE 'LOW'<br />

END<br />

);<br />

END<br />

The function could then be invoked as:<br />

SELECT ORDERNBR, PRIORITY(ORDERDUEDATE) FROM ORDERS<br />

The creation of an <strong>SQL</strong> function causes the registration of the UDF, generates the<br />

executable code <strong>for</strong> the function, and defines to the database the details of how<br />

parameters are actually passed. There<strong>for</strong>e, writing these functions is quite clean<br />

and provides less chance of introducing errors into the function.<br />

Writing UDFs as external functions<br />

▼ <strong>SQL</strong>-argument<br />

You can also write the executable code of a UDF in a language other than <strong>SQL</strong>.<br />

While this method is slightly more cumbersome than an <strong>SQL</strong> function, it provides<br />

the flexibility <strong>for</strong> you to use whatever language is most effective <strong>for</strong> you. The<br />

executable code can be contained in either a program or service program.<br />

Passing arguments from <strong>DB2</strong> to external functions<br />

<strong>DB2</strong> provides the storage <strong>for</strong> all parameters passed to a UDF. There<strong>for</strong>e,<br />

parameters are passed to the external function by address. This is the normal<br />

parameter passing method <strong>for</strong> programs. For service programs, ensure that the<br />

parameters are defined correctly in the function code.<br />

When defining and using the parameters in the UDF, care should be taken to<br />

ensure that no more storage is referenced <strong>for</strong> a given parameter than is defined <strong>for</strong><br />

that parameter. The parameters are all stored in the same space and exceeding a<br />

given parameter’s storage space can overwrite another parameter’s value. This, in<br />

turn, can cause the function to see invalid input data or cause the value returned<br />

to the database to be invalid.<br />

There are four supported parameter styles available to external UDFs. For the most<br />

part, the styles differ in how many parameters are passed to the external program<br />

or service program.<br />

Parameter style <strong>SQL</strong>: The parameter style <strong>SQL</strong> con<strong>for</strong>ms to the industry standard<br />

Structured Query Language (<strong>SQL</strong>). With parameter style <strong>SQL</strong>, the parameters are<br />

passed into the external program as follows (in the order specified):<br />

<strong>SQL</strong>-result<br />

▼ <strong>SQL</strong>-argument-ind<br />

<strong>SQL</strong>-result-ind <strong>SQL</strong>-state ►<br />

► function-name specific-name diagnostic-message ►◄<br />

Chapter 9. Writing User-Defined Functions (UDFs) 191


<strong>SQL</strong>-argument<br />

This argument is set by <strong>DB2</strong> be<strong>for</strong>e calling the UDF. This value repeats n<br />

times, where n is the number of arguments specified in the function<br />

reference. The value of each of these arguments is taken from the<br />

expression specified in the function invocation. It is expressed in the data<br />

type of the defined parameter in the create function statement. Note: These<br />

parameters are treated as input only; any changes to the parameter values<br />

made by the UDF are ignored by <strong>DB2</strong>.<br />

<strong>SQL</strong>-result<br />

This argument is set by the UDF be<strong>for</strong>e returning to <strong>DB2</strong>. The database<br />

provides the storage <strong>for</strong> the return value. Since the parameter is passed by<br />

address, the address is of the storage where the return value should be<br />

placed. The database provides as much storage as needed <strong>for</strong> the return<br />

value as defined on the CREATE FUNCTION statement. If the C<strong>AS</strong>T<br />

FROM clause is used in the CREATE FUNCTION statement, <strong>DB2</strong> assumes<br />

the UDF returns the value as defined in the C<strong>AS</strong>T FROM clause, otherwise<br />

<strong>DB2</strong> assumes the UDF returns the value as defined in the RETURNS<br />

clause.<br />

<strong>SQL</strong>-argument-ind<br />

This argument is set by <strong>DB2</strong> be<strong>for</strong>e calling the UDF. It can be used by the<br />

UDF to determine if the corresponding <strong>SQL</strong>-argument is null or not. The<br />

nth <strong>SQL</strong>-argument-ind corresponds to the nth <strong>SQL</strong>-argument, described<br />

previously. Each indicator is defined as a two-byte signed integer. It is set<br />

to one of the following values:<br />

0 The argument is present and not null.<br />

-1 The argument is null.<br />

If the function is defined with RETURNS NULL ON NULL INPUT, the<br />

UDF does not need to check <strong>for</strong> a null value. However, if it is defined with<br />

CALLS ON NULL INPUT, any argument can be NULL and the UDF<br />

should check <strong>for</strong> null input. Note: these parameters are treated as input<br />

only; any changes to the parameter values made by the UDF are ignored<br />

by <strong>DB2</strong>.<br />

<strong>SQL</strong>-result-ind<br />

This argument is set by the UDF be<strong>for</strong>e returning to <strong>DB2</strong>. The database<br />

provides the storage <strong>for</strong> the return value. The argument is defined as a<br />

two-byte signed integer. If set to a negative value, the database interprets<br />

the result of the function as null. If set to zero or a positive value, the<br />

database uses the value returned in <strong>SQL</strong>-result. The database provides the<br />

storage <strong>for</strong> the return value indicator. Since the parameter is passed by<br />

address, the address is of the storage where the indicator value should be<br />

placed.<br />

<strong>SQL</strong>-state<br />

This argument is a CHAR(5) value that represents the <strong>SQL</strong>STATE.<br />

This parameter is passed in from the database set to '00000' and can be set<br />

by the function as a result state <strong>for</strong> the function. While normally the<br />

<strong>SQL</strong>STATE is not set by the function, it can be used to signal an error or<br />

warning to the database as follows:<br />

01Hxx The function code detected a warning situation. This results in an<br />

<strong>SQL</strong> warning, Here xx may be one of several possible strings.<br />

192 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


►►<br />

▼ <strong>SQL</strong>-argument<br />

38xxx The function code detected an error situation. It results in a <strong>SQL</strong><br />

error. Here xxx may be one of several possible strings.<br />

See Appendix B <strong>for</strong> more in<strong>for</strong>mation on valid <strong>SQL</strong>STATEs that the<br />

function may use.<br />

function-name<br />

This argument is set by <strong>DB2</strong> be<strong>for</strong>e calling the UDF. It is a VARCHAR(139)<br />

value that contains the name of the function on whose behalf the function<br />

code is being invoked.<br />

The <strong>for</strong>m of the function name that is passed is:<br />

.<br />

This parameter is useful when the function code is being used by multiple<br />

UDF definitions so that the code can distinguish which definition is being<br />

invoked. Note: This parameter is treated as input only; any changes to the<br />

parameter value made by the UDF are ignored by <strong>DB2</strong>.<br />

specific-name<br />

This argument is set by <strong>DB2</strong> be<strong>for</strong>e calling the UDF. It is a VARCHAR(128)<br />

value that contains the specific name of the function on whose behalf the<br />

function code is being invoked.<br />

Like function-name, this parameter is useful when the function code is<br />

being used by multiple UDF definitions so that the code can distinguish<br />

which definition is being invoked. See the CREATE FUNCTION <strong>for</strong> more<br />

in<strong>for</strong>mation about specific-name. Note: This parameter is treated as input<br />

only; any changes to the parameter value made by the UDF are ignored by<br />

<strong>DB2</strong>.<br />

diagnostic-message<br />

This argument is set by <strong>DB2</strong> be<strong>for</strong>e calling the UDF. It is a VARCHAR(70)<br />

value that can be used by the UDF to send message text back when an<br />

<strong>SQL</strong>STATE warning or error is signaled by the UDF.<br />

It is initialized by the database on input to the UDF and may be set by the<br />

UDF with descriptive in<strong>for</strong>mation. Message text is ignored by <strong>DB2</strong> unless<br />

the <strong>SQL</strong>-state parameter is set by the UDF.<br />

Parameter style <strong>DB2</strong><strong>SQL</strong>: With the <strong>DB2</strong><strong>SQL</strong> parameter style, the same parameters<br />

and same order of parameters are passed into the external program or service<br />

program as are passed in <strong>for</strong> parameter style <strong>SQL</strong>. However, <strong>DB2</strong><strong>SQL</strong> allows<br />

additional optional parameters to be passed along as well. If more than one of the<br />

optional parameters below is specified in the UDF definition, they are passed to<br />

the UDF in the order defined below. Refer to parameter style <strong>SQL</strong> <strong>for</strong> the common<br />

parameters.<br />

<strong>SQL</strong>-result<br />

► function-name specific-name diagnostic-message<br />

▼ <strong>SQL</strong>-argument-ind<br />

<strong>SQL</strong>-result-ind <strong>SQL</strong>-state ►<br />

scratchpad call-type dbinfo<br />

scratchpad<br />

This argument is set by <strong>DB2</strong> be<strong>for</strong>e calling the UDF. It is only present if the<br />

Chapter 9. Writing User-Defined Functions (UDFs) 193<br />

►◄


CREATE FUNCTION statement <strong>for</strong> the UDF specified the SCRATCHPAD<br />

keyword. This argument is a structure with the following elements:<br />

v An INTEGER containing the length of the scratchpad.<br />

v The actual scratchpad, initialized to all binary 0’s by <strong>DB2</strong> be<strong>for</strong>e the first<br />

call to the UDF.<br />

The scratchpad can be used by the UDF either as working storage or as<br />

persistent storage, since it is maintained across UDF invocations.<br />

call-type<br />

This argument is set by <strong>DB2</strong> be<strong>for</strong>e calling the UDF. It is only present if the<br />

CREATE FUNCTION statement <strong>for</strong> the UDF specified the FINAL CALL<br />

keyword. It is an INTEGER value that contains one of the following<br />

values:<br />

-1 This is the first call to the UDF <strong>for</strong> this statement. A first call is a<br />

normal call in that all <strong>SQL</strong> argument values are passed.<br />

0 This is a normal call. (All the normal input argument values are<br />

passed).<br />

1 This is a final call. No<strong>SQL</strong>-argument or <strong>SQL</strong>-argument-ind values are<br />

passed. A UDF should not return any answer using the <strong>SQL</strong>-result<br />

or <strong>SQL</strong>-result-ind arguments. Both of these are ignored by <strong>DB2</strong><br />

upon return from the UDF. However, the UDF may set the<br />

<strong>SQL</strong>-state and diagnostic-message arguments. These arguments are<br />

handled in a way similar to other calls to the UDF.<br />

dbinfo This argument is set by <strong>DB2</strong> be<strong>for</strong>e calling the UDF. It is only present if the<br />

CREATE FUNCTION statement <strong>for</strong> the UDF specifies the DBINFO<br />

keyword. The argument is a structure whose definition is contained in the<br />

sqludf include.<br />

Parameter Style GENERAL (or SIMPLE CALL): With parameter style GENERAL,<br />

the parameters are passed into the external service program just as they are<br />

specified in the CREATE FUNCTION statement. The <strong>for</strong>mat is:<br />

►►<br />

▼<br />

<strong>SQL</strong>-result = func ()<br />

<strong>SQL</strong>-argument<br />

<strong>SQL</strong>-argument<br />

This argument is set by <strong>DB2</strong> be<strong>for</strong>e calling the UDF. This value repeats n<br />

times, where n is the number of arguments specified in the function<br />

reference. The value of each of these arguments is taken from the<br />

expression specified in the function invocation. It is expressed in the data<br />

type of the defined parameter in the CREATE FUNCTION statement. Note:<br />

These parameters are treated as input only; any changes to the parameter<br />

values made by the UDF are ignored by <strong>DB2</strong>.<br />

<strong>SQL</strong>-result<br />

This value is returned by the UDF. <strong>DB2</strong> copies the value into database<br />

storage. In order to return the value correctly, the function code must be a<br />

value-returning function. The database copies only as much of the value as<br />

defined <strong>for</strong> the return value as specified on the CREATE FUNCTION<br />

statement. If the C<strong>AS</strong>T FROM clause is used in the CREATE FUNCTION<br />

194 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5<br />

►◄


statement, <strong>DB2</strong> assumes the UDF returns the value as defined in the C<strong>AS</strong>T<br />

FROM clause, otherwise <strong>DB2</strong> assumes the UDF returns the value as<br />

defined in the RETURNS clause.<br />

Because of the requirement that the function code be a value-returning<br />

function, any function code used <strong>for</strong> parameter style GENERAL must be<br />

created into a service program.<br />

Parameter Style GENERAL WITH NULLS: With parameter style GENERAL<br />

WITH NULLS, the parameters are passed into the service program as follows (in<br />

the order specified):<br />

►► <strong>SQL</strong>-result = funcname ( ▼<br />

<strong>SQL</strong>-argument<br />

► <strong>SQL</strong>-result-ind )<br />

<strong>SQL</strong>-argument-ind-array<br />

<strong>SQL</strong>-argument<br />

This argument is set by <strong>DB2</strong> be<strong>for</strong>e calling the UDF. This value repeats n<br />

times, where n is the number of arguments specified in the function<br />

reference. The value of each of these arguments is taken from the<br />

expression specified in the function invocation. It is expressed in the data<br />

type of the defined parameter in the CREATE FUNCTION statement. Note:<br />

These parameters are treated as input only; any changes to the parameter<br />

values made by the UDF are ignored by <strong>DB2</strong>.<br />

<strong>SQL</strong>-argument-ind-array<br />

This argument is set by <strong>DB2</strong> be<strong>for</strong>e calling the UDF. It can be used by the<br />

UDF to determine if one or more<strong>SQL</strong>-arguments are null or not. It is an<br />

array of two-byte signed integers (indicators). Thenth array argument<br />

corresponds corresponds to the nth <strong>SQL</strong>-argument. Each array entry is set<br />

to one of the following values:<br />

0 The argument is present and not null.<br />

-1 The argument is null.<br />

The UDF should check <strong>for</strong> null input. Note: This parameter is treated as<br />

input only; any changes to the parameter value made by the UDF is<br />

ignored by <strong>DB2</strong>.<br />

<strong>SQL</strong>-result-ind<br />

This argument is set by the UDF be<strong>for</strong>e returning to <strong>DB2</strong>. The database<br />

provides the storage <strong>for</strong> the return value. The argument is defined as a<br />

two-byte signed integer. If set to a negative value, the database interprets<br />

the result of the function as null. If set to zero or a positive value, the<br />

database uses the value returned in <strong>SQL</strong>-result. The database provides the<br />

storage <strong>for</strong> the return value indicator. Since the parameter is passed by<br />

address, the address is of the storage where the indicator value should be<br />

placed.<br />

<strong>SQL</strong>-result<br />

This value is returned by the UDF. <strong>DB2</strong> copies the value into database<br />

storage. In order to return the value correctly, the function code must be a<br />

Chapter 9. Writing User-Defined Functions (UDFs) 195<br />

►<br />

►◄


value-returning function. The database copies only as much of the value as<br />

defined <strong>for</strong> the return value as specified on the CREATE FUNCTION<br />

statement. If the C<strong>AS</strong>T FROM clause is used in the CREATE FUNCTION<br />

statement, <strong>DB2</strong> assumes the UDF returns the value as defined in the C<strong>AS</strong>T<br />

FROM clause, otherwise <strong>DB2</strong> assumes the UDF returns the value as<br />

defined in the RETURNS clause.<br />

Because of the requirement that the function code be a value-returning<br />

function, any function code used <strong>for</strong> parameter style GENERAL WITH<br />

NULLS must be created into a service program.<br />

Note:<br />

Examples of UDF code<br />

v The external name specified on the CREATE FUNCTION<br />

statement can be specified either with quotes or without quotes. If<br />

the name is not quoted, it is uppercased be<strong>for</strong>e it is stored; if it is<br />

quoted, it is stored as specified. This becomes important when<br />

naming the actual program, as the database searches <strong>for</strong> the<br />

program that has a name that exactly matches the name stored<br />

with the function definition. For example, if a function was<br />

created as:<br />

CREATE FUNCTION X(INT) RETURNS INT<br />

LANGUAGE C<br />

EXTERNAL NAME 'MYLIB/MYPGM(MYENTRY)'<br />

and the source <strong>for</strong> the program was:<br />

void myentry(<br />

int*in<br />

int*out,<br />

.<br />

.<br />

..<br />

the database would not find the entry because it is in lower case<br />

myentry and the database was instructed to look <strong>for</strong> uppercase<br />

MYENTRY.<br />

v For service programs with C++ modules, make sure in the C++<br />

source code to precede the program function definition with<br />

extern ″C″. Otherwise, the C++ compiler will per<strong>for</strong>m ’name<br />

mangling’ of the function’s name and the database will not find it.<br />

These examples show how to implement UDF code by using <strong>SQL</strong> functions and<br />

external functions.<br />

Example: Square of a number UDF<br />

Suppose that you wanted a function that returns the square of a number. The<br />

query statement is:<br />

SELECT SQUARE(myint) FROM mytable<br />

The following examples show how to define the UDF several different ways.<br />

v Using an <strong>SQL</strong> function<br />

196 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


CREATE FUNCTION SQUARE(inval INT) RETURNS INT<br />

LANGUAGE <strong>SQL</strong><br />

BEGIN<br />

RETURN(inval*inval);<br />

END<br />

v Using an external function, parameter style <strong>SQL</strong>:<br />

The CREATE FUNCTION statement:<br />

CREATE FUNCTION SQUARE(INT) RETURNS INT C<strong>AS</strong>T FROM FLOAT<br />

LANGUAGE C<br />

EXTERNAL NAME 'MYLIB/MATH(SQUARE)'<br />

DETERMINISTIC<br />

NO <strong>SQL</strong><br />

NO EXTERNAL ACTION<br />

PARAMETER STYLE <strong>SQL</strong><br />

ALLOW PARALLEL<br />

The code:<br />

void SQUARE(int *inval,<br />

double *outval,<br />

short *inind,<br />

short *outind,<br />

char *sqlstate,<br />

char *funcname,<br />

char *specname,<br />

char *msgtext)<br />

{<br />

if (*inind


CRTCMOD MODULE(mylib/square) DBGVIEW(*SOURCE)<br />

CRTSRVPGM SRVPGM(mylib/math) MODULE(mylib/square)<br />

EXPORT(*ALL) ACTGRP(*CALLER)<br />

Example: Counter<br />

Suppose you want to simply number the rows in your SELECT statement. So you<br />

write a UDF which increments and returns a counter. This example uses an<br />

external function with <strong>DB2</strong> <strong>SQL</strong> parameter style and a scratchpad.<br />

CREATE FUNCTION COUNTER()<br />

RETURNS INT<br />

SCRATCHPAD<br />

NOT DETERMINISTIC<br />

NO <strong>SQL</strong><br />

NO EXTERNAL ACTION<br />

LANGUAGE C<br />

PARAMETER STYLE <strong>DB2</strong><strong>SQL</strong><br />

EXTERNAL NAME 'MYLIB/MATH(ctr)'<br />

DISALLOW PARALLELISM;<br />

/* structure scr defines the passed scratchpad <strong>for</strong> the function "ctr" */<br />

struct scr {<br />

long len;<br />

long countr;<br />

char not_used[96];<br />

};<br />

void ctr (<br />

long *out, /* output answer (counter) */<br />

short *outnull, /* output NULL indicator */<br />

char *sqlstate, /* <strong>SQL</strong> STATE */<br />

char *funcname, /* function name */<br />

char *specname, /* specific function name */<br />

char *mesgtext, /* message text insert */<br />

struct scr *scratchptr) { /* scratch pad */<br />

*out = ++scratchptr->countr; /* increment counter & copy out */<br />

*outnull = 0;<br />

return;<br />

}<br />

/* end of UDF : ctr */<br />

For this UDF, observe that:<br />

v It has no input <strong>SQL</strong> arguments defined, but returns a value.<br />

v It appends the scratchpad input argument after the four standard trailing<br />

arguments, namely <strong>SQL</strong>-state, function-name, specific-name, and message-text.<br />

v It includes a structure definition to map the scratchpad which is passed.<br />

v No input parameters are defined. This agrees with the code.<br />

v SCRATCHPAD is coded, causing <strong>DB2</strong> to allocate, properly initialize and pass the<br />

scratchpad argument.<br />

v You have specified it to be NOT DETERMINISTIC, because it depends on more<br />

than the <strong>SQL</strong> input arguments, (none in this case).<br />

v You have correctly specified DISALLOW PARALLELISM, because correct<br />

functioning of the UDF depends on a single scratchpad.<br />

198 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


Chapter 10. Dynamic <strong>SQL</strong> Applications<br />

Dynamic <strong>SQL</strong> allows an application to define and run <strong>SQL</strong> statements at program<br />

run time. An application that provides <strong>for</strong> dynamic <strong>SQL</strong> accepts as input (or<br />

builds) an <strong>SQL</strong> statement in the <strong>for</strong>m of a character string. The application does<br />

not need to know what type of <strong>SQL</strong> statement it will run. The application:<br />

v Builds or accepts as input an <strong>SQL</strong> statement<br />

v Prepares the <strong>SQL</strong> statement <strong>for</strong> running<br />

v Runs the statement<br />

v Handles <strong>SQL</strong> return codes<br />

Interactive <strong>SQL</strong> (described in Chapter 12. Using Interactive <strong>SQL</strong>) is an example of a<br />

dynamic <strong>SQL</strong> program. <strong>SQL</strong> statements are processed and run dynamically by<br />

interactive <strong>SQL</strong>.<br />

Notes:<br />

1. The run-time overhead is greater <strong>for</strong> statements processed using dynamic <strong>SQL</strong><br />

than <strong>for</strong> static <strong>SQL</strong> statements. The additional process is similar to that required<br />

<strong>for</strong> precompiling, binding, and then running a program, instead of only<br />

running it. There<strong>for</strong>e, only applications requiring the flexibility of dynamic <strong>SQL</strong><br />

should use it. Other applications should access data from the database using<br />

normal (static) <strong>SQL</strong> statements.<br />

2. Programs that contain an EXECUTE or EXECUTE IMMEDIATE statement and<br />

that use a FOR READ ONLY clause to make a cursor read-only experience<br />

better per<strong>for</strong>mance because blocking is used to retrieve rows <strong>for</strong> the cursor.<br />

The ALWBLK(*ALLREAD) CRT<strong>SQL</strong>xxx option will imply a FOR READ ONLY<br />

declaration <strong>for</strong> all cursors that do not explicitly code FOR UPDATE OF or have<br />

positioned deletes or updates that refer to the cursor. Cursors with an implied<br />

FOR READ ONLY will benefit from the second item in this list.<br />

Some dynamic <strong>SQL</strong> statements require use of address variables. RPG <strong>for</strong> <strong>AS</strong>/<strong>400</strong><br />

programs require the aid of PL/I, COBOL, C, or ILE RPG <strong>for</strong> <strong>AS</strong>/<strong>400</strong> programs to<br />

manage the address variables.<br />

The examples in this chapter are PL/I examples. The following table shows all the<br />

statements supported by <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> and indicates if they can be used in<br />

a dynamic application.<br />

Note: In the following table, the numbers in the Dynamic <strong>SQL</strong> column correspond<br />

to the notes on the next page.<br />

Table 22. List of <strong>SQL</strong> Statements Allowed in Dynamic Applications<br />

<strong>SQL</strong> Statement Static <strong>SQL</strong> Dynamic <strong>SQL</strong><br />

ALTER TABLE Y Y<br />

BEGIN DECLARE SECTION Y N<br />

CALL Y Y<br />

CLOSE Y N<br />

COMMENT ON Y Y<br />

COMMIT Y Y<br />

© Copyright IBM Corp. 2000 199


Table 22. List of <strong>SQL</strong> Statements Allowed in Dynamic Applications (continued)<br />

<strong>SQL</strong> Statement Static <strong>SQL</strong> Dynamic <strong>SQL</strong><br />

CONNECT Y N<br />

CREATE ALI<strong>AS</strong> Y Y<br />

CREATE COLLECTION Y Y<br />

CREATE DISTINCT TYPE Y Y<br />

CREATE FUNCTION Y Y<br />

CREATE INDEX Y Y<br />

CREATE PROCEDURE Y Y<br />

CREATE SCHEMA N See Note 8.<br />

CREATE TABLE Y Y<br />

CREATE VIEW Y Y<br />

DECLARE CURSOR Y See Note 4.<br />

DECLARE PROCEDURE Y N<br />

DECLARE STATEMENT Y N<br />

DECLARE VARIABLE Y N<br />

DELETE Y Y<br />

DESCRIBE Y See Note 7.<br />

DESCRIBE TABLE Y N<br />

DISCONNECT Y N<br />

DROP Y Y<br />

END DECLARE SECTION Y N<br />

EXECUTE Y See Note 1.<br />

EXECUTE IMMEDIATE Y See Note 2.<br />

FETCH Y N<br />

FREE LOCATOR Y Y<br />

GRANT Y Y<br />

INCLUDE Y N<br />

INSERT Y Y<br />

LABEL ON Y Y<br />

LOCK TABLE Y Y<br />

OPEN Y N<br />

PREPARE Y See Note 3.<br />

RELE<strong>AS</strong>E Y N<br />

RENAME Y Y<br />

REVOKE Y Y<br />

ROLLBACK Y Y<br />

SELECT INTO Y See Note 5.<br />

SELECT statement Y See Note 6.<br />

SET CONNECTION Y N<br />

SET OPTION Y See Note 9.<br />

SET PATH Y Y<br />

200 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


Table 22. List of <strong>SQL</strong> Statements Allowed in Dynamic Applications (continued)<br />

<strong>SQL</strong> Statement Static <strong>SQL</strong> Dynamic <strong>SQL</strong><br />

SET RESULT SETS Y N<br />

SET TRANSACTION Y Y<br />

SET variable Y N<br />

UPDATE Y Y<br />

VALUES INTO Y N<br />

WHENEVER Y N<br />

Notes:<br />

1. Cannot be prepared, but used to run prepared <strong>SQL</strong> statements. The <strong>SQL</strong><br />

statement must be previously prepared by the PREPARE statement prior to<br />

using the EXECUTE statement. See example <strong>for</strong> PREPARE under “Using the<br />

PREPARE and EXECUTE statements” on page 202.<br />

2. Cannot be prepared, but used with dynamic statement strings that do not have<br />

any ? parameter markers. The EXECUTE IMMEDIATE statement causes the<br />

statement strings to be prepared and run dynamically at program run time. See<br />

example <strong>for</strong> EXECUTE IMMEDIATE under “Processing non-SELECT<br />

statements” on page 202.<br />

3. Cannot be prepared, but used to parse, optimize, and set up dynamic SELECT<br />

statements prior to running. See example <strong>for</strong> PREPARE under “Processing<br />

non-SELECT statements” on page 202.<br />

4. Cannot be prepared, but used to define the cursor <strong>for</strong> the associated dynamic<br />

SELECT statement prior to running.<br />

5. A SELECT INTO statement cannot be prepared or used in EXECUTE<br />

IMMEDIATE.<br />

6. Cannot be used with EXECUTE or EXECUTE IMMEDIATE but can be prepared<br />

and used with OPEN.<br />

7. Cannot be prepared, but used to return a description of a prepared statement.<br />

8. Can only be run using the Run <strong>SQL</strong> Statements (RUN<strong>SQL</strong>STM) command.<br />

9. Can only be used when running a REXX procedure.<br />

Designing and running a dynamic <strong>SQL</strong> application<br />

To issue a dynamic <strong>SQL</strong> statement, you must use the statement with either an<br />

EXECUTE statement or an EXECUTE IMMEDIATE statement, because dynamic<br />

<strong>SQL</strong> statements are not prepared at precompile time and there<strong>for</strong>e must be<br />

prepared at run time. The EXECUTE IMMEDIATE statement causes the <strong>SQL</strong><br />

statement to be prepared and run dynamically at program run time.<br />

There are two basic types of dynamic <strong>SQL</strong> statements: SELECT statements and<br />

non-SELECT statements. Non-SELECT statements include such statements as<br />

DELETE, INSERT, and UPDATE.<br />

Client server applications that use interfaces such as ODBC typically use dynamic<br />

<strong>SQL</strong> to access the database. For more in<strong>for</strong>mation on developing client server<br />

applications that use Client Access, see the Client Access <strong>for</strong> Windows 3.1 ODBC<br />

User’s Guide.<br />

Chapter 10. Dynamic <strong>SQL</strong> Applications 201


Processing non-SELECT statements<br />

To build a dynamic <strong>SQL</strong> non-SELECT statement:<br />

1. Verify that the <strong>SQL</strong> statement you want to build is one that can be run<br />

dynamically (see Table 22 on page 199).<br />

2. Build the <strong>SQL</strong> statement. (Use Interactive <strong>SQL</strong> <strong>for</strong> an easy way to build, verify,<br />

and run your <strong>SQL</strong> statement. See Chapter 12. Using Interactive <strong>SQL</strong> <strong>for</strong> more<br />

in<strong>for</strong>mation.)<br />

To run a dynamic <strong>SQL</strong> non-SELECT statement:<br />

1. Run the <strong>SQL</strong> statement using EXECUTE IMMEDIATE, or PREPARE the <strong>SQL</strong><br />

statement, then EXECUTE the prepared statement.<br />

2. Handle any <strong>SQL</strong> return codes that might result.<br />

The following is an example of an application running a dynamic <strong>SQL</strong><br />

non-SELECT statement (stmtstrg):<br />

EXEC <strong>SQL</strong><br />

EXECUTE IMMEDIATE :stmtstrg;<br />

CCSID of dynamic <strong>SQL</strong> statements<br />

The <strong>SQL</strong> statement is normally a host variable. The CCSID of the host variable is<br />

used as the CCSID of the statement text. In PL/I, it also can be a string expression.<br />

In this case, the job CCSID is used as the CCSID of the statement text.<br />

Dynamic <strong>SQL</strong> statements are processed using the CCSID of the statement text. This<br />

affects variant characters the most. For example, the not sign (¬) is located at 'BA'X<br />

in CCSID 500. This means that if the CCSID of your statement text is 500, <strong>SQL</strong><br />

expects the not sign (¬) to be located at 'BA'X.<br />

If the statement text CCSID is 65535, <strong>SQL</strong> processes variant characters as if they<br />

had a CCSID of 37. This means that <strong>SQL</strong> looks <strong>for</strong> the not sign (¬) at '5F'X.<br />

Using the PREPARE and EXECUTE statements<br />

If non-SELECT statements contain no parameter markers, they can be run<br />

dynamically using the EXECUTE IMMEDIATE statement. However, if the<br />

non-SELECT statements have parameter markers, they must be run using<br />

PREPARE and EXECUTE.<br />

The PREPARE statement prepares the non-SELECT statement (<strong>for</strong> example, the<br />

DELETE statement) and gives it a name of your choosing. If DLYPRP (*YES) is<br />

specified on the CRT<strong>SQL</strong>xxx command, the preparation is delayed until the first<br />

time the statement is used in an EXECUTE or DESCRIBE statement, unless the<br />

USING clause is specified on the PREPARE statement. In this instance, let us call it<br />

S1. After the statement has been prepared, it can be run many times within the<br />

same program, using different values <strong>for</strong> the parameter markers. The following<br />

example is of a prepared statement being run multiple times:<br />

DSTRING = 'DELETE FROM CORPDATA.EMPLOYEE WHERE EMPNO = ?';<br />

/*The ? is a parameter marker which denotes<br />

that this value is a host variable that is<br />

to be substituted each time the statement is run.*/<br />

202 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


EXEC <strong>SQL</strong> PREPARE S1 FROM :DSTRING;<br />

/*DSTRING is the delete statement that the PREPARE statement is<br />

naming S1.*/<br />

DO UNTIL (EMP =0);<br />

/*The application program reads a value <strong>for</strong> EMP from the<br />

display station.*/<br />

EXEC <strong>SQL</strong><br />

EXECUTE S1 USING :EMP;<br />

END;<br />

In routines similar to the example above, you must know the number of parameter<br />

markers and their data types, because the host variables that provide the input<br />

data are declared when the program is being written.<br />

Note: All prepared statements that are associated with an application server are<br />

destroyed whenever the connection to the application server ends.<br />

Connections are ended by a CONNECT (Type 1) statement, a DISCONNECT<br />

statement, or a RELE<strong>AS</strong>E followed by a successful COMMIT.<br />

Processing SELECT statements and using an <strong>SQL</strong>DA<br />

There are two basic types of SELECT statements: fixed-list and varying-list.<br />

To process a fixed-list SELECT statement, an <strong>SQL</strong>DA is not necessary.<br />

To process a varying-list SELECT statement, you must first declare an <strong>SQL</strong>DA<br />

structure. The <strong>SQL</strong>DA is a control block used to pass host variable input values<br />

from an application program to <strong>SQL</strong> and to receive output values from <strong>SQL</strong>. In<br />

addition, in<strong>for</strong>mation about SELECT list expressions can be returned in a<br />

PREPARE or DESCRIBE statement.<br />

Fixed-list SELECT statements<br />

In dynamic <strong>SQL</strong>, fixed-list SELECT statements are those statements designed to<br />

retrieve data of a predictable number and type. When using these statements, you<br />

can anticipate and define host variables to accommodate the retrieved data, so that<br />

an <strong>SQL</strong>DA is not necessary. Each successive FETCH returns the same number of<br />

values as the last, and these values have the same data <strong>for</strong>mats as those returned<br />

<strong>for</strong> the last FETCH. You can specify host variables the same as you would <strong>for</strong> any<br />

<strong>SQL</strong> application.<br />

You can use fixed-list dynamic SELECT statements with any <strong>SQL</strong>-supported<br />

application program.<br />

To run fixed-list SELECT statements dynamically, your application must:<br />

1. Place the input <strong>SQL</strong> statement into a host variable.<br />

2. Issue a PREPARE statement to validate the dynamic <strong>SQL</strong> statement and put it<br />

into a <strong>for</strong>m that can be run. If DLYPRP (*YES) is specified on the CRT<strong>SQL</strong>xxx<br />

command, the preparation is delayed until the first time the statement is used<br />

in an EXECUTE or DESCRIBE statement, unless the USING clause is specified<br />

on the PREPARE statement.<br />

3. Declare a cursor <strong>for</strong> the statement name.<br />

Chapter 10. Dynamic <strong>SQL</strong> Applications 203


4. Open the cursor.<br />

5. FETCH a row into a fixed list of variables (rather than into a descriptor area, as<br />

you would if you were using a varying-list SELECT statement, described in the<br />

following section, Varying-list Select-statements).<br />

6. When end of data occurs, close the cursor.<br />

7. Handle any <strong>SQL</strong> return codes that result.<br />

For example:<br />

MOVE 'SELECT EMPNO, L<strong>AS</strong>TNAME FROM CORPDATA.EMPLOYEE WHERE EMPNO>?'<br />

TO DSTRING.<br />

EXEC <strong>SQL</strong><br />

PREPARE S2 FROM :DSTRING END-EXEC.<br />

EXEC <strong>SQL</strong><br />

DECLARE C2 CURSOR FOR S2 END-EXEC.<br />

EXEC <strong>SQL</strong><br />

OPEN C2 USING :EMP END-EXEC.<br />

PERFORM FETCH-ROW UNTIL <strong>SQL</strong>CODE NOT=0.<br />

EXEC <strong>SQL</strong><br />

CLOSE C2 END-EXEC.<br />

STOP-RUN.<br />

FETCH-ROW.<br />

EXEC <strong>SQL</strong><br />

FETCH C2 INTO :EMP, :EMPNAME END-EXEC.<br />

Note: Remember that because the SELECT statement, in this case, always returns<br />

the same number and type of data items as previously run fixed-list<br />

SELECT statements, you do not have to use the <strong>SQL</strong> descriptor area<br />

(<strong>SQL</strong>DA).<br />

Varying-list Select-statements<br />

In dynamic <strong>SQL</strong>, varying-list SELECT statements are ones <strong>for</strong> which the number<br />

and <strong>for</strong>mat of result columns to be returned are not predictable; that is, you do not<br />

know how many variables you need, or what the data types are. There<strong>for</strong>e, you<br />

cannot define host variables in advance to accommodate the result columns<br />

returned.<br />

Note: In REXX, steps 5b on page 205, 6 on page 205, and 7 on page 205 are not<br />

applicable.<br />

If your application accepts varying-list SELECT statements, your program has to:<br />

1. Place the input <strong>SQL</strong> statement into a host variable.<br />

2. Issue a PREPARE statement to validate the dynamic <strong>SQL</strong> statement and put it<br />

into a <strong>for</strong>m that can be run. If DLYPRP (*YES) is specified on the CRT<strong>SQL</strong>xxx<br />

command, the preparation is delayed until the first time the statement is used<br />

in an EXECUTE or DESCRIBE statement, unless the USING clause is specified<br />

on the PREPARE statement.<br />

3. Declare a cursor <strong>for</strong> the statement name.<br />

4. Open the cursor (declared in step 3) that includes the name of the dynamic<br />

SELECT statement.<br />

5. Issue a DESCRIBE statement to request in<strong>for</strong>mation from <strong>SQL</strong> about the type<br />

and size of each column of the result table.<br />

204 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


Notes:<br />

a. You can also code the PREPARE statement with an INTO clause to<br />

per<strong>for</strong>m the functions of PREPARE and DESCRIBE with a single statement.<br />

b. If the <strong>SQL</strong>DA is not large enough to contain column descriptions <strong>for</strong> each<br />

retrieved column, the program must determine how much space is needed,<br />

get storage <strong>for</strong> that amount of space, build a new <strong>SQL</strong>DA, and reissue the<br />

DESCRIBE statement.<br />

6. Allocate the amount of storage needed to contain a row of retrieved data.<br />

7. Put storage addresses into the <strong>SQL</strong>DA (<strong>SQL</strong> descriptor area) to tell <strong>SQL</strong> where<br />

to put each item of retrieved data.<br />

8. FETCH a row.<br />

9. When end of data occurs, close the cursor.<br />

10. Handle any <strong>SQL</strong> return codes that might result.<br />

<strong>SQL</strong> Descriptor Area (<strong>SQL</strong>DA)<br />

You can use the <strong>SQL</strong>DA to pass in<strong>for</strong>mation about an <strong>SQL</strong> statement between <strong>SQL</strong><br />

and your application.<br />

The <strong>SQL</strong>DA is a collection of variables required <strong>for</strong> running the DESCRIBE and<br />

DESCRIBE TABLE statements. It also can be used on the PREPARE, OPEN,<br />

FETCH, CALL, and EXECUTE statements. An <strong>SQL</strong>DA is used with dynamic <strong>SQL</strong>.<br />

It can be used in a DESCRIBE statement, changed with the addresses of host<br />

variables, and then reused in a FETCH statement.<br />

The meaning of the in<strong>for</strong>mation in an <strong>SQL</strong>DA depends on its use. In PREPARE<br />

and DESCRIBE, an <strong>SQL</strong>DA provides in<strong>for</strong>mation to an application program about<br />

a prepared statement. In DESCRIBE TABLE, the <strong>SQL</strong>DA provides in<strong>for</strong>mation to<br />

an application program about the columns in a table or view. In OPEN, EXECUTE,<br />

CALL, and FETCH, an <strong>SQL</strong>DA provides in<strong>for</strong>mation about host variables.<br />

<strong>SQL</strong>DA is required <strong>for</strong>:<br />

v DESCRIBE<br />

v DESCRIBE TABLE<br />

<strong>SQL</strong>DA is an option <strong>for</strong>:<br />

v EXECUTE<br />

v FETCH<br />

v OPEN<br />

v PREPARE<br />

v CALL<br />

If your application lets you have several cursors open at the same time, you can<br />

code several <strong>SQL</strong>DAs, one <strong>for</strong> each dynamic SELECT statement. For more<br />

in<strong>for</strong>mation on <strong>SQL</strong>DA and <strong>SQL</strong>CA, see the <strong>SQL</strong> Reference book.<br />

<strong>SQL</strong>DAs can be used in C, COBOL, PL/I, REXX, and RPG. Because RPG <strong>for</strong><br />

<strong>AS</strong>/<strong>400</strong> does not provide a way to set pointers, pointers must be set outside the<br />

RPG <strong>for</strong> <strong>AS</strong>/<strong>400</strong> program by a PL/I, C, COBOL, or ILE RPG <strong>for</strong> <strong>AS</strong>/<strong>400</strong> program.<br />

Since the area used must be declared by the PL/I, C, COBOL, or ILE RPG <strong>for</strong><br />

<strong>AS</strong>/<strong>400</strong> program, that program must call the RPG <strong>for</strong> <strong>AS</strong>/<strong>400</strong> program.<br />

Chapter 10. Dynamic <strong>SQL</strong> Applications 205


<strong>SQL</strong>DA <strong>for</strong>mat<br />

The <strong>SQL</strong>DA consists of four variables followed by an arbitrary number of<br />

occurrences of a sequence of six variables collectively named <strong>SQL</strong>VAR.<br />

Note: The <strong>SQL</strong>DA in REXX is different. For more in<strong>for</strong>mation, see the topic<br />

Coding <strong>SQL</strong> Statements in REXX Applications in the <strong>SQL</strong> <strong>Programming</strong> with<br />

Host Languages in<strong>for</strong>mation.<br />

When an <strong>SQL</strong>DA is used in OPEN, FETCH, CALL, and EXECUTE, each occurrence<br />

of <strong>SQL</strong>VAR describes a host variable.<br />

The variables of <strong>SQL</strong>DA are as follows (variable names are in lowercase <strong>for</strong> C):<br />

<strong>SQL</strong>DAID<br />

<strong>SQL</strong>DAID is used <strong>for</strong> storage dumps. Byte 7 of <strong>SQL</strong>DAID is used to<br />

indicate if there are extension <strong>SQL</strong> VARs used <strong>for</strong> LOBs or UDTs. It is a<br />

string of 8 characters that have the value '<strong>SQL</strong>DA' after the <strong>SQL</strong>DA that<br />

is used in a PREPARE or DESCRIBE statement. It is not used <strong>for</strong> FETCH,<br />

OPEN, CALL or EXECUTE.<br />

Byte 7 can be used to determine if more than one <strong>SQL</strong>VAR entry is needed<br />

<strong>for</strong> each column. This flag is set to a blank if there are not any LOBs or<br />

distinct types.<br />

<strong>SQL</strong>DAID is not applicable in REXX.<br />

<strong>SQL</strong>DABC<br />

<strong>SQL</strong>DABC indicates the length of the <strong>SQL</strong>DA. It is a 4-byte integer that<br />

has the value <strong>SQL</strong>N*LENGTH(<strong>SQL</strong>VAR) + 16 after the <strong>SQL</strong>DA is used in a<br />

PREPARE or DESCRIBE statement. <strong>SQL</strong>DABC must have a value equal to<br />

or greater than <strong>SQL</strong>N*LENGTH(<strong>SQL</strong>VAR) + 16 prior to use by FETCH,<br />

OPEN, CALL, or EXECUTE.<br />

<strong>SQL</strong>ABC is not applicable in REXX.<br />

<strong>SQL</strong>N <strong>SQL</strong>N is a 2-byte integer that specifies the total number of occurrences of<br />

<strong>SQL</strong>VAR. It must be set prior to use by any <strong>SQL</strong> statement to a value<br />

greater than or equal to 0.<br />

<strong>SQL</strong>N is not applicable in REXX.<br />

<strong>SQL</strong>D <strong>SQL</strong>D is a 2-byte integer that specifies the pertinent number of occurrences<br />

of <strong>SQL</strong>VAR; that is, the number of host variables described by the <strong>SQL</strong>DA.<br />

This field is set by <strong>SQL</strong> on a DESCRIBE or PREPARE statement. In other<br />

statements, this field must be set prior to use to a value greater than or<br />

equal to 0 and less than or equal to <strong>SQL</strong>N.<br />

<strong>SQL</strong>VAR<br />

The variables of <strong>SQL</strong>VAR are <strong>SQL</strong>TYPE, <strong>SQL</strong>LEN, <strong>SQL</strong>RES, <strong>SQL</strong>DATA,<br />

<strong>SQL</strong>IND, and <strong>SQL</strong>NAME. These variables are set by <strong>SQL</strong> on a DESCRIBE<br />

or PREPARE statement. In other statements, they must be set prior to use.<br />

These variables are defined as follows:<br />

<strong>SQL</strong>TYPE<br />

<strong>SQL</strong>TYPE is a 2-byte integer that specifies the data type of the host<br />

variable as shown in the table below. Odd values <strong>for</strong> <strong>SQL</strong>TYPE show that<br />

the host variable has an associated indicator variable addressed by<br />

<strong>SQL</strong>IND.<br />

206 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


<strong>SQL</strong>LEN<br />

<strong>SQL</strong>LEN is a 2-byte integer variable that specifies the length attributes of<br />

the host variables shown in Figure 10-2.<br />

Table 23. <strong>SQL</strong>TYPE and <strong>SQL</strong>LEN Values <strong>for</strong> PREPARE, DESCRIBE, FETCH, OPEN, CALL, or EXECUTE<br />

<strong>SQL</strong>TYPE<br />

For PREPARE and DESCRIBE For FETCH, OPEN, CALL, and EXECUTE<br />

COLUMN DATA TYPE <strong>SQL</strong>LEN<br />

HOST VARIABLE DATA<br />

TYPE <strong>SQL</strong>LEN<br />

384/385 Date 10 Fixed-length character<br />

string representation of a<br />

date<br />

388/389 Time 8 Fixed-length character<br />

string representation of a<br />

time<br />

392/393 Timestamp 26 Fixed-length character<br />

string representation of a<br />

timestamp<br />

396/397 DataLink 6<br />

Length attribute<br />

of the column<br />

<strong>400</strong>/401 N/A N/A NUL-terminated graphic<br />

string<br />

N/A N/A<br />

392/393 Timestamp 26 Fixed-length character<br />

string representation of a<br />

timestamp<br />

404/405 BLOB 0 7<br />

408/409 CLOB 0 7<br />

412/413 DBCLOB 0 7<br />

452/453 Fixed-length character<br />

string<br />

456/457 Long varying-length<br />

character string<br />

Length attribute<br />

of the column<br />

Length attribute<br />

of the column<br />

Length attribute<br />

of the host<br />

variable<br />

Length attribute<br />

of the host<br />

variable<br />

Length attribute<br />

of the host<br />

variable<br />

Length attribute<br />

of the host<br />

variable<br />

Length attribute<br />

of the host<br />

variable<br />

BLOB Not used. 7<br />

CLOB Not used. 7<br />

DBCLOB Not used. 7<br />

Fixed-length character<br />

string<br />

Long varying-length<br />

character string<br />

460/461 N/A N/A NUL-terminated character<br />

string<br />

464/465 Varying-length graphic<br />

string<br />

Length attribute<br />

of the column<br />

468/469 Fixed-length graphic string Length attribute<br />

of the column<br />

472/473 Long varying-length<br />

graphic string<br />

Length attribute<br />

of the column<br />

Varying-length graphic<br />

string<br />

Length attribute<br />

of the host<br />

variable<br />

Length attribute<br />

of the host<br />

variable<br />

Length attribute<br />

of the host<br />

variable<br />

Length attribute<br />

of the host<br />

variable<br />

Fixed-length graphic string Length attribute<br />

of the host<br />

variable<br />

Long graphic string Length attribute<br />

of the host<br />

variable<br />

476/477 N/A N/A P<strong>AS</strong>CAL L-string Length attribute<br />

of the host<br />

variable<br />

480/481 Floating point 4 <strong>for</strong> single<br />

precision, 8 <strong>for</strong><br />

double precision<br />

Floating point 4 <strong>for</strong> single<br />

precision, 8 <strong>for</strong><br />

double precision<br />

Chapter 10. Dynamic <strong>SQL</strong> Applications 207


|<br />

Table 23. <strong>SQL</strong>TYPE and <strong>SQL</strong>LEN Values <strong>for</strong> PREPARE, DESCRIBE, FETCH, OPEN, CALL, or<br />

EXECUTE (continued)<br />

For PREPARE and DESCRIBE For FETCH, OPEN, CALL, and EXECUTE<br />

HOST VARIABLE DATA<br />

<strong>SQL</strong>TYPE COLUMN DATA TYPE <strong>SQL</strong>LEN TYPE <strong>SQL</strong>LEN<br />

484/485 Packed decimal Precision in byte Packed decimal Precision in byte<br />

1; scale in byte 2<br />

1; scale in byte 2<br />

488/489 Zoned decimal Precision in byte Zoned decimal Precision in byte<br />

1; scale in byte 2<br />

1; scale in byte 2<br />

492/493 Big integer 8 Big integer 8<br />

496/497 Large integer 4 5<br />

Large integer 4<br />

500/501 Small integer 2 5<br />

Small integer 2<br />

504/505 N/A N/A DISPLAY SIGN LEADING Precision in byte<br />

SEPARATE<br />

1; scale in byte 2<br />

916/917 N/A N/A BLOB file reference<br />

variable<br />

267<br />

920/921 N/A N/A CLOB file reference<br />

variable<br />

267<br />

924/925 N/A N/A DBCLOB file reference<br />

variable<br />

267<br />

960/961 N/A N/A BLOB locator 4<br />

964/965 N/A N/A CLOB locator 4<br />

968/969 N/A N/A DBCLOB locator 4<br />

<strong>SQL</strong>RES<br />

<strong>SQL</strong>RES is a 12-byte reserved area <strong>for</strong> boundary alignment purposes. Note<br />

that, in OS/<strong>400</strong>, pointers must be on a quad-word boundary.<br />

<strong>SQL</strong>RES is not applicable in REXX.<br />

<strong>SQL</strong>DATA<br />

<strong>SQL</strong>DATA is a 16-byte pointer variable that specifies the address of the<br />

host variables when the <strong>SQL</strong>DA is used on OPEN, FETCH, CALL, and<br />

EXECUTE.<br />

When the <strong>SQL</strong>DA is used on PREPARE and DESCRIBE, this area is<br />

overlaid with the following in<strong>for</strong>mation:<br />

The CCSID of a character, date, time, timestamp, and graphic field is<br />

stored in the third and fourth bytes of <strong>SQL</strong>DATA. For BIT data, the CCSID<br />

is 65535. In REXX, the CCSID is returned in the variable <strong>SQL</strong>CCSID.<br />

<strong>SQL</strong>IND<br />

<strong>SQL</strong>IND is a 16-byte pointer that specifies the address of a small integer<br />

host variable that is used as an indication of null or not null when the<br />

<strong>SQL</strong>DA is used on OPEN, FETCH, CALL, and EXECUTE. A negative value<br />

indicates null and a non-negative indicates not null. This pointer is only<br />

used if <strong>SQL</strong>TYPE contains an odd value.<br />

5. Large and small binary numbers can be represented in the <strong>SQL</strong> descriptor area (<strong>SQL</strong>DA) as either lengths 2 or 4. They can also be<br />

represented with the precision in byte 1 and the scale in byte 2. If the first byte is greater than X’00’, it indicates precision and<br />

scale. Big integer numbers do not allow a precision and scale. The <strong>SQL</strong>DA defines them as length 8.<br />

6. The DataLink datatype is only returned on DESCRIBE TABLE.<br />

7. The len.sqllonglen field in the secondary <strong>SQL</strong>VAR contains the length attribute of the column.<br />

208 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


When the <strong>SQL</strong>DA is used on PREPARE and DESCRIBE, this area is<br />

reserved <strong>for</strong> future use.<br />

<strong>SQL</strong>NAME<br />

<strong>SQL</strong>NAME is a variable-length character variable with a maximum length<br />

of 30, which contains the name of selected column, label, or system column<br />

name after a PREPARE or DESCRIBE. In OPEN, FETCH, EXECUTE, or<br />

CALL, it can be used to pass the CCSID of character strings. CCSIDs can<br />

be passed <strong>for</strong> character, graphic, date, time, and timestamp host variables.<br />

The <strong>SQL</strong>NAME field in an <strong>SQL</strong>VAR array entry of an input <strong>SQL</strong>DA can be<br />

set to specify the CCSID:<br />

Length of <strong>SQL</strong>NAME <strong>SQL</strong>NAME<br />

Data Type Sub-type <strong>SQL</strong>NAME Bytes 1 & 2 Bytes 3 & 4<br />

Character SBCS 8 X’0000’ CCSID<br />

Character MIXED 8 X’0000’ CCSID<br />

Character BIT 8 X’0000’ X’FFFF’<br />

GRAPHIC not applicable 8 X’0000’ CCSID<br />

Any other data<br />

type<br />

not applicable not applicable not applicable not applicable<br />

Note: It is important to remember that the <strong>SQL</strong>NAME field is only <strong>for</strong><br />

overriding the CCSID. Applications that use the defaults do not<br />

need to pass CCSID in<strong>for</strong>mation. If a CCSID is not passed, the<br />

default CCSID <strong>for</strong> the job is used.<br />

The default <strong>for</strong> graphic host variables is the associated double-byte CCSID<br />

<strong>for</strong> the job CCSID. If an associated double-byte CCSID does not exist,<br />

65535 is used.<br />

<strong>SQL</strong>VAR2<br />

The Extended <strong>SQL</strong>VAR structure. Extended <strong>SQL</strong>VARs are only needed (<strong>for</strong><br />

all columns of the result) if the result includes any LOB or distinct type<br />

columns. For distinct types, they contain the distinct type name. For LOBs,<br />

they contain the length attribute of the host variable and a pointer to the<br />

buffer that contains the actual length. If locators are used to represent<br />

LOBs, these entries are not necessary. The number of Extended <strong>SQL</strong>VAR<br />

occurrences needed depends on the statement that the <strong>SQL</strong>DA was<br />

provided <strong>for</strong> and the data types of the columns or parameters being<br />

described. Byte 7 of <strong>SQL</strong>DAID is always set to the number of sets of<br />

<strong>SQL</strong>VARs necessary.<br />

If <strong>SQL</strong>D is not set to a sufficient number of <strong>SQL</strong>VAR occurrences:<br />

v <strong>SQL</strong>D is set to the total number of <strong>SQL</strong>VAR occurrences needed <strong>for</strong> all<br />

sets.<br />

v A +237 warning is returned in the <strong>SQL</strong>CODE field of the <strong>SQL</strong>CA if at<br />

least enough were specified <strong>for</strong> the Base <strong>SQL</strong>VAR Entries. The Base<br />

<strong>SQL</strong>VAR entries are returned, but no Extended <strong>SQL</strong>VARs are returned.<br />

v A +239 warning is returned in the <strong>SQL</strong>CODE field of the <strong>SQL</strong>CA if<br />

enough <strong>SQL</strong>VARs were not specified <strong>for</strong> even the Base <strong>SQL</strong>VAR Entries.<br />

No <strong>SQL</strong>VAR entries are returned.<br />

<strong>SQL</strong>LONGLEN<br />

<strong>SQL</strong>LONGLEN is part of the Extended <strong>SQL</strong>VAR. It is a 4-byte integer<br />

variable that specifies the length attributes of a LOB (BLOB, CLOB, or<br />

DBCLOB) host variable.<br />

Chapter 10. Dynamic <strong>SQL</strong> Applications 209


<strong>SQL</strong>DATALEN<br />

<strong>SQL</strong>DATALEN is part of the Extended <strong>SQL</strong>VAR. It is a 16-byte pointer<br />

variable that specifies the address of the length of the host variable. It is<br />

used <strong>for</strong> LOB (BLOB, CLOB, and DBCLOB) host variables only. If this field<br />

is NULL, then the actual length is stored in the 4 bytes immediately be<strong>for</strong>e<br />

the start of the data, and <strong>SQL</strong>DATA points to the first byte of the field<br />

length. The actual length indicates the number of bytes <strong>for</strong> a BLOB or<br />

CLOB, and the number of characters <strong>for</strong> a DBCLOB.<br />

If this field is not NULL, it contains a pointer to a 4-byte long buffer that<br />

contains the actual length in bytes (even <strong>for</strong> DBCLOB) of the data in the<br />

buffer pointed to from the <strong>SQL</strong>DATA field in the matching base <strong>SQL</strong>VAR.<br />

<strong>SQL</strong>DATATYPE_NAME<br />

<strong>SQL</strong>DATATYPE_NAME is part of the Extended <strong>SQL</strong>VAR. It is a<br />

variable-length character variable with a maximum length of 30. It is set to<br />

one of the following:<br />

v For a distinct type column, the database manager sets this to the fully<br />

qualified distinct type name.<br />

v If the qualified name is longer than 30 bytes, it is truncated.<br />

v For a label, the database manager sets this to the first 20 bytes of the<br />

label. For a column name, the database manager sets this to the column<br />

name.<br />

Example: Select-statement <strong>for</strong> allocating storage <strong>for</strong> <strong>SQL</strong>DA<br />

The SELECT statement can be read from a display station or from a host variable,<br />

or it can be developed within an application program. The following example<br />

shows a SELECT statement read from a display station:<br />

SELECT WORKDEPT, PHONENO FROM CORPDATA.EMPLOYEE<br />

WHERE L<strong>AS</strong>TNAME = 'PARKER'<br />

Note: The SELECT statement has no INTO clause. Dynamic SELECT statements<br />

must not have an INTO clause, even if they return only one row.<br />

When the statement is read, it is assigned to a host variable. The host variable (<strong>for</strong><br />

example, named DSTRING) is then processed, using the PREPARE statement, as<br />

shown:<br />

EXEC <strong>SQL</strong><br />

PREPARE S1 FROM :DSTRING;<br />

Allocating <strong>SQL</strong>DA Storage<br />

You can allocate storage <strong>for</strong> the <strong>SQL</strong>DA. (Allocating storage is not necessary in<br />

REXX.) The techniques <strong>for</strong> acquiring storage are language dependent. The <strong>SQL</strong>DA<br />

must be allocated on a 16-byte boundary. The <strong>SQL</strong>DA consists of a fixed-length<br />

header, 16 bytes long. The header is followed by a varying-length array section<br />

(<strong>SQL</strong>VAR), each element of which is 80 bytes in length. The amount of storage you<br />

need to allocate depends on how many elements you want to have in the <strong>SQL</strong>VAR<br />

array. Each column you select must have a corresponding <strong>SQL</strong>VAR array element.<br />

There<strong>for</strong>e, the number of columns listed in your SELECT statement determines<br />

how many <strong>SQL</strong>VAR array elements you should allocate. Because SELECT<br />

statements are specified at run time, however, it is impossible to know how many<br />

columns will be accessed. Consequently, you must estimate the number of<br />

columns. Suppose, in this example, that no more than 20 columns are ever<br />

expected to be accessed by a single SELECT statement. This means that the<br />

210 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


<strong>SQL</strong>VAR array should have a dimension of 20 (<strong>for</strong> an <strong>SQL</strong>DA size 20 x 80, or 1600,<br />

plus 16 <strong>for</strong> a total of 1616 bytes), because each item in the select-list must have a<br />

corresponding entry in <strong>SQL</strong>VAR.<br />

Having allocated what you estimated to be enough space <strong>for</strong> your <strong>SQL</strong>DA in the<br />

<strong>SQL</strong>N field of the <strong>SQL</strong>DA, set an initial value equal to the number of <strong>SQL</strong>VAR<br />

array elements. In the following example, set <strong>SQL</strong>N to 20:<br />

Allocate space <strong>for</strong> an <strong>SQL</strong>DA of 1616 bytes on a quadword boundary<br />

<strong>SQL</strong>N = 20;<br />

Note: In PL/I the ALLOCATE statement is the only way to ensure the allocation<br />

of a quadword boundary.<br />

Having allocated storage, you can now issue a DESCRIBE statement.<br />

EXEC <strong>SQL</strong><br />

DESCRIBE S1 INTO :<strong>SQL</strong>DA;<br />

When the DESCRIBE statement is run, <strong>SQL</strong> places values in the <strong>SQL</strong>DA that<br />

provide in<strong>for</strong>mation about the select-list. The following Figure 8 shows the<br />

contents of the <strong>SQL</strong>DA after the DESCRIBE is run:<br />

<strong>SQL</strong>VAR<br />

Element 1<br />

(80 bytes)<br />

<strong>SQL</strong>VAR<br />

Element 2<br />

(80 bytes)<br />

0<br />

0<br />

3<br />

4<br />

7 P H O N E N O<br />

(reserved)<br />

(reserved)<br />

<strong>SQL</strong>DA Size<br />

<strong>SQL</strong>DA (8 bytes) 1616 <strong>SQL</strong>DA (4 bytes) 20 <strong>SQL</strong>N (2 bytes) 2 <strong>SQL</strong>D (2 bytes)<br />

453<br />

8<br />

453<br />

37<br />

37<br />

W O R K D E P T<br />

Figure 8. Contents of <strong>SQL</strong>DA after a DESCRIBE Is Run<br />

<strong>SQL</strong>DAID is an identifier field initialized by <strong>SQL</strong> when a DESCRIBE is run.<br />

<strong>SQL</strong>DABC is the byte count or size of the <strong>SQL</strong>DA. You can ignore these <strong>for</strong> now.<br />

The example <strong>for</strong> running the SELECT statement <strong>for</strong> S1 is:<br />

SELECT WORKDEPT, PHONENO<br />

FROM CORPDATA.EMPLOYEE<br />

WHERE L<strong>AS</strong>TNAME = 'PARKER'<br />

RV3W188-0<br />

Your program might have to alter the <strong>SQL</strong>N value if the <strong>SQL</strong>DA is not large<br />

enough to contain the described <strong>SQL</strong>VAR elements. For example, let the SELECT<br />

statement contain 27 select-list expressions instead of the 20 or less that you<br />

estimated. Because the <strong>SQL</strong>DA was only allocated with an <strong>SQL</strong>VAR dimension of<br />

20 elements, <strong>SQL</strong> cannot describe the select-list, because the <strong>SQL</strong>VAR has too many<br />

elements. <strong>SQL</strong> sets the <strong>SQL</strong>D to the actual number of columns specified by the<br />

Chapter 10. Dynamic <strong>SQL</strong> Applications 211


SELECT statement, and the remainder of the structure is ignored. There<strong>for</strong>e, after a<br />

DESCRIBE, you should compare the <strong>SQL</strong>N to the <strong>SQL</strong>D. If the value of <strong>SQL</strong>D is<br />

greater than the value of <strong>SQL</strong>N, allocate a larger <strong>SQL</strong>DA based on the value in<br />

<strong>SQL</strong>D, as follows:<br />

EXEC <strong>SQL</strong><br />

DESCRIBE S1 INTO :<strong>SQL</strong>DA;<br />

IF <strong>SQL</strong>N


<strong>SQL</strong>VAR<br />

Element 1<br />

(80 bytes)<br />

<strong>SQL</strong>VAR<br />

Element 2<br />

(80 bytes)<br />

453<br />

If you specify NAMES (or omit the USING parameter entirely), only column<br />

names are placed in the <strong>SQL</strong>NAME field. If you specify SYSTEM NAMES, only the<br />

system column names are placed in the <strong>SQL</strong>NAME field. If you specify LABELS,<br />

only labels associated with the columns listed in your <strong>SQL</strong> statement are entered<br />

here. If you specify ANY, labels are placed in the <strong>SQL</strong>NAME field <strong>for</strong> those<br />

columns that have labels; otherwise, the column names are entered. If you specify<br />

BOTH, names and labels are both placed in the field with their corresponding<br />

lengths. If you specify BOTH, however, you must remember to double the size of<br />

the <strong>SQL</strong>VAR array because you are including twice the number of elements. If you<br />

specify ALL, column names, labels, and system column names are placed in the<br />

field with their corresponding lengths. If you specify ALL, remember to triple the<br />

size of the <strong>SQL</strong>VAR array. If you specify ALL:<br />

v Names, and labels are placed in the field with their corresponding lengths.<br />

v The size of the <strong>SQL</strong>VAR array must triple because you are including the number<br />

of elements.<br />

For more in<strong>for</strong>mation on the USING option and on column labels, see the <strong>SQL</strong><br />

Reference book.<br />

In the example, the second <strong>SQL</strong>VAR element contains the in<strong>for</strong>mation <strong>for</strong> the<br />

second column used in the select: PHONENO. The 453 code in <strong>SQL</strong>TYPE specifies<br />

that PHONENO is a CHAR column. For a CHAR data type of length 4, <strong>SQL</strong> sets<br />

<strong>SQL</strong>LEN to 4.<br />

After analyzing the result of the DESCRIBE, you can allocate storage <strong>for</strong> variables<br />

containing the result of the SELECT statement. For WORKDEPT, a character field<br />

of length 3 must be allocated; <strong>for</strong> PHONENO, a character field of length 4 must be<br />

allocated.<br />

After the storage is allocated, you must set <strong>SQL</strong>DATA and <strong>SQL</strong>IND to point to the<br />

appropriate areas. For each element of the <strong>SQL</strong>VAR array, <strong>SQL</strong>DATA points to the<br />

place where the results are to be put. <strong>SQL</strong>IND points to the place where the null<br />

indicator is to be put. The following figure shows what the structure looks like<br />

now:<br />

S Q L D A 1616 20 2<br />

3<br />

Address of FLDA<br />

Address of FLDAI<br />

8 W O R K D E P T<br />

453<br />

4<br />

Address of FLDB<br />

Address of FLDBI<br />

7 P H O N E N O<br />

(reserved)<br />

(reserved)<br />

This is what was done so far:<br />

<strong>SQL</strong>DA Size<br />

FLDA: (CHAR(3))<br />

FLDB: (CHAR(4))<br />

Indicator<br />

Variables: (halfword)<br />

FLDAI: FLDBI:<br />

RV3W189-0<br />

Chapter 10. Dynamic <strong>SQL</strong> Applications 213


EXEC <strong>SQL</strong><br />

INCLUDE <strong>SQL</strong>DA;<br />

/*Read a statement into the DSTRING varying-length<br />

character string host variable.*/<br />

EXEC <strong>SQL</strong><br />

PREPARE S1 FROM :DSTRING;<br />

/*Allocate an <strong>SQL</strong>DA of 1616 bytes.*/<br />

<strong>SQL</strong>N =20;<br />

EXEC <strong>SQL</strong><br />

DESCRIBE S1 INTO :<strong>SQL</strong>DA;<br />

/*Analyze the results of the DESCRIBE.*/<br />

/*Allocate storage to hold one row of<br />

the result table.*/<br />

/*Set <strong>SQL</strong>DATA and <strong>SQL</strong>IND <strong>for</strong> each column<br />

of the result table.*/<br />

Using a cursor<br />

You are now ready to retrieve the SELECT statements results. Dynamically defined<br />

SELECT statements must not have an INTO statement. There<strong>for</strong>e, all dynamically<br />

defined SELECT statements must use a cursor. Special <strong>for</strong>ms of the DECLARE,<br />

OPEN, and FETCH are used <strong>for</strong> dynamically defined SELECT statements.<br />

The DECLARE statement <strong>for</strong> the example statement is:<br />

EXEC <strong>SQL</strong> DECLARE C1 CURSOR FOR S1;<br />

As you can see, the only difference is that the name of the prepared SELECT<br />

statement (S1) is used instead of the SELECT statement itself. The actual retrieval<br />

of result rows is made as follows:<br />

EXEC <strong>SQL</strong><br />

OPEN C1;<br />

EXEC <strong>SQL</strong><br />

FETCH C1 USING DESCRIPTOR :<strong>SQL</strong>DA;<br />

DO WHILE (<strong>SQL</strong>CODE = 0);<br />

/*Display ... the results pointed to by <strong>SQL</strong>DATA*/<br />

END;<br />

/*Display ('END OF LIST')*/<br />

EXEC <strong>SQL</strong><br />

CLOSE C1;<br />

The cursor is opened, and the result table is evaluated. Notice that there are no<br />

input host variables needed <strong>for</strong> the example SELECT statement. The SELECT result<br />

rows are then returned using FETCH. On the FETCH statement, there is no list of<br />

output host variables. Rather, the FETCH statement tells <strong>SQL</strong> to return results into<br />

areas described by the descriptor called <strong>SQL</strong>DA. The same <strong>SQL</strong>DA that was set up<br />

by DESCRIBE is now being used <strong>for</strong> the output of the SELECT statement. In<br />

particular, the results are returned into the storage areas pointed to by the<br />

<strong>SQL</strong>DATA and <strong>SQL</strong>IND fields of the <strong>SQL</strong>VAR elements. The following figure<br />

shows what the structure looks like after the FETCH statement has been processed.<br />

214 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


<strong>SQL</strong>VAR<br />

Element 1<br />

(80 bytes)<br />

<strong>SQL</strong>VAR<br />

Element 2<br />

(80 bytes)<br />

453<br />

S Q L D A 1616 20 2<br />

3<br />

Address of FLDA<br />

Address of FLDAI<br />

8 W O R K D E P T<br />

453<br />

4<br />

Address of FLDB<br />

Address of FLDBI<br />

7 P H O N E N O<br />

The meaning of the SMALLINT pointed to by <strong>SQL</strong>IND is the same as any other<br />

indicator variable:<br />

0 Denotes that the returned value is not null.<br />

0 Denotes that the returned value was truncated because<br />

the storage area furnished was not large enough.<br />

The indicator variable contains the length be<strong>for</strong>e<br />

truncation.<br />

Note: Unless HOLD is specified, dynamic cursors are closed during COMMIT or<br />

ROLLBACK.<br />

Parameter markers<br />

(reserved)<br />

(reserved)<br />

<strong>SQL</strong>DA Size<br />

FLDA: (CHAR(3))<br />

FLDB: (CHAR(4))<br />

Indicator<br />

Variables: (halfword)<br />

FLDAI: FLDBI:<br />

In the example we are using, the SELECT statement that was dynamically run had<br />

predictable parameters (input host variables) in the WHERE clause. In the<br />

example, it was:<br />

WHERE L<strong>AS</strong>TNAME = 'PARKER'<br />

If you want to run the same SELECT statement several times, using different<br />

values <strong>for</strong> L<strong>AS</strong>TNAME, you can use an <strong>SQL</strong> statement such as PREPARE or<br />

EXECUTE (as described in “Using the PREPARE and EXECUTE statements” on<br />

page 202) like this:<br />

SELECT WORKDEPT, PHONENO FROM CORPDATA.EMPLOYEE WHERE L<strong>AS</strong>TNAME = ?<br />

When your parameters are not predictable, your application cannot know the<br />

number or types of the parameters until run time. You can arrange to receive this<br />

in<strong>for</strong>mation at the time your application is run, and by using a USING<br />

DESCRIPTOR on the OPEN statement, you can substitute the values contained in<br />

specific host variables <strong>for</strong> the parameter markers included in the WHERE clause of<br />

the SELECT statement.<br />

To code such a program, you need to use the OPEN statement with the USING<br />

DESCRIPTOR clause. This <strong>SQL</strong> statement is used to not only open a cursor, but to<br />

replace each parameter marker with the value of the corresponding host variable.<br />

The descriptor name that you specify with this statement must identify an <strong>SQL</strong>DA<br />

that contains a valid description of those host variables. This <strong>SQL</strong>DA, unlike those<br />

E11<br />

4502<br />

0 0<br />

RV3W190-0<br />

Chapter 10. Dynamic <strong>SQL</strong> Applications 215


|<br />

previously described, is not used to return in<strong>for</strong>mation on data items that are part<br />

of a SELECT list. That is, it is not used as output from a DESCRIBE statement, but<br />

as input to the OPEN statement. It provides in<strong>for</strong>mation on host variables that are<br />

used to replace parameter markers in the WHERE clause of the SELECT statement.<br />

It gets this in<strong>for</strong>mation from the application, which must be designed to place<br />

appropriate values into the necessary fields of the <strong>SQL</strong>DA. The <strong>SQL</strong>DA is then<br />

ready to be used as a source of in<strong>for</strong>mation <strong>for</strong> <strong>SQL</strong> in the process of replacing<br />

parameter markers with host variable data.<br />

When you use the <strong>SQL</strong>DA <strong>for</strong> input to the OPEN statement with the USING<br />

DESCRIPTOR clause, not all of its fields have to be filled in. Specifically,<br />

<strong>SQL</strong>DAID, <strong>SQL</strong>RES, and <strong>SQL</strong>NAME can be left blank (<strong>SQL</strong>NAME (<strong>SQL</strong>CCSID in<br />

REXX) can be set if a specific CCSID is needed.) There<strong>for</strong>e, when you use this<br />

method <strong>for</strong> replacing parameter markers with host variable values, you need to<br />

determine:<br />

v How many ? parameter markers are there?<br />

v What are the data types and attributes of these parameters markers (<strong>SQL</strong>TYPE,<br />

<strong>SQL</strong>LEN, and <strong>SQL</strong>NAME)?<br />

v Do you want an indicator variable?<br />

In addition, if the routine is to handle both SELECT and non SELECT statements,<br />

you may want to determine what category of statement it is. (Alternatively, you<br />

can write code to look <strong>for</strong> the SELECT keyword.)<br />

If your application uses parameter markers, your program has to:<br />

1. Read a statement into the DSTRING varying-length character string host<br />

variable.<br />

2. Determine the number of ? parameter markers.<br />

3. Allocate an <strong>SQL</strong>DA of that size.<br />

This is not applicable in REXX.<br />

4. Set <strong>SQL</strong>N and <strong>SQL</strong>D to the number of ? parameter markers.<br />

<strong>SQL</strong>N is not applicable in REXX.<br />

5. Set <strong>SQL</strong>DABC equal to <strong>SQL</strong>N*LENGTH(<strong>SQL</strong>VAR) + 16.<br />

This is not applicable in REXX.<br />

6. For each ? parameter marker:<br />

a. Determine the data types, lengths, and indicators.<br />

b. Set <strong>SQL</strong>TYPE and <strong>SQL</strong>LEN.<br />

c. Allocate storage to hold the input values (the ? values).<br />

d. Set these values.<br />

e. Set <strong>SQL</strong>DATA and <strong>SQL</strong>IND (if applicable) <strong>for</strong> each ? parameter marker.<br />

f. If character variables are used, and they are in a CCSID other than the job<br />

default CCSID, set <strong>SQL</strong>NAME (<strong>SQL</strong>CCSID in REXX) accordingly.<br />

g. If graphic variables are used and they have a CCSID other than the<br />

associated DBCS CCSID <strong>for</strong> the job CCSID, set the <strong>SQL</strong>NAME (<strong>SQL</strong>CCSID<br />

in REXX) to that CCSID.<br />

h. Issue the OPEN statement with a USING DESCRIPTOR clause to open your<br />

cursor and substitute a host variable value <strong>for</strong> each of the parameter<br />

markers.<br />

The statement can then be processed normally.<br />

216 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


|<br />

|<br />

|<br />

|<br />

|<br />

|<br />

|<br />

|<br />

|<br />

|<br />

|<br />

|<br />

|<br />

|<br />

|<br />

|<br />

|<br />

|<br />

|<br />

|<br />

|<br />

|<br />

|<br />

|<br />

|<br />

|<br />

|<br />

|<br />

|<br />

|<br />

|<br />

|<br />

|<br />

|<br />

Chapter 11. Use of dynamic <strong>SQL</strong> through client interfaces<br />

Accessing data with Java<br />

Accessing data with Domino<br />

You can access <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> data through client interfaces on <strong>AS</strong>/<strong>400</strong>. The<br />

following topics help you get started with required tasks:<br />

v “Accessing data with Java”<br />

v “Accessing data with Domino”<br />

v “Accessing data with Open Database Connectivity (ODBC)”<br />

You can access <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> data in your Java programs with the <strong>AS</strong>/<strong>400</strong><br />

Developer Kit <strong>for</strong> Java Java Database Connectivity (JDBC) driver. The driver lets<br />

you per<strong>for</strong>m the following tasks.<br />

v Access <strong>AS</strong>/<strong>400</strong> database files<br />

v Access JDBC database functions with embedded Structured Query Language<br />

(<strong>SQL</strong>) <strong>for</strong> Java<br />

v Run <strong>SQL</strong> statements and process results.<br />

See the topic ″Accessing your <strong>AS</strong>/<strong>400</strong> database with the <strong>AS</strong>/<strong>400</strong> Developer Kit <strong>for</strong><br />

Java JDBC driver″ in the <strong>AS</strong>/<strong>400</strong> In<strong>for</strong>mation Center <strong>for</strong> details on how you can<br />

use the JDBC driver.<br />

Domino <strong>for</strong> <strong>AS</strong>/<strong>400</strong> is a Domino server product that lets you integrate data from<br />

<strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> databases and Domino databases in both directions. To take<br />

advantage of this integration, you need to understand and manage how<br />

authorizations work between the two types of databases. For details, see the<br />

″Planning authority <strong>for</strong> Domino database integration″ topic in the Domino <strong>for</strong><br />

<strong>AS</strong>/<strong>400</strong> category of the <strong>AS</strong>/<strong>400</strong> In<strong>for</strong>mation Center.<br />

Accessing data with Open Database Connectivity (ODBC)<br />

You use the Client Access Express ODBC Driver to enable your ODBC client<br />

applications to effectively share data with each other and with the <strong>AS</strong>/<strong>400</strong>. See<br />

″Setting up the Express ODBC driver″ in the Client Access Express category of the<br />

<strong>AS</strong>/<strong>400</strong> In<strong>for</strong>mation Center.<br />

See the ″Database <strong>Programming</strong>″ topic in the same category <strong>for</strong> additional details.<br />

© Copyright IBM Corp. 2000 217


218 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


Chapter 12. Using Interactive <strong>SQL</strong><br />

This chapter describes how to use interactive <strong>SQL</strong> to run <strong>SQL</strong> statements and use<br />

the prompt function. Overview in<strong>for</strong>mation and tips on using interactive <strong>SQL</strong> are<br />

provided. If you want to learn how to use <strong>SQL</strong>, you should see Chapter 2. Getting<br />

Started with <strong>SQL</strong>. Special considerations <strong>for</strong> using interactive <strong>SQL</strong> with a remote<br />

connection are covered in “Accessing remote databases with interactive <strong>SQL</strong>” on<br />

page 229.<br />

Basic functions of interactive <strong>SQL</strong><br />

Interactive <strong>SQL</strong> allows the programmer or database administrator to quickly and<br />

easily define, update, delete, or look at data <strong>for</strong> testing, problem analysis, and<br />

database maintenance. A programmer, using interactive <strong>SQL</strong>, can insert rows into a<br />

table and test the <strong>SQL</strong> statements be<strong>for</strong>e running them in an application program.<br />

A database administrator can use interactive <strong>SQL</strong> to grant or revoke privileges,<br />

create or drop collections, tables, or views, or select in<strong>for</strong>mation from system<br />

catalog tables.<br />

After an interactive <strong>SQL</strong> statement is run, a completion message or an error<br />

message is displayed. In addition, status messages are normally displayed during<br />

long-running statements.<br />

You can see help on a message by positioning the cursor on the message and<br />

pressing F1=Help.<br />

The basic functions supplied by interactive <strong>SQL</strong> are:<br />

v The statement entry function allows you to:<br />

– Type in an interactive <strong>SQL</strong> statement and run it.<br />

– Retrieve and edit statements.<br />

– Prompt <strong>for</strong> <strong>SQL</strong> statements.<br />

– Page through previous statements and messages.<br />

– Call session services.<br />

– Invoke list selection function.<br />

– Exit interactive <strong>SQL</strong>.<br />

v The prompt function allows you to type either a complete <strong>SQL</strong> statement or a<br />

partial <strong>SQL</strong> statement, press F4=Prompt, and then be prompted <strong>for</strong> the syntax of<br />

the statement. It also allows you to press F4 to get a menu of all <strong>SQL</strong> statements.<br />

From this menu, you can select a statement and be prompted <strong>for</strong> the syntax of<br />

the statement.<br />

v The list selection function allows you to select from lists of your authorized<br />

relational databases, collections, tables, views, columns, constraints, or <strong>SQL</strong><br />

packages.<br />

The selections you make from the lists can be inserted into the <strong>SQL</strong> statement at<br />

the cursor position.<br />

v The session services function allows you to:<br />

– Change session attributes.<br />

– Print the current session.<br />

© Copyright IBM Corp. 2000 219


– Remove all entries from the current session.<br />

– Save the session in a source file.<br />

Starting interactive <strong>SQL</strong><br />

You can start using interactive <strong>SQL</strong> by typing STR<strong>SQL</strong> on an <strong>AS</strong>/<strong>400</strong> command line.<br />

For a complete description of the command and its parameters, see Appendix C.<br />

<strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> CL Command Descriptions.<br />

The Enter <strong>SQL</strong> Statements display appears. This is the main interactive <strong>SQL</strong><br />

display. From this display, you can enter <strong>SQL</strong> statements and use:<br />

v F4=prompt<br />

v F13=Session services<br />

v F16=Select collections<br />

v F17=Select tables<br />

v F18=Select columns<br />

Enter <strong>SQL</strong> Statements<br />

Type <strong>SQL</strong> statement, press Enter.<br />

Current connection is to relational database rdjacque.<br />

===>_____________________________________________________________________<br />

_____________________________________________________________________<br />

_____________________________________________________________________<br />

_____________________________________________________________________<br />

_____________________________________________________________________<br />

_____________________________________________________________________<br />

_____________________________________________________________________<br />

_____________________________________________________________________<br />

_____________________________________________________________________<br />

_____________________________________________________________________<br />

_____________________________________________________________________<br />

_____________________________________________________________________<br />

_____________________________________________________________________<br />

_____________________________________________________________________<br />

_____________________________________________________________________<br />

F3=Exit F4=Prompt F6=Insert line F9=Retrieve F10=Copy line<br />

F12=Cancel F13=Services F24=More keys<br />

Press F24=More keys to view the remaining function keys.<br />

Bottom<br />

_____________________________________________________________________<br />

_____________________________________________________________________<br />

_____________________________________________________________________<br />

_____________________________________________________________________<br />

Bottom<br />

F14=Delete line F15=Split line F16=Select collections (libraries)<br />

F17=Select tables F18=Select columns F24=More keys<br />

(files) (fields)<br />

Note: If you are using the system naming convention, the names in parentheses<br />

appear instead of the names shown above.<br />

An interactive session consists of:<br />

v Parameter values you specified <strong>for</strong> the STR<strong>SQL</strong> command .<br />

220 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


v <strong>SQL</strong> statements you entered in the session along with corresponding messages<br />

that follow each <strong>SQL</strong> statement<br />

v Values of any parameters you changed using the session services function<br />

v List selections you have made<br />

Interactive <strong>SQL</strong> supplies a unique session-ID consisting of your user ID and the<br />

current work station ID. This session-ID concept allows multiple users with the<br />

same user ID to use interactive <strong>SQL</strong> from more than one work station at the same<br />

time. Also, more than one interactive <strong>SQL</strong> session can be run from the same work<br />

station at the same time from the same user ID.<br />

If an <strong>SQL</strong> session exists and is being re-entered, any parameters specified on the<br />

STR<strong>SQL</strong> command are ignored. The parameters from the existing <strong>SQL</strong> session are<br />

used.<br />

Using statement entry function<br />

Prompting<br />

The statement entry function is the function you first enter when selecting<br />

interactive <strong>SQL</strong>. You return to the statement entry function after processing each<br />

interactive <strong>SQL</strong> statement.<br />

In the statement entry function, you type or prompt <strong>for</strong> the entire <strong>SQL</strong> statement<br />

and then submit it <strong>for</strong> processing by pressing the Enter key.<br />

Typing statements<br />

The statement you type on the command line can be one or more lines long. You<br />

cannot type comments <strong>for</strong> the <strong>SQL</strong> statement in interactive <strong>SQL</strong>. When the<br />

statement has been processed, the statement and the resulting message are moved<br />

upward on the display. You can then enter another statement.<br />

If a statement is recognized by <strong>SQL</strong> but contains a syntax error, the statement and<br />

the resulting text message (syntax error) are moved upward on the display. In the<br />

input area, a copy of the statement is shown with the cursor positioned at the<br />

syntax error. You can place the cursor on the message and press F1=Help <strong>for</strong> more<br />

in<strong>for</strong>mation about the error.<br />

You can page through previous statements, commands, and messages. Press<br />

F9=Retrieve with your cursor on a previous statement to place a copy of that<br />

statement in the input area. If you need more room to type an <strong>SQL</strong> statement, page<br />

down on the display.<br />

The prompt function helps you supply the necessary in<strong>for</strong>mation <strong>for</strong> the syntax of<br />

the statement you want to use. The prompt function can be used in any of the<br />

three statement processing modes: *RUN, *VLD, and *SYN.<br />

You have two options when using the prompter:<br />

v Type the verb of the statement be<strong>for</strong>e pressing F4=Prompt.<br />

The statement is parsed and the clauses that are completed are filled in on the<br />

prompt displays.<br />

If you type SELECT and press F4=Prompt, the following display appears:<br />

Chapter 12. Using Interactive <strong>SQL</strong> 221


Specify SELECT Statement<br />

Type SELECT statement in<strong>for</strong>mation. Press F4 <strong>for</strong> a list.<br />

FROM tables . . . . . . . . _____________________________________________<br />

SELECT columns . ..... _____________________________________________<br />

WHERE conditions ..... _____________________________________________<br />

GROUP BY columns ..... _____________________________________________<br />

HAVING conditions ..... _____________________________________________<br />

ORDER BY columns ..... _____________________________________________<br />

FOR UPDATE OF columns ... _____________________________________________<br />

Type choices, press Enter.<br />

DISTINCT rows in result table . . ....... N Y=Yes,N=No<br />

UNION with another SELECT ........... N Y=Yes, N=No<br />

Specify additional options ........... N Y=Yes,N=No<br />

Bottom<br />

F3=Exit F4=Prompt F5=Refresh F6=Insert line F9=Specify subquery<br />

F10=Copy line F12=Cancel F14=Delete line F15=Split line F24=More keys<br />

v Press F4=Prompt be<strong>for</strong>e typing anything on the Enter <strong>SQL</strong> Statements display.<br />

You are shown a list of statements. The list of statements varies and depends on<br />

the current interactive <strong>SQL</strong> statement processing mode. For syntax check mode<br />

with a language other than *NONE, the list includes all <strong>SQL</strong> statements. For run<br />

and validate modes, only statements that can be run in interactive <strong>SQL</strong> are<br />

shown. You can select the number of the statement you want to use. The system<br />

prompts you <strong>for</strong> the statement you selected.<br />

If you press F4=Prompt without typing anything, the following display appears:<br />

Select one of the following:<br />

1. ALTER TABLE<br />

2. CALL<br />

3. COMMENT ON<br />

4. COMMIT<br />

5. CONNECT<br />

6. CREATE ALI<strong>AS</strong><br />

7. CREATE COLLECTION<br />

8. CREATE INDEX<br />

9. CREATE PROCEDURE<br />

10. CREATE TABLE<br />

11. CREATE VIEW<br />

12. DELETE<br />

13. DISCONNECT<br />

14. DROP ALI<strong>AS</strong><br />

Selection<br />

__<br />

F3=Exit F12=Cancel<br />

Select <strong>SQL</strong> Statement<br />

More...<br />

If you press F21=Display Statement on a prompt display, the prompter displays the<br />

<strong>for</strong>matted <strong>SQL</strong> statement as it was filled in to that point.<br />

When Enter is pressed within prompting, the statement that was built through the<br />

prompt screens is inserted into the session. If the statement processing mode is<br />

*RUN, the statement is run. The prompter remains in control if an error is<br />

encountered.<br />

222 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


Syntax checking<br />

The syntax of the <strong>SQL</strong> statement is checked when it enters the prompter. The<br />

prompter does not accept a syntactically incorrect statement. You must correct the<br />

syntax or remove the incorrect part of the statement or prompting will not be<br />

allowed.<br />

Statement processing mode<br />

The statement processing mode can be selected on the Change Session Attributes<br />

display. In *RUN (run) or *VLD (validate) mode, only statements that are allowed<br />

to run in interactive <strong>SQL</strong> can be prompted. In *SYN (syntax check) mode, all <strong>SQL</strong><br />

statements are allowed. The statement is not actually run in *SYN or *VLD modes;<br />

only the syntax and existence of objects are checked.<br />

Subqueries<br />

Subqueries can be selected on any display that has a WHERE or HAVING clause.<br />

To see the subquery display, press F9=Specify subquery when the cursor is on a<br />

WHERE or HAVING input line. A display appears that allows you to type in<br />

subselect in<strong>for</strong>mation. If the cursor is within the parentheses of the subquery when<br />

F9 is pressed, the subquery in<strong>for</strong>mation is filled in on the next display. If the<br />

cursor is outside the parentheses of the subquery, the next display is blank. For<br />

more in<strong>for</strong>mation on subqueries, see “Subqueries in SELECT statements” on<br />

page 84.<br />

CREATE TABLE prompting<br />

When prompting <strong>for</strong> CREATE TABLE, support is available <strong>for</strong> entering column<br />

definitions individually. Place your cursor in the column definition section of the<br />

display, and press F4=Prompt. A display that provides room <strong>for</strong> entering all the<br />

in<strong>for</strong>mation <strong>for</strong> one column definition is shown.<br />

To enter a column name longer than 18 characters, press F20=Display entire name.<br />

A window with enough space <strong>for</strong> a 30 character name will be displayed.<br />

The editing keys, F6=Insert line, F10=Copy line, and F14=Delete line, can be used<br />

to add and delete entries in the column definition list.<br />

Entering DBCS Data<br />

The rules <strong>for</strong> processing DBCS data across multiple lines are the same on the Enter<br />

<strong>SQL</strong> Statements display and in the <strong>SQL</strong> prompter. Each line must contain the same<br />

number of shift-in and shift-out characters. When processing a DBCS data string<br />

that requires more than one line <strong>for</strong> entering, the extra shift-in and shift-out<br />

characters are removed. If the last column on a line contains a shift-in and the first<br />

column of the next line contains a shift-out, the shift-in and shift-out characters are<br />

removed by the prompter when the two lines are assembled. If the last two<br />

columns of a line contain a shift-in followed by a single-byte blank and the first<br />

column of the next line contains a shift-out, the shift-in, blank, shift-out sequence is<br />

removed when the two lines are assembled. This removal allows DBCS<br />

in<strong>for</strong>mation to be read as one continuous character string.<br />

As an example, suppose the following WHERE condition were entered. The shift<br />

characters are shown here at the beginning and end of the string sections on each<br />

of the two lines.<br />

Chapter 12. Using Interactive <strong>SQL</strong> 223


Specify SELECT Statement<br />

Type SELECT statement in<strong>for</strong>mation. Press F4 <strong>for</strong> a list.<br />

FROM tables ........ TABLE1_______________________________________<br />

SELECT columns . . . . . . *____________________________________________<br />

WHERE conditions . .... COL1 = '<br />

'______________________________________<br />

GROUP BY columns . . . . . _____________________________________________<br />

HAVING conditions . . . . . _____________________________________________<br />

ORDER BY columns . . . . . _____________________________________________<br />

FOR UPDATE OF columns . . . _____________________________________________<br />

When Enter is pressed, the character string is put together, removing the extra shift<br />

characters. The statement would look like this on the Enter <strong>SQL</strong> Statements<br />

display:<br />

SELECT * FROM TABLE1 WHERE COL1 = ''<br />

Using the list selection function<br />

The list selection function is available by pressing F4 on certain prompt displays,<br />

or F16, F17, or F18 on the Enter <strong>SQL</strong> Statements display. After pressing the<br />

function key, you are given a list of authorized relational databases, collections,<br />

tables, views, aliases, columns, constraints, procedures, parameters, or packages<br />

from which to choose. If you request a list of tables, but you have not previously<br />

selected a collection, you are asked to select a collection first.<br />

On a list, you can select one or more items, numerically specifying the order in<br />

which you want them to appear in the statement. When the list function is exited,<br />

the selections you made are inserted at the position of the cursor on the display<br />

you came from.<br />

Always select the list you are primarily interested in. For example, if you want a<br />

list of columns, but you believe that the columns you want are in a table not<br />

currently selected, press F18=Select columns. Then, from the column list, press F17<br />

to change the table. If the table list were selected first, the table name would be<br />

inserted into your statement. You would not have a choice <strong>for</strong> selecting columns.<br />

You can request a list at any time while typing an <strong>SQL</strong> statement on the Enter <strong>SQL</strong><br />

Statements display. The selections you make from the lists are inserted on the Enter<br />

<strong>SQL</strong> Statements display. They are inserted where the cursor is located in the<br />

numeric order that you specified on the list display. Although the selected list<br />

in<strong>for</strong>mation is added <strong>for</strong> you, you must type the keywords <strong>for</strong> the statement.<br />

The list function tries to provide qualifications that are necessary <strong>for</strong> the selected<br />

columns, tables, and <strong>SQL</strong> packages. However, sometimes the list function cannot<br />

determine the intent of the <strong>SQL</strong> statement. You need to review the <strong>SQL</strong> statement<br />

and verify that the selected columns, tables, and <strong>SQL</strong> packages are properly<br />

qualified.<br />

Example: Using the list selection function<br />

The following example shows you how to use the list function to build a SELECT<br />

statement.<br />

Assume you have:<br />

v Just entered interactive <strong>SQL</strong> by typing STR<strong>SQL</strong> on an <strong>AS</strong>/<strong>400</strong> command line.<br />

224 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


v Made no list selections or entries.<br />

v Selected *<strong>SQL</strong> <strong>for</strong> the naming convention.<br />

Note: The example shows lists that are not on your <strong>AS</strong>/<strong>400</strong> system. They are used<br />

as an example only.<br />

Begin using <strong>SQL</strong> statements:<br />

1. Type SELECT on the first statement entry line.<br />

2. Type FROM on the second statement entry line.<br />

3. Leave the cursor positioned after FROM.<br />

Enter <strong>SQL</strong> Statements<br />

Type <strong>SQL</strong> statement, press Enter.<br />

===> SELECT<br />

FROM _<br />

4. Press F17=Select tables to obtain a list of tables, because you want the table<br />

name to follow FROM.<br />

Instead of a list of tables appearing as you expected, a list of collections<br />

appears (the Select and Sequence Collections display). You have just entered<br />

the <strong>SQL</strong> session and have not selected a collection to work with.<br />

5. Typea1intheSeq column next to YOURCOLL2 collection.<br />

Select and Sequence Collections<br />

Type sequence numbers (1-999) to select collections, press Enter.<br />

Seq Collection Type Text<br />

YOURCOLL1 SYS Company benefits<br />

1 YOURCOLL2 SYS Employee personal data<br />

YOURCOLL3 SYS Job classifications/requirements<br />

YOURCOLL4 SYS Company insurances<br />

6. Press Enter.<br />

The Select and Sequence Tables display appears, showing the tables existing in<br />

the YOURCOLL2 collection.<br />

7. Typea1intheSeq column next to PEOPLE table.<br />

Select and Sequence Tables<br />

Type sequence numbers (1-999) to select tables, press Enter.<br />

Seq Table Collection Type Text<br />

EMPLCO YOURCOLL2 TAB Employee company data<br />

1 PEOPLE YOURCOLL2 TAB Employee personal data<br />

EMPLEXP YOURCOLL2 TAB Employee experience<br />

EMPLEVL YOURCOLL2 TAB Employee evaluation reports<br />

EMPLBEN YOURCOLL2 TAB Employee benefits record<br />

EMPLMED YOURCOLL2 TAB Employee medical record<br />

EMPLINVST YOURCOLL2 TAB Employee investments record<br />

8. Press Enter.<br />

Chapter 12. Using Interactive <strong>SQL</strong> 225


The Enter <strong>SQL</strong> Statements display appears again with the table name,<br />

YOURCOLL2.PEOPLE, inserted after FROM. The table name is qualified by the<br />

collection name in the *<strong>SQL</strong> naming convention.<br />

Enter <strong>SQL</strong> Statements<br />

Type <strong>SQL</strong> statement, press Enter.<br />

===> SELECT<br />

FROM YOURCOLL2.PEOPLE _<br />

9. Position the cursor after SELECT.<br />

10. Press F18=Select columns to obtain a list of columns, because you want the<br />

column name to follow SELECT.<br />

The Select and Sequence Columns display appears, showing the columns in<br />

the PEOPLE table.<br />

11. Typea2intheSeq column next to the NAME column.<br />

12. Typea1intheSeq column next to the SOCSEC column.<br />

Select and Sequence Columns<br />

Type sequence numbers (1-999) to select columns, press Enter.<br />

Seq Column Table Type Digits Length<br />

2 NAME PEOPLE CHARACTER 6<br />

EMPLNO PEOPLE CHARACTER 30<br />

1 SOCSEC PEOPLE CHARACTER 11<br />

STRADDR PEOPLE CHARACTER 30<br />

CITY PEOPLE CHARACTER 20<br />

ZIP PEOPLE CHARACTER 9<br />

PHONE PEOPLE CHARACTER 20<br />

13. Press Enter.<br />

The Enter <strong>SQL</strong> Statements display appears again with SOCSEC, NAME appearing<br />

after SELECT.<br />

Enter <strong>SQL</strong> Statements<br />

Type <strong>SQL</strong> statement, press Enter.<br />

===> SELECT SOCSEC, NAME<br />

FROM YOURCOLL2.PEOPLE<br />

14. Press Enter.<br />

The statement you created is now run.<br />

Once you have used the list function, the values you selected remain in effect until<br />

you change them or until you change the list of collections on the Change Session<br />

Attributes display.<br />

Session services description<br />

The interactive <strong>SQL</strong> Session Services display is requested by pressing F13 on the<br />

Enter <strong>SQL</strong> Statements display.<br />

226 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


From this display you can change session attributes and print, clear, or save the<br />

session to a source file.<br />

Option 1 (Change session attributes) displays the Change Session Attributes<br />

display, which allows you to select the current values that are in effect <strong>for</strong> your<br />

interactive <strong>SQL</strong> session. The options shown on this display change based on the<br />

statement processing option selected.<br />

The following session attributes can be changed:<br />

v Commitment control attributes.<br />

v The statement processing control.<br />

v The SELECT output device.<br />

v The list of collections.<br />

v The list type to select either all your system and <strong>SQL</strong> objects, or only your <strong>SQL</strong><br />

objects.<br />

v The data refresh option when displaying data.<br />

v The allow copy data option.<br />

v The naming option.<br />

v The programming language.<br />

v The date <strong>for</strong>mat.<br />

v The time <strong>for</strong>mat.<br />

v The date separator.<br />

v The time separator.<br />

v The decimal point representation.<br />

v The <strong>SQL</strong> string delimiter.<br />

v The sort sequence.<br />

v The language identifier.<br />

Option 2 (Print current session) accesses the Change Printer display, which lets you<br />

print the current session immediately and then continue working. You are<br />

prompted <strong>for</strong> printer in<strong>for</strong>mation. All the <strong>SQL</strong> statements you entered and all the<br />

messages displayed are printed just as they appear on the Enter <strong>SQL</strong> Statements<br />

display.<br />

Option 3 (Remove all entries from current session) lets you remove all the <strong>SQL</strong><br />

statements and messages from the Enter <strong>SQL</strong> Statements display and the session<br />

history. You are prompted to ensure that you really want to delete the in<strong>for</strong>mation.<br />

Option 4 (Save session in source file) accesses the Change Source File display,<br />

which lets you save the session in a source file. You are prompted <strong>for</strong> the source<br />

file name. This function lets you embed the source file into a host language<br />

program by using the source entry utility (SEU).<br />

Note: Option 4 allows you to embed prototyped <strong>SQL</strong> statements in a high-level<br />

language (HLL) program that uses <strong>SQL</strong>. The source file created by option 4<br />

may be edited and used as the input source file <strong>for</strong> the Run <strong>SQL</strong> Statements<br />

(RUN<strong>SQL</strong>STM) command.<br />

Chapter 12. Using Interactive <strong>SQL</strong> 227


Exiting interactive <strong>SQL</strong><br />

Pressing F3=Exit on the Enter <strong>SQL</strong> Statements display allows you to exit the<br />

interactive <strong>SQL</strong> environment and do one of the following:<br />

1. Save and exit session. Leave interactive <strong>SQL</strong>. Your current session will be saved<br />

and used the next time you start interactive <strong>SQL</strong>.<br />

2. Exit without saving session. Leave interactive <strong>SQL</strong> without saving your session.<br />

3. Resume session. Remain in interactive <strong>SQL</strong> and return to the Enter <strong>SQL</strong><br />

Statements display. The current session parameters remain in effect.<br />

4. Save session in source file. Save the current session in a source file. The Change<br />

Source File display is shown to allow you to select where to save the session.<br />

You cannot recover and work with this session again in interactive <strong>SQL</strong>.<br />

Notes:<br />

1. Option 4 allows you to embed prototype <strong>SQL</strong> statements in a high-level<br />

language (HLL) program that uses <strong>SQL</strong>. Use the source entry utility (SEU) to<br />

copy the statements into your program. The source file can also be edited and<br />

used as the input source file <strong>for</strong> the Run <strong>SQL</strong> Statements (RUN<strong>SQL</strong>STM)<br />

command.<br />

2. If rows have been changed and locks are currently being held <strong>for</strong> this unit of<br />

work and you attempt to exit interactive <strong>SQL</strong>, a warning message is displayed.<br />

Using an existing <strong>SQL</strong> session<br />

If you saved only one interactive <strong>SQL</strong> session by using option 1 (Save and exit<br />

session) on the Exit Interactive <strong>SQL</strong> display, you may resume that session at any<br />

workstation. However, if you use option 1 to save two or more sessions on<br />

different workstations, interactive <strong>SQL</strong> will first attempt to resume a session that<br />

matches your work station. If no matching sessions are available, then interactive<br />

<strong>SQL</strong> will increase the scope of the search to include all sessions that belong to your<br />

user ID. If no sessions <strong>for</strong> your user ID are available, the system will create a new<br />

session <strong>for</strong> your user ID and current workstation.<br />

For example, you saved a session on workstation 1 and saved another session on<br />

workstation 2 and you are currently working at workstation 1. Interactive <strong>SQL</strong> will<br />

first attempt to resume the session saved <strong>for</strong> workstation 1. If that session is<br />

currently in use, interactive <strong>SQL</strong> will then attempt to resume the session that was<br />

saved <strong>for</strong> workstation 2. If that session is also in use, then the system will create a<br />

second session <strong>for</strong> workstation 1.<br />

However, suppose you are working at workstation 3 and want to use the I<strong>SQL</strong><br />

session associated with workstation 2. You then may need to first delete the session<br />

from workstation 1 by using option 2 (Exit without saving session) on the Exit<br />

Interactive <strong>SQL</strong> display.<br />

Recovering an <strong>SQL</strong> session<br />

If the previous <strong>SQL</strong> session ended abnormally, interactive <strong>SQL</strong> presents the<br />

Recover <strong>SQL</strong> Session display at the start of the next session (when the next<br />

STR<strong>SQL</strong> command is entered). From this display, you can either:<br />

v Recover the old session by selecting option 1 (Attempt to resume existing <strong>SQL</strong><br />

session).<br />

228 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


v Delete the old session and start a new session by selecting option 2 (Delete<br />

existing <strong>SQL</strong> session and start a new session).<br />

If you choose to delete the old session and continue with the new session, the<br />

parameters you specified when you entered STR<strong>SQL</strong> are used. If you choose to<br />

recover the old session, or are entering a previously saved session, the parameters<br />

you specified when you entered STR<strong>SQL</strong> are ignored and the parameters from the<br />

old session are used. A message is returned to indicate which parameters were<br />

changed from the specified value to the old session value.<br />

Accessing remote databases with interactive <strong>SQL</strong><br />

In interactive <strong>SQL</strong>, you can communicate with a remote relational database by<br />

using the <strong>SQL</strong> CONNECT statement. Interactive <strong>SQL</strong> uses the CONNECT (Type 2)<br />

semantics (distributed unit of work) <strong>for</strong> CONNECT statements. Interactive <strong>SQL</strong><br />

does an implicit connect to the local RDB when starting an <strong>SQL</strong> session. When the<br />

CONNECT statement is completed, a message shows the relational database<br />

connection that was established. If starting a new session and COMMIT(*NONE)<br />

was not specified, or if restoring a saved session and the commit level saved with<br />

the session was not *NONE, the connection will be registered with commitment<br />

control. This implicit connect and possible commitment control registration may<br />

influence subsequent connections to remote databases. For further in<strong>for</strong>mation, see<br />

“Determining connection type” on page 269. It is recommended that prior to<br />

connecting to the remote system:<br />

v When connecting to an application server that does not support distributed unit<br />

of work, a RELE<strong>AS</strong>E ALL followed by a COMMIT be issued to end previous<br />

connections, including the implicit connection to local.<br />

v When connecting to a non-<strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> application server, a RELE<strong>AS</strong>E<br />

ALL followed by a COMMIT be issued to end previous connections, including<br />

the implicit connection to local, and change the commitment control level to at<br />

least *CHG.<br />

When you are connecting to a non-<strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> application server, some<br />

session attributes are changed to attributes that are supported by that application<br />

server. The following table shows the attributes that change.<br />

Table 24. Values Table<br />

Session Attribute Original Value New Value<br />

Date Format *YMD<br />

*ISO<br />

*EUR<br />

*DMY<br />

*MDY<br />

*JUL<br />

*USA<br />

*USA<br />

Time Format *HMS with a : separator<br />

*HMS with any other<br />

separator<br />

Commitment Control *CHG,<br />

*NONE<br />

*ALL<br />

*JIS<br />

*EUR<br />

*CS Repeatable Read<br />

Naming Convention *SYS *<strong>SQL</strong><br />

Allow Copy Data *NO, *YES *OPTIMIZE<br />

Data Refresh *ALWAYS *FORWARD<br />

Chapter 12. Using Interactive <strong>SQL</strong> 229


Table 24. Values Table (continued)<br />

Session Attribute Original Value New Value<br />

Decimal Point *SYSVAL *PERIOD<br />

Sort Sequence Any value other than *HEX *HEX<br />

Notes:<br />

1. If connecting to an <strong>AS</strong>/<strong>400</strong> system that is running a release prior to Version 2<br />

Release 3, the sort sequence value changes to *HEX.<br />

2. When connecting to a <strong>DB2</strong>/2 or <strong>DB2</strong>/6000 application server, the date and time<br />

<strong>for</strong>mats specified must be the same <strong>for</strong>mat.<br />

After the connection is completed, a message is sent stating that the session<br />

attributes have been changed. The changed session attributes can be displayed by<br />

using the session services display. While interactive <strong>SQL</strong> is running, no other<br />

connection can be established <strong>for</strong> the default activation group.<br />

When connected to a remote system with interactive <strong>SQL</strong>, a statement processing<br />

mode of syntax-only checks the syntax of the statement against the syntax<br />

supported by the local system instead of the remote system. Similarly, the <strong>SQL</strong><br />

prompter and list support use the statement syntax and naming conventions<br />

supported by the local system. The statement is run, however, on the remote<br />

system. Because of differences in the level of <strong>SQL</strong> support between the two<br />

systems, syntax errors may be found in the statement on the remote system at run<br />

time.<br />

Lists of collections and tables are available when you are connected to the local<br />

relational database. Lists of columns are available only when you are connected to<br />

a relational database manager that supports the DESCRIBE TABLE statement.<br />

When you exit interactive <strong>SQL</strong> with connections that have pending changes or<br />

connections that use protected conversations, the connections remain. If you do not<br />

per<strong>for</strong>m additional work over the connections, the connections are ended during<br />

the next COMMIT or ROLLBACK operation. You can also end the connections by<br />

doing a RELE<strong>AS</strong>E ALL and a COMMIT be<strong>for</strong>e exiting interactive <strong>SQL</strong>.<br />

Using interactive <strong>SQL</strong> <strong>for</strong> remote access to non-<strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> application<br />

servers can require some setup. For more in<strong>for</strong>mation, see the Distributed Database<br />

<strong>Programming</strong> book.<br />

Note: In the output of a communications trace, there may be a reference to a<br />

’CREATE TABLE XXX’ statement. This is used to determine package<br />

existence; it is part of normal processing, and can be ignored.<br />

230 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


Chapter 13. Using the <strong>SQL</strong> Statement Processor<br />

This section describes the <strong>SQL</strong> Statement processor. This processor is available<br />

when you use the Run <strong>SQL</strong> Statements (RUN<strong>SQL</strong>STM) command.<br />

The <strong>SQL</strong> statement processor allows <strong>SQL</strong> statements to be executed from a source<br />

member. The statements in the source member can be run repeatedly, or changed,<br />

without compiling the source. This makes the setup of a database environment<br />

easier. The statements that can be used with the <strong>SQL</strong> statement processor are:<br />

v ALTER TABLE<br />

v CALL<br />

v COMMENT ON<br />

v COMMIT<br />

v CREATE ALI<strong>AS</strong><br />

v CREATE COLLECTION<br />

v CREATE DISTINCT TYPE<br />

v CREATE FUNCTION<br />

v CREATE INDEX<br />

v CREATE PROCEDURE<br />

v CREATE SCHEMA<br />

v CREATE TABLE<br />

v CREATE VIEW<br />

v DELETE<br />

v DROP<br />

v GRANT (Function or Procedure Privileges)<br />

v GRANT (Package Privileges)<br />

v GRANT (Table Privileges)<br />

v GRANT (User-Defined Type Privileges)<br />

v INSERT<br />

v LABEL ON<br />

v LOCK TABLE<br />

v RENAME<br />

v REVOKE (Function or Procedure Privileges)<br />

v REVOKE (Package Privileges)<br />

v REVOKE (Table Privileges)<br />

v REVOKE (User-Defined Type Privileges)<br />

v ROLLBACK<br />

v SET PATH<br />

v SET TRANSACTION<br />

v UPDATE<br />

In the source member, statements end with a semicolon and do not begin with<br />

EXEC <strong>SQL</strong>. If the record length of the source member is longer than 80, only the<br />

first 80 characters will be read. Comments in the source member can be either line<br />

comments or block comments. Line comments begin with a double hyphen (−−)<br />

© Copyright IBM Corp. 2000 231


and end at the end of the line. Block comments start with /* and can continue<br />

across many lines until the next */ is reached. Block comments can be nested. Only<br />

<strong>SQL</strong> statements and comments are allowed in the source file. The output listing<br />

and the resulting messages <strong>for</strong> the <strong>SQL</strong> statements are sent to a print file. The<br />

default print file is QSYSPRT.<br />

To per<strong>for</strong>m syntax checking only on all statements in the source member, specify<br />

the PROCESS(*SYN) parameter on the RUN<strong>SQL</strong>STM command.<br />

Execution of statements after errors occur<br />

When a statement returns an error with a severity higher than the value specified<br />

<strong>for</strong> the error level (ERRLVL) parameter of the RUN<strong>SQL</strong>STM command, the<br />

statement has failed. The rest of the statements in the source will be parsed to<br />

check <strong>for</strong> syntax errors, but those statements will not be executed. Most <strong>SQL</strong> errors<br />

have a severity of 30. If you want to continue processing after an <strong>SQL</strong> statement<br />

fails, set the ERRLVL parameter of the RUN<strong>SQL</strong>STM command to 30 or higher.<br />

Commitment control in the <strong>SQL</strong> statement processor<br />

A commitment-control level is specified on the RUN<strong>SQL</strong>STM command. If a<br />

commitment-control level other than *NONE is specified, the <strong>SQL</strong> statements are<br />

run under commitment control. If all of the statements successfully execute, a<br />

COMMIT is done at the completion of the <strong>SQL</strong> statement processor. Otherwise, a<br />

ROLLBACK is done. A statement is considered successful if its return code severity<br />

is less than or equal to the value specified on the ERRLVL parameter of the<br />

RUN<strong>SQL</strong>STM command.<br />

The SET TRANSACTION statement can be used within the source member to<br />

override the level of commitment control specified on the RUN<strong>SQL</strong>STM command.<br />

Note: The job must be at a unit of work boundary to use the <strong>SQL</strong> statement<br />

processor with commitment control.<br />

Schemas in the <strong>SQL</strong> Statement Processor<br />

The <strong>SQL</strong> statement processor supports the CREATE SCHEMA statement. This is a<br />

complex statement that can be thought of as having two distinct sections. The first<br />

section defines the collection <strong>for</strong> the schema. The second section contains DDL<br />

statements that define the objects in the collection.<br />

The first section can be written in one of two ways:<br />

v CREATE SCHEMA collection-name<br />

A collection is created using the specified collection name.<br />

v CREATE SCHEMA AUTHORIZATION authorization-name<br />

A collection is created using the authorization name as the collection name.<br />

When the schema is run, the user must have authority to the user profile that is<br />

named authorization-name.<br />

The privileges held by the authorization-name of the statement must include:<br />

– Authority to run the CREATE COLLECTION statement<br />

– Authority to run each <strong>SQL</strong> statement within the CREATE SCHEMA<br />

232 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


The second section of the CREATE SCHEMA statement can contain from zero to<br />

any number of the following statements:<br />

v COMMENT ON<br />

v CREATE ALI<strong>AS</strong><br />

v CREATE DISTINCT TYPE<br />

v CREATE INDEX<br />

v CREATE TABLE<br />

v CREATE VIEW<br />

v GRANT (Table Privileges)<br />

v GRANT (User-Defined Type Privileges)<br />

v LABEL ON<br />

These statements follow directly after the first section of the statement. The<br />

statements and sections are not separated by semicolons. If other <strong>SQL</strong> statements<br />

follow this schema definition, the last statement in the schema must be ended by a<br />

semicolon.<br />

All objects created or referenced in the second part of the schema statement must<br />

be in the collection that was created <strong>for</strong> the schema. All unqualified references are<br />

implicitly qualified by the collection that was created. All qualified references must<br />

be qualified by the created collection.<br />

Source member listing <strong>for</strong> the <strong>SQL</strong> statement processor<br />

5769ST1 V4R5M0 000225 Run <strong>SQL</strong> Statements SCHEMA 06/06/00 15:35:18 Page 1<br />

Source file...............CORPDATA/SRC<br />

Member....................SCHEMA<br />

Commit....................*NONE<br />

Naming....................*SYS<br />

Generation level..........10<br />

Date <strong>for</strong>mat...............*JOB<br />

Date separator............*JOB<br />

Time <strong>for</strong>mat...............*HMS<br />

Time separator ...........*JOB<br />

Default Collection........*NONE<br />

IBM <strong>SQL</strong> flagging..........*NOFLAG<br />

ANS flagging..............*NONE<br />

Decimal point.............*JOB<br />

Sort Sequence.............*JOB<br />

Language ID...............*JOB<br />

Printer file..............*LIBL/QSYSPRT<br />

Source file CCSID.........65535<br />

Job CCSID.................0<br />

Statement processing......*RUN<br />

Allow copy of data........*OPTIMIZE<br />

Allow blocking............*READ<br />

Source member changed on 04/01/98 11:54:10<br />

Figure 9. QSYSPRT listing <strong>for</strong> <strong>SQL</strong> statement processor (Part 1 of 3)<br />

Chapter 13. Using the <strong>SQL</strong> Statement Processor 233


5769ST1 V4R45M0 000225 Run <strong>SQL</strong> Statements SCHEMA 06/06/00 15:35:18 Page 2<br />

Record *...+... 1 ...+... 2 ...+... 3 ...+... 4 ...+... 5 ...+... 6 ...+... 7 ...+... 8 SEQNBR Last change<br />

1<br />

2 DROP COLLECTION DEPT;<br />

3 DROP COLLECTION MANAGER;<br />

4<br />

5 CREATE SCHEMA DEPT<br />

6 CREATE TABLE EMP (EMPNAME CHAR(50), EMPNBR INT)<br />

7 -- EMP will be created in collection DEPT<br />

8 CREATE INDEX EMPIND ON EMP(EMPNBR)<br />

9 -- EMPIND will be created in DEPT<br />

10 GRANT SELECT ON EMP TO PUBLIC; -- grant authority<br />

11<br />

12 INSERT INTO DEPT/EMP VALUES('JOHN SMITH', 1234);<br />

13 /* table must be qualified since no<br />

14 longer in the schema */<br />

15<br />

16 CREATE SCHEMA AUTHORIZATION MANAGER<br />

17 -- this schema will use MANAGER's<br />

18 -- user profile<br />

19 CREATE TABLE EMP_SALARY (EMPNBR INT, SALARY DECIMAL(7,2),<br />

20 LEVEL CHAR(10))<br />

21 CREATE VIEW LEVEL <strong>AS</strong> SELECT EMPNBR, LEVEL<br />

22 FROM EMP_SALARY<br />

23 CREATE INDEX SALARYIND ON EMP_SALARY(EMPNBR,SALARY)<br />

24<br />

25 GRANT ALL ON LEVEL TO JONES GRANT SELECT ON EMP_SALARY TO CLERK<br />

26 -- Two statements can be on the same line<br />

***** END OF SOURCE *****<br />

Figure 9. QSYSPRT listing <strong>for</strong> <strong>SQL</strong> statement processor (Part 2 of 3)<br />

5769ST1 V4R5M0 000225 Run <strong>SQL</strong> Statements SCHEMA 06/06/00 15:35:18 Page 3<br />

Record *...+... 1 ...+... 2 ...+... 3 ...+... 4 ...+... 5 ...+... 6 ...+... 7 ...+... 8 SEQNBR Last change<br />

MSG ID SEV RECORD TEXT<br />

<strong>SQL</strong>7953 0 1 Position 1 Drop of DEPT in QSYS complete.<br />

<strong>SQL</strong>7953 0 3 Position 3 Drop of MANAGER in QSYS complete.<br />

<strong>SQL</strong>7952 0 5 Position 3 Collection DEPT created.<br />

<strong>SQL</strong>7950 0 6 Position 8 Table EMP created in collection DEPT.<br />

<strong>SQL</strong>7954 0 8 Position 8 Index EMPIND created on table EMP in DEPT.<br />

<strong>SQL</strong>7966 0 10 Position 8 GRANT of authority to EMP in DEPT completed.<br />

<strong>SQL</strong>7956 0 10 Position 40 1 rows inserted in EMP in DEPT.<br />

<strong>SQL</strong>7952 0 13 Position 28 Collection<br />

MANAGER created.<br />

<strong>SQL</strong>7950 0 19 Position 9 Table EMP_SALARY created in collection<br />

MANAGER.<br />

<strong>SQL</strong>7951 0 21 Position 9 View LEVEL created in collection MANAGER.<br />

<strong>SQL</strong>7954 0 23 Position 9 Index SALARYIND created on table EMP_SALARY<br />

in MANAGER.<br />

<strong>SQL</strong>7966 0 25 Position 9 GRANT of authority to LEVEL in MANAGER<br />

completed.<br />

<strong>SQL</strong>7966 0 25 Position 37 GRANT of authority to EMP_SALARY in MANAGER<br />

completed.<br />

Message Summary<br />

Total Info Warning Error Severe Terminal<br />

13 13 0 0 0 0<br />

00 level severity errors found in source<br />

***** END OF LISTING *****<br />

Figure 9. QSYSPRT listing <strong>for</strong> <strong>SQL</strong> statement processor (Part 3 of 3)<br />

234 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


Chapter 14. <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> Data Protection<br />

Security <strong>for</strong> <strong>SQL</strong> objects<br />

This chapter describes the security plan <strong>for</strong> protecting <strong>SQL</strong> data from unauthorized<br />

users and the methods <strong>for</strong> ensuring data integrity.<br />

All objects on the <strong>AS</strong>/<strong>400</strong> system, including <strong>SQL</strong> objects, are managed by the<br />

system security function. Users may authorize <strong>SQL</strong> objects through either the <strong>SQL</strong><br />

GRANT and REVOKE statements or the CL commands Edit Object Authority<br />

(EDTOBJAUT), Grant Object Authority (GRTOBJAUT), and Revoke Object<br />

Authority (RVKOBJAUT). For more in<strong>for</strong>mation on system security and the use of<br />

the GRTOBJAUT and RVKOBJAUT commands, see the Security - Reference book.<br />

The <strong>SQL</strong> GRANT and REVOKE statements operate on <strong>SQL</strong> packages, <strong>SQL</strong><br />

procedures, tables, views, and the individual columns of tables and views.<br />

Furthermore, <strong>SQL</strong> GRANT and REVOKE statements only grant private and public<br />

authorities. In some cases, it is necessary to use EDTOBJAUT, GRTOBJAUT, and<br />

RVKOBJAUT to authorize users to other objects, such as commands and programs.<br />

For more in<strong>for</strong>mation on the GRANT and REVOKE statements, see the <strong>SQL</strong><br />

Reference book.<br />

The authority checked <strong>for</strong> <strong>SQL</strong> statements depends on whether the statement is<br />

static, dynamic, or being run interactively.<br />

For static <strong>SQL</strong> statements:<br />

v If the USRPRF value is *USER, the authority to run the <strong>SQL</strong> statement locally is<br />

checked using the user profile of the user running the program. The authority to<br />

run the <strong>SQL</strong> statement remotely is checked using the user profile at the<br />

application server. *USER is the default <strong>for</strong> system (*SYS) naming.<br />

v If the USRPRF value is *OWNER, the authority to run the <strong>SQL</strong> statement locally<br />

is checked using the user profiles of the user running the program and of the<br />

owner of the program. The authority to run the <strong>SQL</strong> statement remotely is<br />

checked using the user profiles of the application server job and the owner of<br />

the <strong>SQL</strong> package. The higher authority is the authority that is used. *OWNER is<br />

the default <strong>for</strong> <strong>SQL</strong> (*<strong>SQL</strong>) naming.<br />

For dynamic <strong>SQL</strong> statements:<br />

v If the USRPRF value is *USER, the authority to run the <strong>SQL</strong> statement locally is<br />

checked using the user profile of the person running the program. The authority<br />

to run the <strong>SQL</strong> statement remotely is checked using the user profile of the<br />

application server job.<br />

v If the USRPRF value is *OWNER and DYNUSRPRF is *USER, the authority to<br />

run the <strong>SQL</strong> statement locally is checked using the user profile of the person<br />

running the program. The authority to run the <strong>SQL</strong> statement remotely is<br />

checked using the user profile of the application server job.<br />

v If the USRPRF value is *OWNER and DYNUSRPRF is *OWNER, the authority to<br />

run the <strong>SQL</strong> statement locally is checked using the user profiles of the user<br />

running the program and the owner of the program. The authority to run the<br />

<strong>SQL</strong> statement remotely is checked using the user profiles of the application<br />

© Copyright IBM Corp. 2000 235


server job and the owner of the <strong>SQL</strong> package. The highest authority is the<br />

authority that is used. Because of security concerns, you should use the<br />

*OWNER parameter value <strong>for</strong> DYNUSRPRF carefully. This option gives the<br />

access authority of the owner program or package to those who run the<br />

program.<br />

For interactive <strong>SQL</strong> statements, authority is checked against the authority of the<br />

person processing the statement. Adopted authority is not used <strong>for</strong> interactive <strong>SQL</strong><br />

statements.<br />

Authorization ID<br />

Views<br />

Auditing<br />

The authorization ID identifies a unique user and is a user profile object on the<br />

<strong>AS</strong>/<strong>400</strong> system. Authorization IDs can be created using the system Create User<br />

Profile (CRTUSRPRF) command.<br />

A view can prevent unauthorized users from having access to sensitive data. The<br />

application program can access the data it needs in a table, without having access<br />

to sensitive or restricted data in the table. A view can restrict access to particular<br />

columns by not specifying those columns in the SELECT list (<strong>for</strong> example,<br />

employee salaries). A view can also restrict access to particular rows in a table by<br />

specifying a WHERE clause (<strong>for</strong> example, allowing access only to the rows<br />

associated with a particular department number).<br />

<strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> is designed to comply with the U.S. government C2 security<br />

level. A key feature of that level is the ability to audit actions on the system. <strong>DB2</strong><br />

<strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> uses the audit facilities managed by the system security function.<br />

Auditing can be per<strong>for</strong>med on an object level, user, or system level. The system<br />

value QAUDCTL controls whether auditing is per<strong>for</strong>med at the object or user<br />

level. The Change User Audit (CHGUSRAUD) command and Change Object Audit<br />

(CHGOBJAUD) command specify which users and objects are audited. The system<br />

value QAUDLVL controls what types of actions are audited (<strong>for</strong> example,<br />

authorization failures, creates, deletes, grants, revokes, etc.) For more in<strong>for</strong>mation<br />

on auditing see the Security - Reference book.<br />

<strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> can also audit row changes by using the <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong><br />

<strong>AS</strong>/<strong>400</strong> journal support.<br />

In some cases, entries in the auditing journal will not be in the same order as they<br />

occured. For example, a job that is running under commitment control deletes a<br />

table, creates a new table with the same name as the one that was deleted, then<br />

does a commit. This will be recorded in the auditing journal as a create followed<br />

by a delete. This is because objects that are created are journalled immediately. An<br />

object that is deleted under commitment control is hidden and not actually deleted<br />

until a commit is done. Once the commit is done, the action is journaled.<br />

236 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


Data integrity<br />

Data integrity protects data from being destroyed or changed by unauthorized<br />

persons, system operation or hardware failures (such as physical damage to a<br />

disk), programming errors, interruptions be<strong>for</strong>e a job is completed (such as a<br />

power failure), or interference from running applications at the same time (such as<br />

serialization problems). Data integrity is ensured by the following functions:<br />

v Concurrency<br />

v Journaling<br />

v Commitment control<br />

v Atomic operations<br />

v Constraints<br />

v Save/restore<br />

v Damage tolerance<br />

v Index recovery<br />

The Database <strong>Programming</strong> book and the Backup and Recovery book contain more<br />

in<strong>for</strong>mation about each of these functions.<br />

Concurrency<br />

Concurrency is the ability <strong>for</strong> multiple users to access and change data in the same<br />

table or view at the same time without risk of losing data integrity. This ability is<br />

automatically supplied by the <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> database manager. Locks are<br />

implicitly acquired on tables and rows to protect concurrent users from changing<br />

the same data at precisely the same time.<br />

Typically, <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> will acquire locks on rows to ensure integrity.<br />

However, some situations require <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> to acquire a more<br />

exclusive table level lock instead of row locks. For more in<strong>for</strong>mation see<br />

“Commitment control” on page 239.<br />

For example, an update (exclusive) lock on a row currently held by one cursor can<br />

be acquired by another cursor in the same program (or in a DELETE or UPDATE<br />

statement not associated with the cursor). This will prevent a positioned UPDATE<br />

or positioned DELETE statement that references the first cursor until another<br />

FETCH is per<strong>for</strong>med. A read (shared no-update) lock on a row currently held by<br />

one cursor will not prevent another cursor in the same program (or DELETE or<br />

UPDATE statement) from acquiring a lock on the same row.<br />

Default and user-specifiable lock-wait time-out values are supported. <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong><br />

<strong>AS</strong>/<strong>400</strong> creates tables, views, and indexes with the default record wait time (60<br />

seconds) and the default file wait time (*IMMED). This lock wait time is used <strong>for</strong><br />

DML statements. You can change these values by using the CL commands Change<br />

Physical File (CHGPF), Change Logical File (CHGLF), and Override Database File<br />

(OVRDBF).<br />

The lock wait time used <strong>for</strong> all DDL statements and the LOCK TABLE statement, is<br />

the job default wait time (DFTWAIT). You can change this value by using the CL<br />

commands Change Job (CHGJOB) or Change Class (CHGCLS).<br />

In the event that a large record wait time is specified, deadlock detection is<br />

provided. For example, assume one job has an exclusive lock on row 1 and another<br />

Chapter 14. <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> Data Protection 237


job has an exclusive lock on row 2. If the first job attempts to lock row 2, it will<br />

wait because the second job is holding the lock. If the second job then attempts to<br />

lock row 1, <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> will detect that the two jobs are in a deadlock<br />

and an error will be returned to the second job.<br />

You can explicitly prevent other users from using a table at the same time by using<br />

the <strong>SQL</strong> LOCK TABLE statement, which is described in the <strong>SQL</strong> Reference book.<br />

Using COMMIT(*RR) will also prevent other users from using a table during a unit<br />

of work.<br />

In order to improve per<strong>for</strong>mance, <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> will frequently leave the<br />

open data path (ODP) open (<strong>for</strong> details see the Database Per<strong>for</strong>mance and Query<br />

Optimization in<strong>for</strong>mation). This per<strong>for</strong>mance feature also leaves a lock on tables<br />

referenced by the ODP, but does not leave any locks on rows. A lock left on a table<br />

may prevent another job from per<strong>for</strong>ming an operation on that table. In most<br />

cases, however, <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> will detect that other jobs are holding locks<br />

and events will be signalled to those jobs. The event causes <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong><br />

to close any ODPs (and release the table locks) that are associated with that table<br />

and are currently only open <strong>for</strong> per<strong>for</strong>mance reasons. Note that the lock wait time<br />

out must be large enough <strong>for</strong> the events to be signalled and the other jobs to close<br />

the ODPs or an error will be returned.<br />

Unless the LOCK TABLE statement is used to acquire table locks, or either<br />

COMMIT(*ALL) or COMMIT(*RR) is used, data which has been read by one job<br />

can be immediately changed by another job. Usually, the data that is read at the<br />

time the <strong>SQL</strong> statement is executed and there<strong>for</strong>e it is very current (<strong>for</strong> example,<br />

during FETCH). In the following cases, however, data is read prior to the execution<br />

of the <strong>SQL</strong> statement and there<strong>for</strong>e the data may not be current (<strong>for</strong> example,<br />

during OPEN).<br />

v ALWCPYDTA(*OPTIMIZE) was specified and the optimizer determined that<br />

making a copy of the data would per<strong>for</strong>m better than not making a copy.<br />

v Some queries require the database manager to create a temporary result table.<br />

The data in the temporary result table will not reflect changes made after the<br />

cursor was opened. A temporary result table is required when:<br />

– The total length in bytes of storage <strong>for</strong> the columns specified in an ORDER<br />

BY clause exceeds 2000 bytes.<br />

– ORDER BY and GROUP BY clauses specify different columns or columns in a<br />

different order.<br />

– UNION or DISTINCT clauses are specified.<br />

– ORDER BY or GROUP BY clauses specify columns which are not all from the<br />

same table.<br />

– Joining a logical file defined by the JOINDFT data definition specifications<br />

(DDS) keyword with another file.<br />

– Joining or specifying GROUP BY on a logical file which is based on multiple<br />

database file members.<br />

– The query contains a join in which at least one of the files is a view which<br />

contains a GROUP BY clause.<br />

– The query contains a GROUP BY clause which references a view that contains<br />

a GROUP BY clause.<br />

v A basic subquery is evaluated when the query is opened.<br />

238 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


Journaling<br />

The <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> journal support supplies an audit trail and <strong>for</strong>ward and<br />

backward recovery. Forward recovery can be used to take an older version of a<br />

table and apply the changes logged on the journal to the table. Backward recovery<br />

can be used to remove changes logged on the journal from the table.<br />

When an <strong>SQL</strong> collection is created, a journal and journal receiver are created in the<br />

collection. When <strong>SQL</strong> creates the journal and journal receiver, they are only created<br />

on a user auxiliary storage pool (<strong>AS</strong>P) if the <strong>AS</strong>P clause is specified on the<br />

CREATE COLLECTION or the CREATE SCHEMA statement. However, because<br />

placing journal receivers on their own <strong>AS</strong>Ps can improve per<strong>for</strong>mance, the person<br />

managing the journal might want to create all future journal receivers on a<br />

separate <strong>AS</strong>P.<br />

When a table is created into the collection, it is automatically journaled to the<br />

journal <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> created in the collection (QSQJRN). A table created in<br />

a non-collection will also have journaling started if a journal named QSQJRN exists<br />

in that library. After this point, it is your responsibility to use the journal functions<br />

to manage the journal, the journal receivers, and the journaling of tables to the<br />

journal. For example, if a table is moved into a collection, no automatic change to<br />

the journaling status occurs. If a table is restored, the normal journal rules apply.<br />

That is, if the table was journaled at the time of the save, it is journaled to the<br />

same journal at restore time. If the table was not journaled at the time of the save,<br />

it is not journaled at restore time.<br />

The journal created in the <strong>SQL</strong> collection is normally the journal used <strong>for</strong> logging<br />

all changes to <strong>SQL</strong> tables. You can, however, use the system journal functions to<br />

journal <strong>SQL</strong> tables to a different journal. This may be necessary if a table in one<br />

collection is a parent to a table in another collection. This is because <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong><br />

<strong>AS</strong>/<strong>400</strong> requires that the parent and dependent file in a referential constraint be<br />

journaled to the same journal when updates or deletes are per<strong>for</strong>med to the parent<br />

table.<br />

A user can stop journaling on any table using the journal functions, but doing so<br />

prevents an application from running under commitment control. If journaling is<br />

stopped on a parent table of a referential constraint with a delete rule of NO<br />

ACTION, C<strong>AS</strong>CADE, SET NULL, or SET DEFAULT, all update and delete<br />

operations will be prevented. Otherwise, an application is still able to function if<br />

you have specified COMMIT(*NONE); however, this does not provide the same<br />

level of integrity that journaling and commitment control provide.<br />

Commitment control<br />

The <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> commitment control support provides a means to<br />

process a group of database changes (updates, inserts, DDL operations, or deletes)<br />

as a single unit of work (transaction). A commit operation guarantees that the<br />

group of operations is completed. A rollback operation guarantees that the group<br />

of operations is backed out. A commit operation can be issued through several<br />

different interfaces. For example,<br />

v An <strong>SQL</strong> COMMIT statement<br />

v A CL COMMIT command<br />

v A language commit statement (such as an RPG COMMIT statement)<br />

Chapter 14. <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> Data Protection 239


A rollback operation can be issued through several different interfaces. For<br />

example,<br />

v An <strong>SQL</strong> ROLLBACK statement<br />

v A CL ROLLBACK command<br />

v A language rollback statement (such as an RPG ROLBK statement)<br />

The only <strong>SQL</strong> statements that cannot be committed or rolled back are:<br />

v DROP COLLECTION<br />

v GRANT or REVOKE if an authority holder exists <strong>for</strong> the specified object<br />

If commitment control was not already started when either an <strong>SQL</strong> statement is<br />

executed with an isolation level other than COMMIT(*NONE) or a RELE<strong>AS</strong>E<br />

statement is executed, then <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> sets up the commitment control<br />

environment by implicitly calling the CL command Start Commitment Control<br />

(STRCMTCTL). <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> specifies NFYOBJ(*NONE) and<br />

CMTSCOPE(*ACTGRP) parameters along with LCKLVL on the STRCMTCTL<br />

command. The LCKLVL specified is the lock level on the COMMIT parameter on<br />

the CRT<strong>SQL</strong>xxx, STR<strong>SQL</strong>, or RUN<strong>SQL</strong>STM commands. In REXX, the LCKLVL<br />

specified is the lock level on the SET OPTION statement. 8 You may use the<br />

STRCMTCTL command to specify a different CMTSCOPE, NFYOBJ, or LCKLVL. If<br />

you specify CMTSCOPE(*JOB) to start the job level commitment definition, <strong>DB2</strong><br />

<strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> uses the job level commitment definition <strong>for</strong> programs in that<br />

activation group.<br />

Note: When using commitment control, the tables referred to in the application<br />

program by Data Manipulation Language statements must be journaled.<br />

For cursors that use column functions, GROUP BY, or HAVING, and are running<br />

under commitment control, a ROLLBACK HOLD has no effect on the cursor’s<br />

position. In addition, the following occurs under commitment control:<br />

v If COMMIT(*CHG) and (ALWBLK(*NO) or (ALWBLK(*READ)) is specified <strong>for</strong><br />

one of these cursors, a message (CPI430B) is sent that says COMMIT(*CHG)<br />

requested but not allowed.<br />

v If COMMIT(*ALL), COMMIT(*RR), or COMMIT(*CS) with the KEEP LOCKS<br />

clause is specified <strong>for</strong> one of the cursors, <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> will lock all<br />

referenced tables in shared mode (*SHRNUP). The lock prevents concurrent<br />

application processes from executing any but read-only operations on the named<br />

table. A message (either <strong>SQL</strong>7902 or CPI430A) is sent that says COMMIT(*ALL),<br />

COMMIT(*RR), or COMMIT(*CS) with the KEEP LOCKS clause is specified <strong>for</strong><br />

one of the cursors requested but not allowed. Message <strong>SQL</strong>0595 may also be<br />

sent.<br />

For cursors where either COMMIT(*ALL), COMMIT(*RR), or COMMIT(*CS) with<br />

the KEEP LOCKS clause is specified and either catalog files are used or a<br />

temporary result table is required, <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> will lock all referenced<br />

tables in shared mode (*SHRNUP). This will prevent concurrent processes from<br />

executing anything but read-only operations on the table(s). A message (either<br />

<strong>SQL</strong>7902 or CPI430A) is sent that says COMMIT(*ALL) is requested but not<br />

allowed. Message <strong>SQL</strong>0595 may also be sent.<br />

8. Note that the LCKLVL specified is only the default lock level. After commitment control is started, the SET TRANSACTION <strong>SQL</strong><br />

statement and the lock level specified on the COMMIT parameter on the CRT<strong>SQL</strong>xxx, STR<strong>SQL</strong>, or RUN<strong>SQL</strong>STM commands will<br />

override the default lock level.<br />

240 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


Table 25. Record Lock Duration<br />

<strong>SQL</strong> Statement<br />

SELECT INTO<br />

SET variable<br />

VALUES INTO<br />

FETCH (read-only<br />

cursor)<br />

If ALWBLK(*ALLREAD) and COMMIT(*CHG) were specified, when the program<br />

was precompiled, all read only cursors will allow blocking of rows and a<br />

ROLLBACK HOLD will not roll the cursor position back.<br />

If COMMIT(*RR) is requested, the tables will be locked until the query is closed. If<br />

the cursor is read only, the table will be locked (*SHRNUP). If the cursor is in<br />

update mode, the table will be locked (*EXCLRD). Since other users will be locked<br />

out of the table, running with repeatable read will prevent concurrent access of the<br />

table.<br />

If an isolation level other then COMMIT(*NONE) was specified and the<br />

application issues a ROLLBACK or the activation group ends normally (and the<br />

commitment definition is not *JOB), all updates, inserts, deletes, and DDL<br />

operations made within the unit of work are backed out. If the application issues a<br />

COMMIT or the activation group ends normally, all updates, inserts, deletes, and<br />

DDL operations made within the unit of work are committed.<br />

<strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> uses locks on rows to keep other jobs from accessing<br />

changed data be<strong>for</strong>e a unit of work completes. If COMMIT(*ALL) is specified, read<br />

locks on rows fetched are also used to prevent other jobs from changing data that<br />

was read be<strong>for</strong>e a unit of work completes. This will not prevent other jobs from<br />

reading the unchanged records. This ensures that, if the same unit of work rereads<br />

a record, it gets the same result. Read locks do not prevent other jobs from fetching<br />

the same rows.<br />

Commitment control handles up to 4 million distinct row changes in a unit of<br />

work. If COMMIT(*ALL) or COMMIT(*RR) is specified, all rows read are also<br />

included in the limit. (If a row is changed or read more than once in a unit of<br />

work, it is only counted once toward the limit.) Holding a large number of locks<br />

adversely affects system per<strong>for</strong>mance and does not allow concurrent users to<br />

access rows locked in the unit of work until the end of the unit of work. It is in<br />

your best interest to keep the number of rows processed in a unit of work small.<br />

Commitment control will allow up to 512 files <strong>for</strong> each journal to be open under<br />

commitment control or closed with pending changes in a unit of work.<br />

COMMIT HOLD and ROLLBACK HOLD allows you to keep the cursor open and<br />

start another unit of work without issuing an OPEN again. The HOLD value is not<br />

available when you are connected to a remote database that is not on an <strong>AS</strong>/<strong>400</strong><br />

system. However, the WITH HOLD option on DECLARE CURSOR may be used to<br />

keep the cursor open after a COMMIT. This type of cursor is supported when you<br />

are connected to a remote database that is not on an <strong>AS</strong>/<strong>400</strong> system. Such a cursor<br />

is closed on a rollback.<br />

COMMIT Parameter<br />

(See note 6) Duration of Record Locks Lock Type<br />

*NONE<br />

*CHG<br />

*CS (See note 8)<br />

*ALL (See note 2)<br />

*NONE<br />

*CHG<br />

*CS (See note 8)<br />

*ALL (See note 2)<br />

No locks<br />

No locks<br />

Row locked when read and released<br />

From read until ROLLBACK or COMMIT<br />

No locks<br />

No locks<br />

From read until the next FETCH<br />

From read until ROLLBACK or COMMIT<br />

READ<br />

READ<br />

READ<br />

READ<br />

Chapter 14. <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> Data Protection 241


Table 25. Record Lock Duration (continued)<br />

<strong>SQL</strong> Statement<br />

FETCH (update or<br />

delete capable cursor)<br />

(See note 1)<br />

COMMIT Parameter<br />

(See note 6) Duration of Record Locks Lock Type<br />

*NONE<br />

*CHG<br />

*CS<br />

*ALL<br />

INSERT (target table) *NONE<br />

*CHG<br />

*CS<br />

*ALL<br />

INSERT (tables in<br />

subselect)<br />

*NONE<br />

*CHG<br />

*CS<br />

*ALL<br />

UPDATE (non-cursor) *NONE<br />

*CHG<br />

*CS<br />

*ALL<br />

DELETE (non-cursor) *NONE<br />

*CHG<br />

*CS<br />

*ALL<br />

UPDATE (with cursor) *NONE<br />

*CHG<br />

*CS<br />

*ALL<br />

DELETE (with cursor) *NONE<br />

*CHG<br />

*CS<br />

*ALL<br />

Subqueries (update or<br />

delete capable cursor or<br />

UPDATE or DELETE<br />

non-cursor)<br />

Subqueries (read-only<br />

cursor or SELECT<br />

INTO)<br />

*NONE<br />

*CHG<br />

*CS<br />

*ALL (see note 2)<br />

*NONE<br />

*CHG<br />

*CS<br />

*ALL<br />

242 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5<br />

When record not updated or deleted<br />

from read until next FETCH<br />

When record is updated or deleted<br />

from read until UPDATE or DELETE<br />

When record not updated or deleted<br />

from read until next FETCH<br />

When record is updated or deleted<br />

from read until COMMIT or ROLLBACK<br />

When record not updated or deleted<br />

from read until next FETCH<br />

When record is updated or deleted<br />

from read until COMMIT or ROLLBACK<br />

From read until ROLLBACK or COMMIT<br />

No locks<br />

From insert until ROLLBACK or COMMIT<br />

From insert until ROLLBACK or COMMIT<br />

From insert until ROLLBACK or COMMIT<br />

No locks<br />

No locks<br />

Each record locked while being read<br />

From read until ROLLBACK or COMMIT<br />

Each record locked while being updated<br />

From read until ROLLBACK or COMMIT<br />

From read until ROLLBACK or COMMIT<br />

From read until ROLLBACK or COMMIT<br />

Each record locked while being deleted<br />

From read until ROLLBACK or COMMIT<br />

From read until ROLLBACK or COMMIT<br />

From read until ROLLBACK or COMMIT<br />

Lock released when record updated<br />

From read until ROLLBACK or COMMIT<br />

From read until ROLLBACK or COMMIT<br />

From read until ROLLBACK or COMMIT<br />

Lock released when record deleted<br />

From read until ROLLBACK or COMMIT<br />

From read until ROLLBACK or COMMIT<br />

From read until ROLLBACK or COMMIT<br />

From read until next FETCH<br />

From read until next FETCH<br />

From read until next FETCH<br />

From read until ROLLBACK or COMMIT<br />

No locks<br />

No locks<br />

Each record locked while being read<br />

From read until ROLLBACK or COMMIT<br />

UPDATE<br />

UPDATE<br />

UPDATE<br />

UPDATE 3<br />

UPDATE<br />

UPDATE<br />

UPDATE 4<br />

READ<br />

READ<br />

UPDATE<br />

UPDATE<br />

UPDATE<br />

UPDATE<br />

UPDATE<br />

UPDATE<br />

UPDATE<br />

UPDATE<br />

UPDATE<br />

UPDATE<br />

UPDATE<br />

UPDATE<br />

UPDATE<br />

UPDATE<br />

UPDATE<br />

UPDATE<br />

READ<br />

READ<br />

READ<br />

READ<br />

READ<br />

READ


Table 25. Record Lock Duration (continued)<br />

COMMIT Parameter<br />

<strong>SQL</strong> Statement (See note 6) Duration of Record Locks Lock Type<br />

Notes:<br />

1. A cursor is open with UPDATE or DELETE capabilities if the result table is not read-only (see description of<br />

DECLARE CURSOR in <strong>SQL</strong> Reference book) and if one of the following is true:<br />

v The cursor is defined with a FOR UPDATE clause.<br />

v The cursor is defined without a FOR UPDATE, FOR READ ONLY, or ORDER BY clause and the program<br />

contains at least one of the following:<br />

– Cursor UPDATE referring to the same cursor-name<br />

– Cursor DELETE referring to the same cursor-name<br />

– An EXECUTE or EXECUTE IMMEDIATE statement and ALWBLK(*READ) or ALWBLK(*NONE) was<br />

specified on the CRT<strong>SQL</strong>xxx command.<br />

2. A table or view can be locked exclusively in order to satisfy COMMIT(*ALL). If a subselect is processed that<br />

includes a UNION, or if the processing of the query requires the use of a temporary result, an exclusive lock is<br />

acquired to protect you from seeing uncommitted changes.<br />

3. If the row is not updated or deleted, the lock is reduced to *READ.<br />

4. An UPDATE lock on rows of the target table and a READ lock on the rows of the subselect table.<br />

5. A table or view can be locked exclusively in order to satisfy repeatable read. Row locking is still done under<br />

repeatable read. The locks acquired and their duration are identical to *ALL.<br />

6. Repeatable read (*RR) record locks will be the same as the locks indicated <strong>for</strong> *ALL.<br />

7. For a detailed explanation of isolation levels and locking, see the section entitled ″Isolation Level″ in Chapter 1<br />

of the <strong>SQL</strong> Reference book.<br />

8. If the KEEP LOCKS clause is specified with *CS, any read locks are held until the cursor is closed or until a<br />

COMMIT or ROLLBACK is done. If no cursors are associated with the isolation clause, then locks are held until<br />

the completion of the <strong>SQL</strong> statement.<br />

Atomic operations<br />

When running under COMMIT(*CHG), COMMIT(*CS), or COMMIT(*ALL), all<br />

operations are guaranteed to be atomic. That is, they will complete or they will<br />

appear not to have started. This is true regardless of when or how the function<br />

was ended or interrupted (such as power failure, abnormal job end, or job cancel).<br />

If COMMIT (*NONE) is specified, however, some underlying database data<br />

definition functions are not atomic. The following <strong>SQL</strong> data definition statements<br />

are guaranteed to be atomic:<br />

ALTER TABLE (See note 1)<br />

COMMENT ON (See note 2)<br />

LABEL ON (See note 2)<br />

GRANT (See note 3)<br />

REVOKE (See note 3)<br />

DROP TABLE (See note 4)<br />

DROP VIEW (See note 4)<br />

DROP INDEX<br />

DROP PACKAGE<br />

Chapter 14. <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> Data Protection 243


Notes:<br />

1. If constraints need to be added or removed, as well as column definitions<br />

changed, the operations are processed one at a time, so the entire <strong>SQL</strong><br />

statement is not atomic. The order of operation is:<br />

v remove constraints<br />

v drop columns <strong>for</strong> which the RESTRICT option was specified<br />

v all other column definition changes (DROP COLUMN C<strong>AS</strong>CADE, ALTER<br />

COLUMN, ADD COLUMN)<br />

v add constraints<br />

2. If multiple columns are specified <strong>for</strong> a COMMENT ON or LABEL ON<br />

statement, the columns are processed one at a time, so the entire <strong>SQL</strong> statement<br />

is not atomic, but the COMMENT ON or LABEL ON to each individual<br />

column or object will be atomic.<br />

3. If multiple tables, <strong>SQL</strong> packages, or users are specified <strong>for</strong> a GRANT or<br />

REVOKE statement, the tables are processed one at a time, so the entire <strong>SQL</strong><br />

statement is not atomic, but the GRANT or REVOKE to each individual table<br />

will be atomic.<br />

4. If dependent views need to be dropped during DROP TABLE or DROP VIEW,<br />

each dependent view is processed one at a time, so the entire <strong>SQL</strong> statement is<br />

not atomic.<br />

The following data definition statements are not atomic because they involve more<br />

than one <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> database operation:<br />

CREATE ALI<strong>AS</strong><br />

CREATE COLLECTION<br />

CREATE DISTINCT TYPE<br />

CREATE FUNCTION<br />

CREATE PROCEDURE<br />

CREATE TABLE<br />

CREATE VIEW<br />

CREATE INDEX<br />

CREATE SCHEMA<br />

DROP ALI<strong>AS</strong><br />

DROP COLLECTION<br />

DROP DISTINCT TYPE<br />

DROP FUNCTION<br />

DROP PROCEDURE<br />

DROP SCHEMA<br />

RENAME (See note 1)<br />

Notes:<br />

1. RENAME is atomic only if the name or the system name is changed. When<br />

both are changed, the RENAME is not atomic.<br />

For example, a CREATE TABLE can be interrupted after the <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong><br />

physical file has been created, but be<strong>for</strong>e the member has been added. There<strong>for</strong>e,<br />

in the case of create statements, if an operation ends abnormally, you may have to<br />

drop the object and then create it again. In the case of a DROP COLLECTION<br />

statement, you may have to drop the collection again or use the CL command<br />

Delete Library (DLTLIB) to remove the remaining parts of the collection.<br />

244 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


Constraints<br />

<strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> supports unique, referential, and check constraints. A unique<br />

constraint is a rule that guarantees that the values of a key are unique. A<br />

referential constraint is a rule that all non-null values of <strong>for</strong>eign keys in a<br />

dependent table have a corresponding parent key in a parent table. A check<br />

constraint is a rule that limits the values allowed in a column or group of columns.<br />

<strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> will en<strong>for</strong>ce the validity of the constraint during any DML<br />

(data manipulation language) statement. Certain operations (such as restore of the<br />

dependent table), however, cause the validity of the constraint to be unknown. In<br />

this case, DML statements may be prevented until <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> has<br />

verified the validity of the constraint.<br />

v Unique constraints are implemented with indexes. If an index that implements a<br />

unique constraint is invalid, the Edit Rebuild of Access Paths (EDTRBDAP)<br />

command can be used to display any indexes that currently require rebuild.<br />

v If <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> does not currently know whether a referential constraint<br />

or check constraint is valid, the constraint is considered to be in a check pending<br />

state. The Edit Check Pending Constraints (EDTCPCST) command can be used<br />

to display any indexes that currently require rebuild.<br />

Save/Restore<br />

For more in<strong>for</strong>mation on constraints see the Database <strong>Programming</strong> book.<br />

The <strong>AS</strong>/<strong>400</strong> save/restore functions are used to save tables, views, indexes,<br />

journals, journal receivers, <strong>SQL</strong> packages, <strong>SQL</strong> procedures, user-defined functions,<br />

user-defined types, and collections on disk (save file) or to some external media<br />

(tape or diskette). The saved versions can be restored onto any <strong>AS</strong>/<strong>400</strong> system at<br />

some later time. The save/restore function allows an entire collection, selected<br />

objects, or only objects changed since a given date and time to be saved. All<br />

in<strong>for</strong>mation needed to restore an object to its previous state is saved. This function<br />

can be used to recover from damage to individual tables by restoring the data with<br />

a previous version of the table or the entire collection.<br />

When a program that was created <strong>for</strong> an <strong>SQL</strong> procedure or a service program that<br />

was created <strong>for</strong> an <strong>SQL</strong> function or a sourced function is restored, it is<br />

automatically added to the SYSROUTINES and SYSPARMS catalogs, as long as the<br />

procedure or function does not already exist with the same signature. <strong>SQL</strong><br />

programs created in QSYS will not be created as <strong>SQL</strong> procedures when restored.<br />

Additionally, external programs or service programs that were referenced on a<br />

CREATE PROCEDURE or CREATE FUNCTION statement may contain the<br />

in<strong>for</strong>mation required to register the routine in SYSROUTINES. If the in<strong>for</strong>mation<br />

exists and the signature is unique, the functions or procedures will also be added<br />

to SYSROUTINES and SYSPARMS when restored.<br />

When an *<strong>SQL</strong>UDT object is restored <strong>for</strong> a user-defined type, the user-defined type<br />

is automatically added to the SYSTYPES catalog. The appropriate functions needed<br />

to cast between the user-defined type and the source type are also created, as long<br />

as the type and functions do not already exist.<br />

Either a distributed <strong>SQL</strong> program or its associated <strong>SQL</strong> package can be saved and<br />

restored to any number of <strong>AS</strong>/<strong>400</strong> systems. This allows any number of copies of<br />

the <strong>SQL</strong> programs on different systems to access the same <strong>SQL</strong> package on the<br />

same application server. This also allows a single distributed <strong>SQL</strong> program to<br />

Chapter 14. <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> Data Protection 245


connect to any number of application servers that have the <strong>SQL</strong> package restored<br />

(CRT<strong>SQL</strong>PKG can also be used). <strong>SQL</strong> packages cannot be restored to a different<br />

library.<br />

Attention: Restoring a collection to an existing library or to a collection that has a<br />

different name does not restore the journal, journal receivers, or IDDU dictionary<br />

(if one exists). If the collection is restored to a collection with a different name, the<br />

catalog views in that collection will only reflect objects in the old collection. The<br />

catalog views in QSYS2, however, will appropriately reflect all objects.<br />

Damage tolerance<br />

The <strong>AS</strong>/<strong>400</strong> system provides several mechanisms to reduce or eliminate damage<br />

caused by disk errors. For example, mirroring, checksums, and RAID disks can all<br />

reduce the possibility of disk problems. The <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> functions also<br />

have a certain amount of tolerance to damage caused by disk errors or system<br />

errors.<br />

A DROP operation always succeeds, regardless of the damage. This ensures that<br />

should damage occur, at least the table, view, <strong>SQL</strong> package, or index can be<br />

deleted and restored or created again.<br />

In the event that a disk error has damaged a small portion of the rows in a table,<br />

the <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> database manager allows you to read rows still<br />

accessible.<br />

Index recovery<br />

<strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> supplies several functions to deal with index recovery.<br />

v System managed index protection<br />

The EDTRCYAP CL command allows a user to instruct <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> to<br />

guarantee that in the event of a system or power failure, the amount of time<br />

required to recover all indexes on the system is kept below a specified time. The<br />

system automatically journals enough in<strong>for</strong>mation in a system journal to limit<br />

the recovery time to the specified amount.<br />

v Journaling of indexes<br />

<strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> supplies an index journaling function that makes it<br />

unnecessary to rebuild an entire index due to a power or system failure. If the<br />

index is journaled, the system database support automatically makes sure the<br />

index is in synchronization with the data in the tables without having to rebuild<br />

it from scratch. <strong>SQL</strong> indexes are not journaled automatically. You can, however,<br />

use the CL command Start Journal Access Path (STRJRNAP) to journal any<br />

index created by <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong>.<br />

v Index rebuild<br />

All indexes on the system have a maintenance option that specifies when an<br />

index is maintained. <strong>SQL</strong> indexes are created with an attribute of *IMMED<br />

maintenance.<br />

In the event of a power failure or abnormal system failure, if indexes were not<br />

protected by one of the previously described techniques, those indexes in the<br />

process of change may need to be rebuilt by the database manager to make sure<br />

they agree with the actual data. All indexes on the system have a recovery<br />

option that specifies when an index should be rebuilt if necessary. All <strong>SQL</strong><br />

indexes with an attribute of UNIQUE are created with a recovery attribute of<br />

*IPL (this means that these indexes are rebuilt be<strong>for</strong>e the OS/<strong>400</strong> has been<br />

246 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


started). All other <strong>SQL</strong> indexes are created with the *AFTIPL recovery option<br />

(this means that after the operating system has been started, indexes are<br />

asynchronously rebuilt). During an IPL, the operator can see a display showing<br />

indexes needing to be rebuilt and their recovery option. The operator can<br />

override the recovery options.<br />

v Save and restore of indexes<br />

The save/restore function allows you to save indexes when a table is saved by<br />

using ACCPTH(*YES) on the Save Object (SAVOBJ) or Save Library (SAVLIB) CL<br />

commands. In the event of a restore when the indexes have also been saved,<br />

there is no need to rebuild the indexes. Any indexes not previously saved and<br />

restored are automatically and asynchronously rebuilt by the database manager.<br />

Catalog integrity<br />

Catalogs contain in<strong>for</strong>mation about tables, views, <strong>SQL</strong> packages, indexes,<br />

procedures, and parameters in a collection. The database manager ensures that the<br />

in<strong>for</strong>mation in the catalog is accurate at all times. This is accomplished by<br />

preventing end users from explicitly changing any in<strong>for</strong>mation in the catalog and<br />

by implicitly maintaining the in<strong>for</strong>mation in the catalog when changes occur to the<br />

tables, views, <strong>SQL</strong> packages, indexes, procedures, and parameters described in the<br />

catalog.<br />

The integrity of the catalog is maintained whether objects in the collection are<br />

changed by <strong>SQL</strong> statements, OS/<strong>400</strong> CL commands, System/38 Environment CL<br />

commands, System/36 Environment functions, or any other product or utility on<br />

an <strong>AS</strong>/<strong>400</strong> system. For example, deleting a table can be done by running an <strong>SQL</strong><br />

DROP statement, issuing an OS/<strong>400</strong> DLTF CL command, issuing a System/38<br />

DLTF CL command or entering option 4 on a WRKF or WRKOBJ display.<br />

Regardless of the interface used to delete the table, the database manager will<br />

remove the description of the table from the catalog at the time the delete is<br />

per<strong>for</strong>med. The following is a list of functions and the associated effect on the<br />

catalog:<br />

Table 26. Effect of Various Functions on Catalogs<br />

Function Effect on the Catalog<br />

Add constraint to table In<strong>for</strong>mation added to catalog<br />

Remove of constraint from table Related in<strong>for</strong>mation removed from catalog<br />

Create object into collection In<strong>for</strong>mation added to catalog<br />

Delete of object from collection Related in<strong>for</strong>mation removed from catalog<br />

Restore of object into collection In<strong>for</strong>mation added to catalog<br />

Change of object long comment Comment updated in catalog<br />

Change of object label (text) Label updated in catalog<br />

Change of object owner Owner updated in catalog<br />

Move of object from a collection Related in<strong>for</strong>mation removed from catalog<br />

Move of object into collection In<strong>for</strong>mation added to catalog<br />

Rename of object Name of object updated in catalog<br />

User auxiliary storage pool (<strong>AS</strong>P)<br />

An <strong>SQL</strong> collection can be created in a user <strong>AS</strong>P by using the <strong>AS</strong>P clause on the<br />

CREATE COLLECTION and CREATE SCHEMA statements. The CRTLIB command<br />

Chapter 14. <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> Data Protection 247


can also be used to create a library in a user <strong>AS</strong>P. That library can then be used to<br />

receive <strong>SQL</strong> tables, views, and indexes. See the Backup and Recovery book and the<br />

Backup and Recovery book <strong>for</strong> more in<strong>for</strong>mation on auxiliary storage pools.<br />

248 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


Chapter 15. Testing <strong>SQL</strong> Statements in Application Programs<br />

This chapter describes how to establish a test environment <strong>for</strong> <strong>SQL</strong> statements in<br />

an application program and how to debug this program.<br />

Establishing a test environment<br />

Some things you need to test your program are:<br />

v Authorization. You need to be authorized to create tables and views, access <strong>SQL</strong><br />

data, and create and run programs.<br />

v A test data structure. If your program updates, inserts, or deletes data from<br />

tables and views, you should use test data to verify the running of the program. If<br />

your program only retrieves data from tables and views, you might consider<br />

using production-level data when testing your program. It is recommended,<br />

however, that you use the CL command Start Debug (STRDBG) with<br />

UPDPROD(*NO) to assure that the production level data does not accidentally<br />

get changed. See the chapter on testing in the CL <strong>Programming</strong>book <strong>for</strong> more<br />

in<strong>for</strong>mation on debugging.<br />

v Test input data. The input data your program uses during testing should be<br />

valid data that represents as many possible input conditions as you can think of.<br />

You cannot be sure that your output data is valid unless you use valid input<br />

data.<br />

If your program verifies that input data is valid, include both valid and not<br />

valid data to verify that the valid data is processed and the not valid data is<br />

detected.<br />

You might have to refresh the data <strong>for</strong> subsequent tests.<br />

To test the program thoroughly, test as many of the paths through the program as<br />

possible. For example:<br />

v Use input data that <strong>for</strong>ces the program to run each of its branches.<br />

v Check the results. For example, if the program updates a row, select the row to<br />

see if it was updated correctly.<br />

v Be sure to test the program error routines. Again, use input data that <strong>for</strong>ces the<br />

program to encounter as many of the anticipated error conditions as possible.<br />

v Test the editing and validation routines your program uses. Give the program as<br />

many different combinations of input data as possible to verify that it correctly<br />

edits or validates that data.<br />

Designing a test data structure<br />

To test an application that accesses <strong>SQL</strong> data, you might have to create test tables<br />

and views:<br />

v Test views of existing tables. If your application does not change data and the<br />

data exists in one or more production-level tables, you might consider using a<br />

view of the existing tables. It is also recommended that you use STRDBG<br />

command with UPDPROD(*NO) to assure that the production level data does<br />

not accidentally get changed. See the chapter on testing in the CL <strong>Programming</strong><br />

<strong>for</strong> more in<strong>for</strong>mation on debugging.<br />

© Copyright IBM Corp. 2000 249


v Test tables. When your application creates, changes, or deletes data, you will<br />

probably want to test the application by using tables that contain test data. See<br />

Chapter 2. Getting Started with <strong>SQL</strong> <strong>for</strong> a description of how to create tables and<br />

views.<br />

Also, you might want to use the CL command Create Duplicate Object<br />

(CRTDUPOBJ) to create a duplicate test table, view, or index.<br />

Authorization<br />

Be<strong>for</strong>e you can create a table, you must be authorized to create tables and to use<br />

the collection in which the table is to reside. In addition, you must have authority<br />

to create and run the programs you want to test.<br />

If you intend to use existing tables and views (either directly or as the basis <strong>for</strong> a<br />

view), you must be authorized to access those tables and views.<br />

If you want to create a view, you must be authorized to create views and must<br />

have authorization to each table and view on which the view is based. For more<br />

in<strong>for</strong>mation on specific authorities required <strong>for</strong> any specific <strong>SQL</strong> statement, see the<br />

<strong>SQL</strong> Reference book.<br />

Testing your <strong>SQL</strong> application programs<br />

There are two phases <strong>for</strong> testing <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> applications: the<br />

program debug phase and the per<strong>for</strong>mance verification phase.<br />

Program debug phase<br />

This test phase is done to ensure that the <strong>SQL</strong> queries are specified correctly and<br />

that the program is producing the correct results.<br />

Debugging your program with <strong>SQL</strong> statements is much the same as debugging<br />

your program without <strong>SQL</strong> statements. However, when <strong>SQL</strong> statements are run in<br />

a job in the debug mode, the database manager puts messages in the job log about<br />

how each <strong>SQL</strong> statement ran. This message is an indication of the <strong>SQL</strong>CODE <strong>for</strong><br />

the <strong>SQL</strong> statement. If the statement ran successfully, the <strong>SQL</strong>CODE value is zero,<br />

and a completion message is issued. A negative <strong>SQL</strong>CODE results in a diagnostic<br />

message. A positive <strong>SQL</strong>CODE results in an in<strong>for</strong>mational message.<br />

The message is either a 4-digit code prefixed by <strong>SQL</strong> or a 5-digit code prefixed by<br />

SQ. For example, an <strong>SQL</strong>CODE of −204 results in a message of <strong>SQL</strong>0204, and an<br />

<strong>SQL</strong>CODE of 30000 results in a message of SQ30000.<br />

Associated with a <strong>SQL</strong>CODE is a <strong>SQL</strong>STATE. The <strong>SQL</strong>STATE is an additional<br />

return code provided in the <strong>SQL</strong>CA that identifies common error conditions<br />

among the different IBM relational database products. The same error condition on<br />

different relational database products will produce the same <strong>SQL</strong>STATE. The same<br />

error conditions will not produce the same <strong>SQL</strong>CODE. This return code is<br />

particularly useful when determining the cause of errors returned from the<br />

relational database operations per<strong>for</strong>med on non-<strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> system.<br />

For non-ILE program debugging, references to high-level language statement<br />

numbers in debug mode must be taken from the compile listing. For ILE program<br />

debugging, precompile the program specifying DBGVIEW(*SOURCE) and then use<br />

the source-level debugger.<br />

250 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


<strong>SQL</strong> will always put messages in the job log <strong>for</strong> negative <strong>SQL</strong>CODEs and positive<br />

codes other than +100 regardless of whether it is in debug mode or not.<br />

Per<strong>for</strong>mance verification phase<br />

This test phase verifies that the appropriate indexes are available and that the<br />

queries are coded in a manner that allows the database manager to resolve the<br />

queries in the expected response time. The per<strong>for</strong>mance of an <strong>SQL</strong> application is<br />

dependent on the attributes of the tables being accessed. If you use small tables,<br />

the response time of the query is not affected by the availability of indexes.<br />

However, when you run that same query on a database with large tables and<br />

appropriate indexes do not exist, the response time <strong>for</strong> the queries can be very<br />

long.<br />

The test environment should resemble the production environment as closely as<br />

possible. The test collection should have tables with the same names and<br />

composition as the production collection. The same indexes need to be available<br />

over the tables in both collections. The number of rows and the distribution of<br />

values in the tables should be similar.<br />

See the Database Per<strong>for</strong>mance and Query Optimization book <strong>for</strong> a description of<br />

the tools and commands you can use to verify per<strong>for</strong>mance.<br />

Chapter 15. Testing <strong>SQL</strong> Statements in Application Programs 251


252 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


Chapter 16. Solving Common Database Problems<br />

This chapter describes techniques <strong>for</strong> solving some common database problems.<br />

Techniques are provided to help you do the following tasks:<br />

v Page through retrieved data<br />

v Retrieve data in reverse order<br />

v Establish position at the end of a table<br />

v Add data to the end of a table<br />

v Update data as it is retrieved from a table<br />

v Update data previously retrieved<br />

v Change the table definition<br />

Paging through retrieved data<br />

Retrieving in reverse order<br />

When a program retrieves data from the database, the FETCH statement allows the<br />

program to page <strong>for</strong>ward through the data. If you are using a scrollable cursor,<br />

then the program can page anywhere in the file, based on the scroll option<br />

specified on the FETCH statement. This allows the program to retrieve the data<br />

more than once. Several options that can be used to page through the data are<br />

listed in 56.<br />

If there is only one row <strong>for</strong> each value of DEPTNO, then the following statement<br />

specifies a unique ordering of rows:<br />

SELECT * FROM DEPARTMENT<br />

WHERE LOCATION = 'MINNESOTA'<br />

ORDER BY DEPTNO<br />

To retrieve the same rows in reverse order, simply specify that the order is<br />

descending, as in this statement:<br />

SELECT * FROM DEPARTMENT<br />

WHERE LOCATION = 'MINNESOTA'<br />

ORDER BY DEPTNO DESC<br />

A cursor on the second statement would retrieve rows in exactly the opposite<br />

order from a cursor on the first statement. But that is guaranteed only if the first<br />

statement specifies a unique ordering.<br />

If both statements are required in the same program, it might be useful to have<br />

two indexes on the DEPTNO column, one in ascending order and one in<br />

descending order.<br />

Establishing position at the end of a table<br />

For a scrollable cursor, the end of the table can be determined by the following:<br />

FETCH AFTER FROM C1<br />

© Copyright IBM Corp. 2000 253


Once the cursor is positioned at the end of the table, the program can use the<br />

PRIOR or RELATIVE scroll options to position and fetch data starting from the end<br />

of the table.<br />

Adding data to the end of a table<br />

The order in which rows are returned to your program depends on the ORDER BY<br />

clause in the <strong>SQL</strong> statement. To get the effect of adding data to the end of a table,<br />

include a sequence number column in the table definition. Then, when you retrieve<br />

data from the table, use an ORDER BY clause naming that column.<br />

Updating data as it is retrieved from a table<br />

You can update rows of data as you retrieve them. On the select-statement, use<br />

FOR UPDATE OF followed by a list of columns that may be updated. Then use the<br />

cursor-controlled UPDATE statement. The WHERE CURRENT OF clause names<br />

the cursor that points to the row you want to update. If a FOR UPDATE OF, an<br />

ORDER BY, a FOR READ ONLY, or a SCROLL clause without the DYNAMIC<br />

clause is not specified, all columns can be updated.<br />

If a multiple-row FETCH statement has been specified and run, the cursor is<br />

positioned on the last row of the block. There<strong>for</strong>e, if the WHERE CURRENT OF<br />

clause is specified on the UPDATE statement, the last row in the block is updated.<br />

If a row within the block must be updated, the program must first position the<br />

cursor on that row. Then the UPDATE WHERE CURRENT OF can be specified.<br />

Consider the following example:<br />

Table 27. Updating a Table<br />

Scrollable Cursor <strong>SQL</strong> Statement Comments<br />

EXEC <strong>SQL</strong><br />

DECLARE THISEMP DYNAMIC SCROLL CURSOR FOR<br />

SELECT EMPNO, WORKDEPT, BONUS<br />

FROM CORPDATA.EMPLOYEE<br />

WHERE WORKDEPT = ’D11’<br />

FOR UPDATE OF BONUS<br />

END-EXEC.<br />

EXEC <strong>SQL</strong><br />

OPEN THISEMP<br />

END-EXEC.<br />

EXEC <strong>SQL</strong><br />

WHENEVER NOT FOUND<br />

GO TO CLOSE-THISEMP<br />

END-EXEC.<br />

EXEC <strong>SQL</strong><br />

DEPTINFO and<br />

FETCH NEXT FROM THISEMP<br />

IND-ARRAY are declared<br />

FOR5ROWS<br />

in the program as a host<br />

INTO :DEPTINFO :IND-ARRAY<br />

structure array and an<br />

END-EXEC.<br />

indicator array.<br />

... determine if any employees in department D11 receive a<br />

bonus less than $500.00. If so, update that record to the new<br />

minimum of $500.00.<br />

254 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


Table 27. Updating a Table (continued)<br />

Scrollable Cursor <strong>SQL</strong> Statement Comments<br />

EXEC <strong>SQL</strong><br />

... positions to the record<br />

FETCH RELATIVE :NUMBACK FROM THISEMP<br />

in the block to update by<br />

END-EXEC.<br />

fetching in the reverse<br />

order.<br />

EXEC <strong>SQL</strong><br />

... updates the bonus <strong>for</strong><br />

UPDATE CORPDATA.EMPLOYEE<br />

the employee in<br />

SET BONUS = 500<br />

department D11 that is<br />

WHERE CURRENT OF THISEMP<br />

under the new $500.00<br />

END-EXEC.<br />

minimum.<br />

EXEC <strong>SQL</strong><br />

... positions to the<br />

FETCH RELATIVE :NUMBACK FROM THISEMP<br />

beginning of the same<br />

FOR5ROWS<br />

block that was already<br />

INTO :DEPTINFO :IND-ARRAY<br />

fetched and fetches the<br />

END-EXEC.<br />

... branch back to determine if any more employees in the block<br />

have a bonus under $500.00.<br />

block again. (NUMBACK<br />

-(5 - NUMBACK - 1))<br />

Restrictions<br />

... branch back to fetch and process the next block of rows.<br />

CLOSE-THISEMP.<br />

EXEC <strong>SQL</strong><br />

CLOSE THISEMP<br />

END-EXEC.<br />

You cannot use FOR UPDATE OF with a select-statement that includes any of<br />

these elements:<br />

v The first FROM clause identifies more than one table or view.<br />

v The first FROM clause identifies a read-only view.<br />

v The first SELECT clause specifies the keyword DISTINCT.<br />

v The outer subselect contains a GROUP BY clause.<br />

v The outer subselect contains a HAVING clause.<br />

v The first SELECT clause contains a column function.<br />

v The select-statement contains a subquery such that the base object of the outer<br />

subselect and of the subquery is the same table.<br />

v The select-statement contains a UNION or UNION ALL operator.<br />

v The select-statement includes a FOR READ ONLY clause.<br />

v The SCROLL keyword is specified without DYNAMIC.<br />

If a FOR UPDATE OF clause is specified, you cannot update columns that were<br />

not named in the FOR UPDATE OF clause. But you can name columns in the FOR<br />

UPDATE OF clause that are not in the SELECT list, as in this example:<br />

SELECT A, B, C FROM TABLE<br />

FOR UPDATE OF A,E<br />

Do not name more columns than you need in the FOR UPDATE OF clause;<br />

indexes on those columns are not used when you access the table.<br />

Chapter 16. Solving Common Database Problems 255


Updating data previously retrieved<br />

Changing the table definition<br />

You can page through and update data that had previously been retrieved by<br />

doing one of three things:<br />

v Use the UPDATE statement with a WHERE clause that names all of the values<br />

in the row or specifies a unique key of the table. You can code one statement,<br />

using host variables in the WHERE clause, and run the same statement many<br />

times with different values of the variables to update different rows.<br />

v For a scrollable cursor, the program can use the appropriate scroll options to<br />

retrieve the row that had previously been fetched. Then, using the WHERE<br />

CURRENT OF clause on the UPDATE statement, the row can be changed to the<br />

appropriate value.<br />

You can add, drop, and alter columns in a table using the <strong>SQL</strong> ALTER TABLE<br />

statement or the Change Physical File (CHGPF) CL command.<br />

See the <strong>SQL</strong> Reference book <strong>for</strong> in<strong>for</strong>mation on how to use the <strong>SQL</strong> ALTER TABLE<br />

statement. See the Control Language (CL) book <strong>for</strong> in<strong>for</strong>mation on how to use the<br />

Change Physical File (CHGPF) CL command.<br />

You can also dynamically create a view of the table, which includes only the<br />

columns you want, in the order you want.<br />

256 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


Chapter 17. Distributed Relational Database Function<br />

A distributed relational database consists of a set of <strong>SQL</strong> objects that are spread across<br />

interconnected computer systems. These relational databases can be of the same<br />

type (<strong>for</strong> example, <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong>) or of different types (<strong>DB2</strong> <strong>for</strong> OS/390,<br />

<strong>DB2</strong> <strong>for</strong> VM, <strong>DB2</strong> Universal Database (<strong>UDB</strong>), or non-IBM database management<br />

systems which support DRDA). Each relational database has a relational database<br />

manager to manage the tables in its environment. The database managers<br />

communicate and cooperate with each other in a way that allows a given database<br />

manager access to run <strong>SQL</strong> statements on a relational database on another system.<br />

The application requester supports the application side of a connection. The<br />

application server is the local or remote database to which an application requester<br />

is connected. <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> provides support <strong>for</strong> Distributed Relational<br />

Database Architecture (DRDA) to allow an application requester to communicate<br />

with application servers. In addition, <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> can invoke exit<br />

programs to allow access to data on other database management systems which do<br />

not support DRDA. These exit programs are called application requester driver<br />

(ARD) programs.<br />

<strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> supports two levels of distributed relational database:<br />

v Remote unit of work (RUW)<br />

Remote unit of work is where the preparation and running of <strong>SQL</strong> statements<br />

occurs at only one application server during a unit of work. <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong><br />

<strong>AS</strong>/<strong>400</strong> supports RUW over either APPC or TCP/IP.<br />

v Distributed unit of work (DUW)<br />

Distributed unit of work is where the preparation and running of <strong>SQL</strong><br />

statements can occur at multiple applications servers during a unit of work.<br />

However, a single <strong>SQL</strong> statement can only refer to objects located at a single<br />

application server. <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> supports DUW over APPC only.<br />

For comprehensive in<strong>for</strong>mation about distributed relational databases, see<br />

theDistributed Database <strong>Programming</strong> book.<br />

<strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> distributed relational database support<br />

The <strong>DB2</strong> <strong>UDB</strong> Query Manager and <strong>SQL</strong> Development Kit licensed program<br />

supports interactive access to distributed databases with the following <strong>SQL</strong><br />

statements:<br />

v CONNECT<br />

v SET CONNECTION<br />

v DISCONNECT<br />

v RELE<strong>AS</strong>E<br />

v DROP PACKAGE<br />

v GRANT PACKAGE<br />

v REVOKE PACKAGE<br />

For detailed descriptions of these statements, see the <strong>SQL</strong> Reference book.<br />

© Copyright IBM Corp. 2000 257


Additional support is provided by the development kit through parameters on the<br />

<strong>SQL</strong> precompiler commands:<br />

Create <strong>SQL</strong> ILE C Object (CRT<strong>SQL</strong>CI) command<br />

Create <strong>SQL</strong> COBOL Program (CRT<strong>SQL</strong>CBL) command<br />

Create <strong>SQL</strong> ILE COBOL Object (CRT<strong>SQL</strong>CBLI) command<br />

Create <strong>SQL</strong> PL/I Program (CRT<strong>SQL</strong>PLI) command<br />

Create <strong>SQL</strong> RPG Program (CRT<strong>SQL</strong>RPG) command<br />

Create <strong>SQL</strong> ILE RPG Object (CRT<strong>SQL</strong>RPGI) command<br />

For more in<strong>for</strong>mation on the <strong>SQL</strong> precompiler commands, see the topic Preparing<br />

and Running a Program with <strong>SQL</strong> Statements in the <strong>SQL</strong> <strong>Programming</strong> with Host<br />

Languages in<strong>for</strong>mation. The create <strong>SQL</strong> Package (CRT<strong>SQL</strong>PKG) command lets you<br />

create an <strong>SQL</strong> package from an <strong>SQL</strong> program that was created as a distributed<br />

program. Syntax and parameter definitions <strong>for</strong> the CRT<strong>SQL</strong>PKG and CRT<strong>SQL</strong>xxx<br />

commands are provided in Appendix C. <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> CL Command<br />

Descriptions.<br />

<strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> distributed relational database example program<br />

A remote unit of work relational database sample program has been shipped with<br />

the <strong>SQL</strong> product. There are several files and members within the Q<strong>SQL</strong> library to<br />

help you set up an environment that will run a distributed <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong><br />

sample program.<br />

To use these files and members, you need to run the SETUP batch job located in<br />

the file Q<strong>SQL</strong>/QSQSAMP. The SETUP batch job allows you to customize the<br />

example to do the following:<br />

v Create the QSQSAMP library at the local and remote locations.<br />

v Set up relational database directory entries at the local and remote locations.<br />

v Create application panels at the local location.<br />

v Precompile, compile, and run programs to create distributed sample application<br />

collections, tables, indexes, and views.<br />

v Load data into the tables at the local and remote locations.<br />

v Precompile and compile programs.<br />

v Create <strong>SQL</strong> packages at the remote location <strong>for</strong> the application programs.<br />

v Precompile, compile, and run the program to update the location column in the<br />

department table.<br />

Be<strong>for</strong>e running the SETUP, you may need to edit the SETUP member of the<br />

Q<strong>SQL</strong>/QSQSAMP file. Instructions are included in the member as comments. To<br />

run the SETUP, specify the following command on the <strong>AS</strong>/<strong>400</strong> command line:<br />

========> SBMDBJOB Q<strong>SQL</strong>/QSQSAMP SETUP<br />

Wait <strong>for</strong> the batch job to complete.<br />

To use the sample program, specify the following command on the command line:<br />

========> ADDLIBLE QSQSAMP<br />

258 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


To call the first display that allows you to customize the sample program, specify<br />

the following command on the command line.<br />

========> CALL QSQ8HC3<br />

The following display appears. From this display, you can customize your database<br />

sample program.<br />

<strong>DB2</strong> <strong>for</strong> OS/<strong>400</strong> ORGANIZATION APPLICATION<br />

ACTION...........: _ A (ADD) E (ER<strong>AS</strong>E)<br />

D (DISPLAY) U (UPDATE)<br />

OBJECT...........: __ DE (DEPARTMENT) EM (EMPLOYEE)<br />

DS (DEPT STRUCTURE)<br />

SEARCH CRITERIA..: __ DI (DEPARTMENT ID) MN (MANAGER NAME)<br />

DN (DEPARTMENT NAME) EI (EMPLOYEE ID)<br />

MI (MANAGER ID) EN (EMPLOYEE NAME)<br />

LOCATION.........: ________________ (BLANK IMPLIES LOCAL LOCATION)<br />

DATA.............: _______________________________<br />

F3=Exit<br />

<strong>SQL</strong> package support<br />

Bottom<br />

(C) COPYRIGHT IBM CORP. 1982, 1991<br />

The OS/<strong>400</strong> program supports an object called an <strong>SQL</strong> package. (OS/<strong>400</strong> object<br />

type is *<strong>SQL</strong>PKG.) The <strong>SQL</strong> package contains the control structures and access<br />

plans necessary to process <strong>SQL</strong> statements on the application server when running<br />

a distributed program. An <strong>SQL</strong> package can be created when:<br />

v The RDB parameter is specified on the CRT<strong>SQL</strong>xxx command and the program<br />

object is successfully created. The <strong>SQL</strong> package will be created on the system<br />

specified by the RDB parameter.<br />

If the compile is unsuccessful or the compile only creates the module object, the<br />

<strong>SQL</strong> package will not be created.<br />

v Using the CRT<strong>SQL</strong>PKG command. The CRT<strong>SQL</strong>PKG can be used to create a<br />

package when the package was not created at precompile time or if the package<br />

is needed at an RDB other than the one specified on the precompile command.<br />

The Delete <strong>SQL</strong> Package (DLT<strong>SQL</strong>PKG) command allows you to delete an <strong>SQL</strong><br />

package on the local system.<br />

An <strong>SQL</strong> package is not created unless the privileges held by the authorization ID<br />

associated with the creation of the <strong>SQL</strong> package includes appropriate authority <strong>for</strong><br />

creating a package on the remote system (the application server). To run the<br />

program, the authorization ID must include EXECUTE privileges on the <strong>SQL</strong><br />

package. On <strong>AS</strong>/<strong>400</strong> systems, the EXECUTE privilege includes system authority of<br />

*OBJOPR and *EXECUTE.<br />

The syntax <strong>for</strong> the Create <strong>SQL</strong> Package (CRT<strong>SQL</strong>PKG) command is shown in<br />

Appendix C. <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> CL Command Descriptions.<br />

Chapter 17. Distributed Relational Database Function 259


Valid <strong>SQL</strong> statements in an <strong>SQL</strong> package<br />

Programs that connect to another <strong>AS</strong>/<strong>400</strong> can use any of the <strong>SQL</strong> statements as<br />

described in the <strong>SQL</strong> Reference book, except the SET TRANSACTION statement.<br />

Programs compiled using <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> that refer to a system that is not<br />

<strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> can use executable <strong>SQL</strong> statements supported by that remote<br />

system. The precompiler will continue to issue diagnostic messages <strong>for</strong> statements<br />

it does not understand. These statements are sent to the remote system during the<br />

creation of the <strong>SQL</strong> package. The run-time support will return a <strong>SQL</strong>CODE of -84<br />

or -525 when the statement cannot be run on the current application server. For<br />

example, multiple-row FETCH, blocked INSERT, and scrollable cursor support are<br />

allowed only in distributed programs where both the application requester and<br />

application server are OS/<strong>400</strong> at Version 2 Release 2 or later. For more in<strong>for</strong>mation,<br />

see the appendix that contains the section ″Considerations <strong>for</strong> Using Distributed<br />

Relational Database″ in the <strong>SQL</strong> Reference book.<br />

Considerations <strong>for</strong> creating an <strong>SQL</strong> package<br />

There are many considerations to think about when you are creating an <strong>SQL</strong><br />

package. Some of these considerations are listed below.<br />

CRT<strong>SQL</strong>PKG Authorization<br />

When creating an <strong>SQL</strong> package on an <strong>AS</strong>/<strong>400</strong> system the authorization ID used<br />

must have *USE authority to the CRT<strong>SQL</strong>PKG command.<br />

Creating a Package on a non-<strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong><br />

When you create a program and <strong>SQL</strong> package <strong>for</strong> a non-<strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong>, and<br />

try to use <strong>SQL</strong> statements that are unique to that relational database, the<br />

CRT<strong>SQL</strong>xxx GENLVL parameter should be set to 30. The program will be created<br />

unless a message with a severity level of greater than 30 is issued. If a message is<br />

issued with a severity level of greater than 30, the statement is probably not valid<br />

<strong>for</strong> any relational database. For example, undefined or unusable host variables or<br />

constants that are not valid would generate a message severity greater than 30.<br />

The precompiler listing should be checked <strong>for</strong> unexpected messages when running<br />

with a GENLVL greater than 10. When you are creating a package <strong>for</strong> a <strong>DB2</strong><br />

Universal Database, you must set the GENLVL parameter to a value less than 20.<br />

If the RDB parameter specifies a system that is not a <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> system,<br />

then the following options should not be used on the CRT<strong>SQL</strong>xxx command:<br />

v COMMIT(*NONE)<br />

v OPTION(*SYS)<br />

v DATFMT(*MDY)<br />

v DATFMT(*DMY)<br />

v DATFMT(*JUL)<br />

v DATFMT(*YMD)<br />

v DATFMT(*JOB)<br />

v DYNUSRPRF(*OWNER)<br />

v TIMFMT(*HMS) if TIMSEP(*BLANK) or TIMSEP(’,’) is specified<br />

v SRTSEQ(*JOBRUN)<br />

v SRTSEQ(*LANGIDUNQ)<br />

260 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


v SRTSEQ(*LANGIDSHR)<br />

v SRTSEQ(library-name/table-name)<br />

Note: When connecting to a <strong>DB2</strong> Universal Database application server, the<br />

following additional rules apply:<br />

v The specified date and time <strong>for</strong>mats must be the same <strong>for</strong>mat<br />

v A value of *BLANK must be used <strong>for</strong> the TEXT parameter<br />

v Default collections (DFTRDBCOL) are not supported<br />

v The CCSID of the source program from which the package is being created must<br />

not be 65535; if 65535 is used, an empty package is created.<br />

Target Release (TGTRLS)<br />

While creating the package, the <strong>SQL</strong> statements are checked to determine which<br />

release can support the function. This release is set as the restore level of the<br />

package. For example, if the package contains a CREATE TABLE statement which<br />

adds a FOREIGN KEY constraint to the table, then the restore level of the package<br />

will be Version 3 Release 1, because FOREIGN KEY constraints were not supported<br />

prior to this release. TGTRLS message are suppressed when the TGTRLS parameter<br />

is *CURRENT.<br />

<strong>SQL</strong> Statement Size<br />

The create <strong>SQL</strong> package function may not be able to handle the same size <strong>SQL</strong><br />

statement that the precompiler can process. During the precompile of the <strong>SQL</strong><br />

program, the <strong>SQL</strong> statement is placed into the associated space of the program.<br />

When this occurs, each token is separated by a blank. In addition, when the RDB<br />

parameter is specified, the host variables of the source statement are replaced with<br />

an ’H’. The create <strong>SQL</strong> package function passes this statement to the application<br />

server, along with a list of the host variables <strong>for</strong> that statement. The addition of the<br />

blanks between the tokens and the replacement of host variables may cause the<br />

statement to exceed the maximum <strong>SQL</strong> statement size (<strong>SQL</strong>0101 reason 5).<br />

Statements that do not require a package<br />

In some cases, you might try to create an <strong>SQL</strong> package but the <strong>SQL</strong> package will<br />

not be created and the program will still run. This situation occurs when the<br />

program contains only <strong>SQL</strong> statements that do not require an <strong>SQL</strong> package to run.<br />

For example, a program that contains only the <strong>SQL</strong> statement DESCRIBE TABLE<br />

will generate message <strong>SQL</strong>5041 during <strong>SQL</strong> package creation. The <strong>SQL</strong> statements<br />

that do not require an <strong>SQL</strong> package are:<br />

v DESCRIBE TABLE<br />

v COMMIT<br />

v ROLLBACK<br />

v CONNECT<br />

v SET CONNECTION<br />

v DISCONNECT<br />

v RELE<strong>AS</strong>E<br />

Package object type<br />

<strong>SQL</strong> packages are always created as non-ILE objects and always run in the default<br />

activation group.<br />

Chapter 17. Distributed Relational Database Function 261


ILE programs and service programs<br />

ILE programs and service programs that bind several modules containing <strong>SQL</strong><br />

statements must have a separate <strong>SQL</strong> package <strong>for</strong> each module.<br />

Package creation connection<br />

The type of connection done <strong>for</strong> the package creation is based on the type of<br />

connect requested using the RDBCNNMTH parameter. If RDBCNNMTH(*DUW)<br />

was specified, commitment control is used and the connection may be a read-only<br />

connection. If the connection is read-only, then the package creation will fail.<br />

Unit of work<br />

Because package creation implicitly per<strong>for</strong>ms a commit or rollback, the commit<br />

definition must be at a unit of work boundary be<strong>for</strong>e the package creation is<br />

attempted. The following conditions must all be true <strong>for</strong> a commit definition to be<br />

at a unit of work boundary:<br />

v <strong>SQL</strong> is at a unit of work boundary.<br />

v There are no local or DDM files open using commitment control and no closed<br />

local or DDM files with pending changes.<br />

v There are no API resources registered.<br />

v There are no LU 6.2 resources registered that are not associated with DRDA or<br />

DDM.<br />

Creating packages locally<br />

The name specified on the RDB parameter can be the name of the local system. If<br />

it is the name of the local system, the <strong>SQL</strong> package will be created on the local<br />

system. The <strong>SQL</strong> package can be saved (SAVOBJ command) and then restored<br />

(RSTOBJ command) to another <strong>AS</strong>/<strong>400</strong> system. When you run the program with a<br />

connection to the local system, the <strong>SQL</strong> package is not used. If you specify<br />

*LOCAL <strong>for</strong> the RDB parameter, an *<strong>SQL</strong>PKG object is not created, but the<br />

package in<strong>for</strong>mation is saved in the *PGM object.<br />

Labels<br />

You can use the LABEL ON statement to create a description <strong>for</strong> the <strong>SQL</strong> package.<br />

Consistency token<br />

The program and its associated <strong>SQL</strong> package contain a consistency token that is<br />

checked when a call is made to the <strong>SQL</strong> package. The consistency tokens must<br />

match or the package cannot be used. It is possible <strong>for</strong> the program and <strong>SQL</strong><br />

package to appear to be uncoordinated. Assume the program is on the <strong>AS</strong>/<strong>400</strong><br />

system and the application server is another <strong>AS</strong>/<strong>400</strong> system. The program is<br />

running in session A and it is recreated in session B (where the <strong>SQL</strong> package is<br />

also recreated). The next call to the program in session A could result in a<br />

consistency token error. To avoid locating the <strong>SQL</strong> package on each call, <strong>SQL</strong><br />

maintains a list of addresses <strong>for</strong> <strong>SQL</strong> packages that are used by each session. When<br />

session B re-creates the <strong>SQL</strong> package, the old <strong>SQL</strong> package is moved to the<br />

QRPLOBJ library. The address to the <strong>SQL</strong> package in session A is still valid. (This<br />

situation can be avoided by creating the program and <strong>SQL</strong> package from the<br />

session that is running the program, or by submitting a remote command to delete<br />

the old <strong>SQL</strong> package be<strong>for</strong>e creating the program.)<br />

262 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


To use the new <strong>SQL</strong> package, you should end the connection with the remote<br />

system. You can either sign off the session and then sign on again, or you can use<br />

the interactive <strong>SQL</strong> (STR<strong>SQL</strong>) command to issue a DISCONNECT <strong>for</strong> unprotected<br />

network connections or a RELE<strong>AS</strong>E followed by a COMMIT <strong>for</strong> protected<br />

connections. RCLDDMCNV should then be used to end the network connections.<br />

Call the program again.<br />

<strong>SQL</strong> and recursion<br />

If you invoke <strong>SQL</strong> from an attention key program while you are already<br />

precompiling, you will receive unpredictable results.<br />

The CRT<strong>SQL</strong>xxx, CRT<strong>SQL</strong>PKG, STR<strong>SQL</strong> commands and the <strong>SQL</strong> run-time<br />

environment are not recursive. They will produce unpredictable results if recursion<br />

is attempted. Recursion would occur if while one of the commands is running, (or<br />

running a program with embedded <strong>SQL</strong> statements) the job is interrupted be<strong>for</strong>e<br />

the command has completed, and another <strong>SQL</strong> function is started.<br />

CCSID considerations <strong>for</strong> <strong>SQL</strong><br />

If you are running a distributed application and one of your systems is not an<br />

<strong>AS</strong>/<strong>400</strong> system, the job CCSID value on the <strong>AS</strong>/<strong>400</strong> cannot be set to 65535.<br />

Be<strong>for</strong>e requesting that the remote system create an <strong>SQL</strong> package, the application<br />

requester always converts the name specified on the RDB parameter, <strong>SQL</strong> package<br />

name, library name, and the text of the <strong>SQL</strong> package from the CCSID of the job to<br />

CCSID 500. This is required by DRDA. When the remote relational database is an<br />

<strong>AS</strong>/<strong>400</strong> system, the names are not converted from CCSID 500 to the job CCSID.<br />

It is recommended that delimited identifiers not be used <strong>for</strong> table, view, index,<br />

collection, library, or <strong>SQL</strong> package names. Conversion of names does not occur<br />

between systems with different CCSIDs. Consider the following example with<br />

system A running with a CCSID of 37 and system B running with a CCSID of 500.<br />

v Create a program that creates a table with the name ″a¬b|c″ on system A.<br />

v Save program ″a¬b|c″ on system A, then restore it to system B.<br />

v The code point <strong>for</strong> ¬ in CCSID 37 is x’5F’ while in CCSID 500 it is x’BA’.<br />

v On system B the name would display ″a[b]c″. If you created a program that<br />

referenced the table whose name was ″a¬b|c.″, the program would not find the<br />

table.<br />

The at sign (@), pound sign (#), and dollar sign ($) characters should not be used<br />

in <strong>SQL</strong> object names. Their code points depend on the CCSID used. If you use<br />

delimited names or the three national extenders, the name resolution functions<br />

may possibly fail in a future release.<br />

Connection management and activation groups<br />

Connections and conversations<br />

Prior to the use of TCP/IP by DRDA, the term ’connection’ was not ambiguous. It<br />

referred to a connection from the <strong>SQL</strong> point of view. That is, a connection started<br />

at the time one did a CONNECT TO some RDB, and ended when a DISCONNECT<br />

was done or a RELE<strong>AS</strong>E ALL followed by a successful COMMIT occurred. The<br />

Chapter 17. Distributed Relational Database Function 263


APPC conversation may or may not have been kept up, depending on the job’s<br />

DDMCNV attribute value, and whether the conversation was with an <strong>AS</strong>/<strong>400</strong> or<br />

other type of system.<br />

TCP/IP terminology does not include the term ’conversation’. A similar concept<br />

exists, however. With the advent of TCP/IP support by DRDA, use of the term<br />

’conversation’ will be replaced, in this book, by the more general term ’connection’,<br />

unless the discussion is specifically about an APPC conversation. There<strong>for</strong>e, there<br />

are now two different types of connections about which the reader must be aware:<br />

<strong>SQL</strong> connections of the type described above, and ’network’ connections which<br />

replace the term ’conversation’.<br />

Where there would be the possibility of confusion between the two types of<br />

connections, the word will be qualified by ’<strong>SQL</strong>’ or ’network’ to allow the reader<br />

to understand the intended meaning.<br />

<strong>SQL</strong> connections are managed at the activation group level. Each activation group<br />

within a job manages its own connections and these connections are not shared<br />

across activation groups. For programs that run in the default activation group,<br />

connections are still managed as they were prior to Version 2 Release 3.<br />

The following is an example of an application that runs in multiple activation<br />

groups. This example is used to illustrate the interaction between activation<br />

groups, connection management, and commitment control. It is not a<br />

recommended coding style.<br />

Source code <strong>for</strong> PGM1:<br />

....<br />

EXEC <strong>SQL</strong><br />

CONNECT TO SYSB<br />

END-EXEC.<br />

EXEC <strong>SQL</strong><br />

SELECT ....<br />

END-EXEC.<br />

CALL PGM2.<br />

....<br />

Figure 10. Source Code <strong>for</strong> PGM1<br />

Command to create program and <strong>SQL</strong> package <strong>for</strong> PGM1:<br />

CRT<strong>SQL</strong>CBL PGM(PGM1) COMMIT(*NONE) RDB(SYSB)<br />

264 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


Source code <strong>for</strong> PGM2:<br />

....<br />

...<br />

Command to create program and <strong>SQL</strong> package <strong>for</strong> PGM2:<br />

CRT<strong>SQL</strong>CI OBJ(PGM2) COMMIT(*CHG) RDB(SYSC) OBJTYPE(*PGM)<br />

Source code <strong>for</strong> PGM3:<br />

EXEC <strong>SQL</strong><br />

CONNECT TO SYSC;<br />

EXEC <strong>SQL</strong><br />

DECLARE C1 CURSOR FOR<br />

SELECT ....;<br />

EXEC <strong>SQL</strong><br />

OPEN C1;<br />

do {<br />

EXEC <strong>SQL</strong><br />

FETCH C1 INTO :st1;<br />

EXEC <strong>SQL</strong><br />

UPDATE ...<br />

SET COL1 = COL1+10<br />

WHERE CURRENT OF C1;<br />

PGM3(st1);<br />

} while <strong>SQL</strong>CODE == 0;<br />

EXEC <strong>SQL</strong><br />

CLOSE C1;<br />

EXEC <strong>SQL</strong> COMMIT;<br />

Figure 11. Source Code <strong>for</strong> PGM2<br />

...<br />

EXEC <strong>SQL</strong><br />

INSERT INTO TAB VALUES(:st1);<br />

EXEC <strong>SQL</strong> COMMIT;<br />

....<br />

Figure 12. Source Code <strong>for</strong> PGM3<br />

Commands to create program and <strong>SQL</strong> package <strong>for</strong> PGM3:<br />

CRT<strong>SQL</strong>CI OBJ(PGM3) COMMIT(*CHG) RDB(SYSD) OBJTYPE(*MODULE)<br />

CRTPGM PGM(PGM3) ACTGRP(APPGRP)<br />

CRT<strong>SQL</strong>PKG PGM(PGM3) RDB(SYSD)<br />

Chapter 17. Distributed Relational Database Function 265


SYSA<br />

Job:<br />

PGM1<br />

Call<br />

Default Activation<br />

Group:<br />

Call<br />

System-Named<br />

Activation Group:<br />

PGM2<br />

Call Return Call<br />

Activation Group<br />

APPGRP:<br />

PGM3<br />

Connect<br />

Connect<br />

Connect<br />

SYSB (Remote)<br />

SYSC (Remote)<br />

SYSD (Remote)<br />

<strong>SQL</strong> Package<br />

<strong>for</strong> PGM1<br />

<strong>SQL</strong> Package<br />

<strong>for</strong> PGM2<br />

<strong>SQL</strong>Package<br />

<strong>for</strong> PGM3<br />

In this example, PGM1 is a non-ILE program created using the CRT<strong>SQL</strong>CBL<br />

command. This program runs in the default activation group. PGM2 is created<br />

using the CRT<strong>SQL</strong>CI command, and it runs in a system-named activation group.<br />

PGM3 is also created using the CRT<strong>SQL</strong>CI command, but it runs in the activation<br />

group named APPGRP. Because APPGRP is not the default value <strong>for</strong> the ACTGRP<br />

parameter, the CRTPGM command is issued separately. The CRTPGM command is<br />

followed by a CRT<strong>SQL</strong>PKG command that creates the <strong>SQL</strong> package object on the<br />

SYSD relational database. In this example, the user has not explicitly started the job<br />

level commitment definition. <strong>SQL</strong> implicitly starts commitment control.<br />

1. PGM1 is called and runs in the default activation group.<br />

2. PGM1 connects to relational database SYSB and runs a SELECT statement.<br />

3. PGM1 then calls PGM2, which runs in a system-named activation group.<br />

4. PGM2 does a connect to relational database SYSC. Because PGM1 and PGM2<br />

are in different activation groups, the connection started by PGM2 in the<br />

system-named activation group does not disconnect the connection started by<br />

PGM1 in the default activation group. Both connections are active. PGM2 opens<br />

the cursor and fetches and updates a row. PGM2 is running under commitment<br />

control, is in the middle of a unit of work, and is not at a connectable state.<br />

5. PGM2 calls PGM3, which runs in activation group APPGRP.<br />

6. The INSERT statement is the first statement run in activation group APPGRP.<br />

The first <strong>SQL</strong> statement causes an implicit connect to relational database SYSD.<br />

A row is inserted into table TAB located at relational database SYSD. The insert<br />

266 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5<br />

Job:<br />

Job:<br />

Job:<br />

Default Activation<br />

Group:<br />

Default Activation<br />

Group:<br />

Default Activation<br />

Group:<br />

RV2W577-3


is then committed. The pending changes in the system-named activation group<br />

are not committed, because commitment control was started by <strong>SQL</strong> with a<br />

commit scope of activation group.<br />

7. PGM3 is then exited and control returns to PGM2. PGM2 fetches and updates<br />

another row.<br />

8. PGM3 is called again to insert the row. An implicit connect was done on the<br />

first call to PGM3. It is not done on subsequent calls because the activation<br />

group did not end between calls to PGM3. Finally, all the rows are processed<br />

by PGM2 and the unit of work associated with the system-named activation<br />

group is committed.<br />

Multiple connections to the same relational database<br />

If different activation groups connect to the same relational database, each <strong>SQL</strong><br />

connection has its own network connection and its own application server job. If<br />

activation groups are run with commitment control, changes committed in one<br />

activation group do not commit changes in other activation groups unless the<br />

job-level commitment definition is used.<br />

SYSA<br />

Job:<br />

Default ActivationGroup:<br />

System-Named<br />

Activation Group:<br />

Connect<br />

Connect<br />

SYSB<br />

Job:<br />

Implicit connection management <strong>for</strong> the default activation<br />

group<br />

The application requester can implicitly connect to an application server. Implicit<br />

<strong>SQL</strong> connection occurs when the application requester detects the first <strong>SQL</strong><br />

statement is being issued by the first active <strong>SQL</strong> program <strong>for</strong> the default activation<br />

group and the following items are true:<br />

v The <strong>SQL</strong> statement being issued is not a CONNECT statement with parameters.<br />

v <strong>SQL</strong> is not active in the default activation group.<br />

Job:<br />

RV2W578-2<br />

Chapter 17. Distributed Relational Database Function 267


For a distributed program, the implicit <strong>SQL</strong> connection is to the relational database<br />

specified on the RDB parameter. For a nondistributed program, the implicit <strong>SQL</strong><br />

connection is to the local relational database.<br />

<strong>SQL</strong> will end any active connections in the default activation group when <strong>SQL</strong><br />

becomes not active. <strong>SQL</strong> becomes not active when:<br />

v The application requester detects the first active <strong>SQL</strong> program <strong>for</strong> the process<br />

has ended and the following are all true:<br />

– There are no pending <strong>SQL</strong> changes<br />

– There are no connections using protected connections<br />

– A SET TRANSACTION statement is not active<br />

– No programs that were precompiled with CLO<strong>SQL</strong>CSR(*ENDJOB) were run.<br />

If there are pending changes, protected connections, or an active SET<br />

TRANSACTION statement, <strong>SQL</strong> is placed in the exited state. If programs<br />

precompiled with CLO<strong>SQL</strong>CSR(*ENDJOB) were run, <strong>SQL</strong> will remain active <strong>for</strong><br />

the default activation group until the job ends.<br />

v At the end of a unit of work if <strong>SQL</strong> is in the exited state. This occurs when you<br />

issue a COMMIT or ROLLBACK command outside of an <strong>SQL</strong> program.<br />

v At the end of a job.<br />

Implicit connection management <strong>for</strong> nondefault activation<br />

groups<br />

Distributed support<br />

The application requester can implicitly connect to an application server. Implicit<br />

<strong>SQL</strong> connection occurs when the application requester detects that the first <strong>SQL</strong><br />

statement issued <strong>for</strong> the activation group is not a CONNECT statement with<br />

parameters.<br />

For a distributed program, the implicit <strong>SQL</strong> connection is made to the relational<br />

database specified on the RDB parameter. For a nondistributed program, the<br />

implicit <strong>SQL</strong> connection is made to the local relational database.<br />

Implicit disconnect can occur at the following times in a process:<br />

v When the activation group ends, if commitment control is not active, activation<br />

group level commitment control is active, or the job level commitment definition<br />

is at a unit of work boundary.<br />

If the job level commitment definition is active and not at a unit of work<br />

boundary, <strong>SQL</strong> is placed in the exited state.<br />

v If <strong>SQL</strong> is in the exited state, when the job level commitment definition is<br />

committed or rolled back.<br />

v At the end of a job.<br />

<strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> supports two levels of distributed relational database:<br />

v Remote unit of work (RUW)<br />

Remote unit of work is where the preparation and running of <strong>SQL</strong> statements<br />

occurs at only one application server during a unit of work. An activation group<br />

with an application process at an application requester can connect to an<br />

application server and, within one or more units of work, run any number of<br />

268 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


static or dynamic <strong>SQL</strong> statements that refer to objects on the application server.<br />

Remote unit of work is also referred to as DRDA level 1.<br />

v Distributed unit of work (DUW)<br />

Distributed unit of work is where the preparation and running of <strong>SQL</strong><br />

statements can occur at multiple applications servers during a unit of work.<br />

However, a single <strong>SQL</strong> statement can only refer to objects located at a single<br />

application server. Distributed unit of work is also referred to as DRDA level 2.<br />

Distributed unit of work allows:<br />

– Update access to multiple application servers in one logical unit of work<br />

or<br />

– Update access to a single application server with read access to multiple<br />

application servers, in one logical unit of work.<br />

Whether multiple application servers can be updated in a unit of work is<br />

dependent on the existence of a sync point manager at the application requester,<br />

sync point managers at the application servers, and two-phase commit protocol<br />

support between the application requester and the application servers.<br />

The sync point manager is a system component that coordinates commit and<br />

rollback operations among the participants in the two-phase commit protocol.<br />

When running distributed updates, the sync point managers on the different<br />

systems cooperate to ensure that resources reach a consistent state. The protocols<br />

and flows used by sync point managers are also referred to as two-phase<br />

commit protocols.<br />

If two-phase commit protocols will be used, the connection is a protected<br />

resource; otherwise the connection is an unprotected resource.<br />

The type of data transport protocols used between systems affects whether the<br />

network connection is protected or unprotected. In OS/<strong>400</strong> V4R2, TCP/IP<br />

connections are always unprotected; thus they can participate in a distributed<br />

unit of work in only a limited way.<br />

For example, if the first connection made from the program is to an <strong>AS</strong>/<strong>400</strong> over<br />

TCP/IP, updates can be per<strong>for</strong>med over it, but any subsequent connections, even<br />

over APPC, will be read only.<br />

Note that when using Interactive <strong>SQL</strong>, the first <strong>SQL</strong> connection is to the local<br />

system. There<strong>for</strong>e in order to make updates to a remote system using TCP/IP,<br />

you must do a RELE<strong>AS</strong>E ALL followed by a COMMIT to end all <strong>SQL</strong><br />

connections be<strong>for</strong>e doing the CONNECT TO remote-tcp-system.<br />

Determining connection type<br />

When a remote connection is established it will use either an unprotected or<br />

protected network connection. With regards to committable updates, this <strong>SQL</strong><br />

connection may be read-only, updateable, or unknown whether it is updateable<br />

when the connection is established. A committable update is any insert, delete,<br />

update, or DDL statement that is run under commitment control. If the connection<br />

is read-only, changes using COMMIT(*NONE) can still be run. After a CONNECT<br />

or SET CONNECTION, <strong>SQL</strong>ERRD(4) of the <strong>SQL</strong>CA indicates the type of<br />

connection. <strong>SQL</strong>ERRD(4) will also indicate if the connection uses a unprotected or<br />

protected network connection. Specific values are:<br />

Chapter 17. Distributed Relational Database Function 269


1. Committable updates can be per<strong>for</strong>med on the connection. The connection is<br />

unprotected. This will occur when:<br />

v The connection is established using remote unit of work<br />

(RDBCNNMTH(*RUW)). This also includes local connections and application<br />

requester driver (ARD) connections using remote unit of work.<br />

v If the connection is established using distributed unit of work<br />

(RDBCNNMTH(*DUW)) then all the following are true:<br />

– The connection is not local.<br />

– The application server does not support distributed unit of work. For<br />

example, a <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> application server with a release of<br />

OS/<strong>400</strong> prior to Version 3 Release 1.<br />

– The commitment control level of the program issuing the connect is not<br />

*NONE.<br />

– Either no connections to other application servers (including local) exist<br />

that can per<strong>for</strong>m committable updates or all connections are read-only<br />

connections to application servers that do not support distributed unit of<br />

work.<br />

– There are no open updateable local files under commitment control <strong>for</strong> the<br />

commitment definition.<br />

– There are no open updateable DDM files that use a different connection<br />

under commitment control <strong>for</strong> the commitment definition.<br />

– There are no API commitment control resources <strong>for</strong> the commitment<br />

definition.<br />

– There are no protected connections registered <strong>for</strong> the commitment<br />

definition.<br />

If running with commitment control, <strong>SQL</strong> will register a one-phase<br />

updateable DRDA resource <strong>for</strong> remote connections or a two-phase<br />

updateable DRDA resource <strong>for</strong> local and ARD connections.<br />

2. No committable updates can be per<strong>for</strong>med on the connection. The connection is<br />

read-only. The network connection is unprotected.<br />

This will never occur <strong>for</strong> applications compiled with remote unit of work<br />

connection management (*RUW).<br />

For distributed unit of work applications, this will occur only when the<br />

following are true when the connection is established:<br />

v The connection is not local.<br />

v The application server does not support distributed unit of work<br />

v At least one of the following is true:<br />

– The commitment control level of the program issuing the connect is<br />

*NONE.<br />

– Another connection exists to an application server that does not support<br />

distributed unit-of-work and that application server can per<strong>for</strong>m<br />

committable updates<br />

– Another connection exists to an application server that supports<br />

distributed unit-of-work (including local).<br />

– There are open updateable local files under commitment control <strong>for</strong> the<br />

commitment definition.<br />

– There are open updateable DDM files that use a different connection<br />

under commitment control <strong>for</strong> the commitment definition.<br />

270 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


– There are no one-phase API commitment control resources <strong>for</strong> the<br />

commitment definition.<br />

– There are protected connections registered <strong>for</strong> the commitment definition.<br />

If running with commitment control, <strong>SQL</strong> will register a one-phase read-only<br />

resource.<br />

3. It is unknown if committable updates can be per<strong>for</strong>med. The connection is<br />

protected.<br />

This will never occur <strong>for</strong> applications compiled with remote unit of work<br />

connection management (*RUW).<br />

For distributed unit of work applications, this will occur when all of the<br />

following are true when the connection is established:<br />

v The connection is not local.<br />

v The commitment control level of the program issuing the connect is not<br />

*NONE.<br />

v The application server supports both distributed unit of work and two-phase<br />

commit protocol (protected connections).<br />

If running with commitment control, <strong>SQL</strong> will register a two-phase<br />

undetermined resource.<br />

4. It is unknown if committable updates can be per<strong>for</strong>med. The connection is not<br />

protected.<br />

This will never occur <strong>for</strong> applications compiled with remote unit of work<br />

connection management (*RUW).<br />

For distributed unit of work, this will occur only when all of the following are<br />

true when the connection is established:<br />

v The connection is not local.<br />

v The application server supports distributed unit of work<br />

v Either the application server does not support two-phase commit protocols<br />

(protected connections) or the commitment control level of the program<br />

issuing the connect is *NONE.<br />

If running with commitment control, <strong>SQL</strong> will register a one-phase DRDA<br />

undetermined resource.<br />

5. It is unknown if committable updates can be per<strong>for</strong>med and the connection is a<br />

local connection using distributed unit of work or an ARD connection using<br />

distributed unit of work.<br />

If running with commitment control, <strong>SQL</strong> will register a two-phase DRDA<br />

undetermined resource.<br />

For more in<strong>for</strong>mation on two-phase and one-phase resources, see the Backup and<br />

Recovery book.<br />

The following table summarizes the type of connection that will result <strong>for</strong> remote<br />

distributed unit of work connections. <strong>SQL</strong>ERRD(4) is set on successful CONNECT<br />

and SET CONNECTION statements.<br />

Chapter 17. Distributed Relational Database Function 271


Table 28. Summary of Connection Type<br />

Connect under<br />

Commitment<br />

Control<br />

Application<br />

Server Supports<br />

Two-phase<br />

Commit<br />

Application<br />

Server Supports<br />

Distributed Unit<br />

of Work<br />

Other<br />

Updateable<br />

One-phase<br />

Resource<br />

Registered <strong>SQL</strong>ERRD(4)<br />

No No No No 2<br />

No No No Yes 2<br />

No No Yes No 4<br />

No No Yes Yes 4<br />

No Yes No No 2<br />

No Yes No Yes 2<br />

No Yes Yes No 4<br />

No Yes Yes Yes 4<br />

Yes No No No 1<br />

Yes No No Yes 2<br />

Yes No Yes No 4<br />

Yes No Yes Yes 4<br />

Yes Yes No No N/A *<br />

Yes Yes No Yes N/A *<br />

Yes Yes Yes No 3<br />

Yes Yes Yes Yes 3<br />

*DRDA does not allow protected connections to be used to application servers which only<br />

support remote unit of work (DRDA1). This includes all <strong>DB2</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> TCP/IP<br />

connections.<br />

Connect and commitment control restrictions<br />

There are some restrictions on when you can connect using commitment control.<br />

These restrictions also apply to attempting to run statements using commitment<br />

control but the connection was established using COMMIT(*NONE).<br />

If a two-phase undetermined or updateable resource is registered or a one-phase<br />

updateable resource is registered, another one-phase updateable resource cannot<br />

not be registered.<br />

Furthermore, when protected connections are inactive and the DDMCNV job<br />

attribute is *KEEP, these unused DDM connections will also cause the CONNECT<br />

statements in programs compiled with RUW connection management to fail.<br />

If running with RUW connection management and using the job-level commitment<br />

definition, then there are some restrictions.<br />

v If the job-level commitment definition is used by more than one activation<br />

group, all RUW connections must be to the local relational database.<br />

v If the connection is remote, only one activation group may use the job-level<br />

commitment definition <strong>for</strong> RUW connections.<br />

272 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


Determining connection status<br />

The CONNECT statement without parameters can be used to determine if the<br />

current connection is updateable or read-only <strong>for</strong> the current unit of work. A value<br />

of 1 or 2 will be returned in <strong>SQL</strong>ERRD(3). The value in <strong>SQL</strong>ERRD(3) is determined<br />

as follows:<br />

1. Committable updates can be per<strong>for</strong>med on the connection <strong>for</strong> the unit of work.<br />

This will occur when one of the following is true:<br />

v <strong>SQL</strong>ERRD(4) has a value of 1.<br />

v All of the following are true:<br />

– <strong>SQL</strong>ERRD(4) has a value of 3 or 5.<br />

– No connection exists to an application server that does not support<br />

distributed unit of work which can per<strong>for</strong>m committable updates.<br />

– One of the following is true:<br />

- The first committable update is per<strong>for</strong>med on a connection that uses a<br />

protected connection, is per<strong>for</strong>med on the local database, or is<br />

per<strong>for</strong>med on a connection to an ARD program.<br />

- There there are open updateable local files under commitment control.<br />

- There are open updateable DDM files that use protected connections.<br />

- There are two-phase API commitment control resources.<br />

- No committable updates have been made.<br />

v All of the following are true:<br />

– <strong>SQL</strong>ERRD(4) has a value of 4<br />

– No other connections exist to an application server that does not support<br />

distributed unit of work which can per<strong>for</strong>m committable updates.<br />

– The first committable update is per<strong>for</strong>med on this connection or no<br />

committable updates have been made.<br />

– There are no open updateable DDM files that use protected connections.<br />

– There are no open updateable local files under commitment control.<br />

– There are no two-phase API commitment control resources.<br />

2. No committable updates can be per<strong>for</strong>med on the connection <strong>for</strong> this unit of<br />

work.<br />

This will occur when one of the following is true:<br />

v <strong>SQL</strong>ERRD(4) has a value of 2.<br />

v <strong>SQL</strong>ERRD(4) has a value of 3 or 5 and one of the following is true:<br />

– A connection exists to an updateable application server that only supports<br />

remote unit of work.<br />

– The first committable update is per<strong>for</strong>med on a connection that uses an<br />

unprotected connection.<br />

v <strong>SQL</strong>ERRD(4) has a value of 4 and one of the following is true:<br />

– A connection exists to an updateable application server that only supports<br />

remote unit of work.<br />

– The first committable update was not per<strong>for</strong>med on this connection.<br />

– There are open updateable DDM files that use protected connections.<br />

– There are open updateable local files under commitment control.<br />

– There are two-phase API commitment control resources.<br />

Chapter 17. Distributed Relational Database Function 273


This following table summarizes how <strong>SQL</strong>ERRD(3) is determined based on the<br />

<strong>SQL</strong>ERRD(4) value, if there is an updateable connection to an application server<br />

that only supports remote unit of work, and where the first committable update<br />

occurred.<br />

Table 29. Summary of Determining <strong>SQL</strong>ERRD(3) Values<br />

Connection Exists to<br />

Updateable Remote Where First<br />

Unit of Work Committable Update<br />

<strong>SQL</strong>ERRD(4) Application Server Occurred * <strong>SQL</strong>ERRD(3)<br />

1 -- -- 1<br />

2 -- -- 2<br />

3 Yes -- 2<br />

3 No no updates 1<br />

3 No one-phase 2<br />

3 No this connection 1<br />

3 No two-phase 1<br />

4 Yes -- 2<br />

4 No no updates 1<br />

4 No one-phase 2<br />

4 No this connection 1<br />

4 No two-phase 2<br />

5 Yes -- 2<br />

5 No no updates 1<br />

5 No one-phase 2<br />

5 No this connection 1<br />

5 No two-phase 1<br />

* The terms in this column are defined as:<br />

v No updates indicates no committable updates have been per<strong>for</strong>med, no DDM files open <strong>for</strong><br />

update using a protected connection, no local files are open <strong>for</strong> update, and no<br />

commitment control APIs are registered.<br />

v One-phase indicates the first committable update was per<strong>for</strong>med using an unprotected<br />

connection or DDM files are open <strong>for</strong> update using unprotected connections.<br />

v Two-phase indicates a committable update was per<strong>for</strong>med on a two-phase<br />

distributed-unit-of-work application server, DDM files are open <strong>for</strong> update using a<br />

protected connection, commitment control APIs are registered, or local files are open <strong>for</strong><br />

update under commitment control.<br />

When the value of <strong>SQL</strong>ERRD(4) is 3, 4, or 5 (due to an ARD program) and the<br />

value of <strong>SQL</strong>ERRD(3) is 2, if an attempt is made to per<strong>for</strong>m a committable update<br />

over the connection, the unit of work will be placed in a rollback required state. If<br />

an unit of work is in a rollback required state, the only statement allowed is a<br />

ROLLBACK statement; all other statements will result in <strong>SQL</strong>CODE -918.<br />

Distributed unit of work connection considerations<br />

When connecting in a distributed unit of work application, there are many<br />

considerations. This section lists some design considerations.<br />

v If the unit of work will per<strong>for</strong>m updates at more than one application server and<br />

commitment control will be used, all connections over which updates will be<br />

274 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


done should be made using commitment control. If the connections are done not<br />

using commitment control and later committable updates are per<strong>for</strong>med,<br />

read-only connections <strong>for</strong> the unit of work are likely to result.<br />

v Other non-<strong>SQL</strong> commit resources, such as local files, DDM files, and<br />

commitment control API resources, will affect the updateable and read-only<br />

status of a connection.<br />

v If connecting using commitment control to an application server that does not<br />

support distributed unit of work (<strong>for</strong> example, a V4R2 <strong>AS</strong>/<strong>400</strong> using TCP/IP),<br />

that connection will be either updateable or read-only. If the connection is<br />

updateable it is the only updateable connection.<br />

Ending connections<br />

Because remote connections use resources, connections that are no longer going to<br />

be used should be ended as soon as possible. Connections can be ended implicitly<br />

or explicitly. For a description of when connections are implicitly ended see<br />

“Implicit connection management <strong>for</strong> the default activation group” on page 267<br />

and “Implicit connection management <strong>for</strong> nondefault activation groups” on<br />

page 268. Connections can be explicitly ended by either the DISCONNECT<br />

statement or the RELE<strong>AS</strong>E statement followed by a successful COMMIT. The<br />

DISCONNECT statement can only be used with connections that use unprotected<br />

connections or with local connections. The DISCONNECT statement will end the<br />

connection when the statement is run. The RELE<strong>AS</strong>E statement can be used with<br />

either protected or unprotected connections. When the RELE<strong>AS</strong>E statement is run,<br />

the connection is not ended but instead placed into the released state. A connection<br />

that is in the release stated can still be used. The connection is not ended until a<br />

successful COMMIT is run. A ROLLBACK or an unsuccessful COMMIT will not<br />

end a connection in the released state.<br />

When a remote <strong>SQL</strong> connection is established, a DDM network connection (APPC<br />

conversation or TCP/IP connection) is used. When the <strong>SQL</strong> connection is ended,<br />

the network connection may either be placed in the unused state or dropped.<br />

Whether a network connection is dropped or placed in the unused state depends<br />

on the DDMCNV job attribute. If the job attribute value is *KEEP and the<br />

connection is to another <strong>AS</strong>/<strong>400</strong>, the connection becomes unused. If the job<br />

attribute value is *DROP and the connection is to another <strong>AS</strong>/<strong>400</strong>, the connection<br />

is dropped. If the connection is to a non-<strong>AS</strong>/<strong>400</strong>, the connection is always<br />

dropped. *DROP is desirable in the following situations:<br />

v When the cost of maintaining the unused connection is high and the connection<br />

will not be used relatively soon.<br />

v When running with a mixture of programs, some compiled with RUW<br />

connection management and some programs compiled with DUW connection<br />

management. Attempts to run programs compiled with RUW connection<br />

management to remote locations will fail when protected connections exist.<br />

v When running with protected connections using either DDM or DRDA.<br />

Additional overhead is incurred on commits and rollbacks <strong>for</strong> unused protected<br />

connections.<br />

The Reclaim DDM connections (RCLDDMCNV) command may be used to end all<br />

unused connections.<br />

Chapter 17. Distributed Relational Database Function 275


Distributed unit of work<br />

Distributed unit of work (DUW) allows access to multiple application servers<br />

within the same unit of work. Each <strong>SQL</strong> statement can access only one application<br />

server. Using distributed unit of work allows changes at multiple applications<br />

servers to be committed or rolled back within a single unit of work.<br />

Managing distributed unit of work connections<br />

The CONNECT, SET CONNECTION, DISCONNECT, and RELE<strong>AS</strong>E statements are<br />

used to manage connections in the DUW environment. A distributed unit of work<br />

CONNECT is run when the program is precompiled using RDBCNNMTH(*DUW),<br />

which is the default. This <strong>for</strong>m of the CONNECT statement does not disconnect<br />

existing connections but instead places the previous connection in the dormant<br />

state. The relational database specified on the CONNECT statement becomes the<br />

current connection. The CONNECT statement can only be used to start new<br />

connections; if you want to switch between existing connections, the SET<br />

CONNECTION statement must be used. Because connections use system resources,<br />

connections should be ended when they are no longer needed. The RELE<strong>AS</strong>E or<br />

DISCONNECT statement can be used to end connections. The RELE<strong>AS</strong>E statement<br />

must be followed by a successful commit in order <strong>for</strong> the connections to end.<br />

The following is an example of aCprogram running in a DUW environment that<br />

uses commitment control.<br />

....<br />

EXEC <strong>SQL</strong> WHENEVER <strong>SQL</strong>ERROR GO TO done;<br />

EXEC <strong>SQL</strong> WHENEVER NOT FOUND GO TO done;<br />

....<br />

EXEC <strong>SQL</strong><br />

DECLARE C1 CURSOR WITH HOLD FOR<br />

SELECT PARTNO, PRICE<br />

FROM PARTS<br />

WHERE SITES_UPDATED = 'N'<br />

FOR UPDATE OF SITES_UPDATED;<br />

/* Connect to the systems */<br />

EXEC <strong>SQL</strong> CONNECT TO LOCALSYS;<br />

EXEC <strong>SQL</strong> CONNECT TO SYSB;<br />

EXEC <strong>SQL</strong> CONNECT TO SYSC;<br />

/* Make the local system the current connection */<br />

EXEC <strong>SQL</strong> SET CONNECTION LOCALSYS;<br />

/* Open the cursor */<br />

EXEC <strong>SQL</strong> OPEN C1;<br />

Figure 13. Example of Distributed Unit of Work Program (Part 1 of 4)<br />

276 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


while (<strong>SQL</strong>CODE==0)<br />

{<br />

/* Fetch the first row */<br />

EXEC <strong>SQL</strong> FETCH C1 INTO :partnumber,:price;<br />

/* Update the row which indicates that the updates have been<br />

propagated to the other sites */<br />

EXEC <strong>SQL</strong> UPDATE PARTS SET SITES_UPDATED='Y'<br />

WHERE CURRENT OF C1;<br />

/* Check if the part data is on SYSB */<br />

if ((partnumber > 10) && (partnumber < 100))<br />

{<br />

/* Make SYSB the current connection and update the price */<br />

EXEC <strong>SQL</strong> SET CONNECTION SYSB;<br />

EXEC <strong>SQL</strong> UPDATE PARTS<br />

SET PRICE=:price<br />

WHERE PARTNO=:partnumber;<br />

}<br />

Figure 13. Example of Distributed Unit of Work Program (Part 2 of 4)<br />

/* Check if the part data is on SYSC */<br />

if ((partnumber > 50) && (partnumber < 200))<br />

{<br />

/* Make SYSC the current connection and update the price */<br />

EXEC <strong>SQL</strong> SET CONNECTION SYSC;<br />

EXEC <strong>SQL</strong> UPDATE PARTS<br />

SET PRICE=:price<br />

WHERE PARTNO=:partnumber;<br />

}<br />

/* Commit the changes made at all 3 sites */<br />

EXEC <strong>SQL</strong> COMMIT;<br />

/* Set the current connection to local so the next row<br />

can be fetched */<br />

EXEC <strong>SQL</strong> SET CONNECTION LOCALSYS;<br />

}<br />

done:<br />

Figure 13. Example of Distributed Unit of Work Program (Part 3 of 4)<br />

EXEC <strong>SQL</strong> WHENEVER <strong>SQL</strong>ERROR CONTINUE;<br />

/* Release the connections that are no longer being used */<br />

EXEC <strong>SQL</strong> RELE<strong>AS</strong>E SYSB;<br />

EXEC <strong>SQL</strong> RELE<strong>AS</strong>E SYSC;<br />

/* Close the cursor */<br />

EXEC <strong>SQL</strong> CLOSE C1;<br />

/* Do another commit which will end the released connections.<br />

The local connection is still active because it was not<br />

released. */<br />

EXEC <strong>SQL</strong> COMMIT;<br />

...<br />

Figure 13. Example of Distributed Unit of Work Program (Part 4 of 4)<br />

In this program, there are 3 application servers active: LOCALSYS which the local<br />

system, and 2 remote systems, SYSB and SYSC. SYSB and SYSC also support<br />

distributed unit of work and two-phase commit. Initially all connections are made<br />

active by using the CONNECT statement <strong>for</strong> each of the application servers<br />

involved in the transaction. When using DUW, a CONNECT statement does not<br />

disconnect the previous connection, but instead places the previous connection in<br />

Chapter 17. Distributed Relational Database Function 277


the dormant state. After all the application servers, have been connected, the local<br />

connection is made the current connection using the SET CONNECTION<br />

statement. The cursor is then opened and the first row of data fetched. It is then<br />

determined at which application servers the data needs to be updated. If SYSB<br />

needs to be updated, then SYSB is made the current connection using the SET<br />

CONNECTION statement and the update is run. The same is done <strong>for</strong> SYSC. The<br />

changes are then committed. Because two-phase commit is being used, it is<br />

guaranteed that the changes are committed at the local system and the two remote<br />

systems. Because the cursor was declared WITH HOLD, it remains open after the<br />

commit. The current connection is then changed to the local system so that the<br />

next row of data can be fetched. This set of fetches, updates, and commits is<br />

repeated until all the data has been processed. After all the data has been fetched,<br />

the connections <strong>for</strong> both remote systems are released. They can not be<br />

disconnected because they use protected connections. After the connections are<br />

released, a commit is issued to end the connections. The local system is still<br />

connected and continues processing.<br />

Checking connection status<br />

If running in an environment where it is possible to have read-only connections,<br />

the status of the connection should be checked be<strong>for</strong>e doing committable updates.<br />

This will prevent the unit of work from entering the rollback required state. The<br />

following COBOL example shows how to check the connection status.<br />

...<br />

EXEC <strong>SQL</strong><br />

SET CONNECTION SYS5<br />

END-EXEC.<br />

...<br />

* Check if the connection is updateable.<br />

EXEC <strong>SQL</strong> CONNECT END-EXEC.<br />

* If connection is updateable, update sales in<strong>for</strong>mation otherwise<br />

* in<strong>for</strong>m the user.<br />

IF <strong>SQL</strong>ERRD(3) = 1 THEN<br />

EXEC <strong>SQL</strong><br />

INSERT INTO SALES_TABLE<br />

VALUES(:SALES-DATA)<br />

END-EXEC<br />

ELSE<br />

DISPLAY 'Unable to update sales in<strong>for</strong>mation at this time'.<br />

...<br />

Figure 14. Example of Checking Connection Status<br />

Cursors and prepared statements<br />

Cursors and prepared statements are scoped to the compilation unit and also to<br />

the connection. Scoping to the compilation unit means that a program called from<br />

another separately compiled program cannot use a cursor or prepared statement<br />

that was opened or prepared by the calling program. Scoping to the connection<br />

means that each connection within a program can have its own separate instance<br />

of a cursor or prepared statement.<br />

The following distributed unit of work example shows how the same cursor name<br />

is opened in two different connections, resulting in two instances of cursor C1.<br />

278 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


Application requester driver programs<br />

Problem handling<br />

.....<br />

EXEC <strong>SQL</strong> DECLARE C1 CURSOR FOR<br />

SELECT * FROM CORPDATA.EMPLOYEE;<br />

/* Connect to local and open C1 */<br />

EXEC <strong>SQL</strong> CONNECT TO LOCALSYS;<br />

EXEC <strong>SQL</strong> OPEN C1;<br />

/* Connect to the remote system and open C1 */<br />

EXEC <strong>SQL</strong> CONNECT TO SYSA;<br />

EXEC <strong>SQL</strong> OPEN C1;<br />

/* Keep processing until done */<br />

while (NOT_DONE) {<br />

/* Fetch a row of data from the local system */<br />

EXEC <strong>SQL</strong> SET CONNECTION LOCALSYS;<br />

EXEC <strong>SQL</strong> FETCH C1 INTO :local_emp_struct;<br />

/* Fetch a row of data from the remote system */<br />

EXEC <strong>SQL</strong> SET CONNECTION SYSA;<br />

EXEC <strong>SQL</strong> FETCH C1 INTO :rmt_emp_struct;<br />

/* Process the data */<br />

.....<br />

}<br />

/* Close the cursor on the remote system */<br />

EXEC <strong>SQL</strong> CLOSE C1;<br />

/* Close the cursor on the local system */<br />

EXEC <strong>SQL</strong> SET CONNECTION LOCALSYS;<br />

EXEC <strong>SQL</strong> CLOSE C1;<br />

.....<br />

Figure 15. Example of Cursors in a DUW program<br />

To complement database access provided by products that implement DRDA, <strong>DB2</strong><br />

<strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> provides an interface <strong>for</strong> writing exit programs on a <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong><br />

<strong>AS</strong>/<strong>400</strong> application requester to process <strong>SQL</strong> requests. Such an exit program is<br />

called an application requester driver. The <strong>AS</strong>/<strong>400</strong> calls the ARD program during<br />

the following operations:<br />

v During package creation per<strong>for</strong>med using the CRT<strong>SQL</strong>PKG or CRT<strong>SQL</strong>xxx<br />

commands, when the relational database (RDB) parameter matches the RDB<br />

name corresponding to the ARD program.<br />

v Processing of <strong>SQL</strong> statements when the current connection is to an RDB name<br />

corresponding to the ARD program.<br />

These calls allow the ARD program to pass the <strong>SQL</strong> statements and in<strong>for</strong>mation<br />

about the statements to a remote relational database and return results back to the<br />

system. The system then returns the results to the application or the user. Access to<br />

relational databases accessed by ARD programs appears like access to DRDA<br />

application servers in the unlike environment.<br />

For more in<strong>for</strong>mation about application requester driver programs, see the OS/<strong>400</strong><br />

File APIs.<br />

The primary strategy <strong>for</strong> capturing and reporting error in<strong>for</strong>mation <strong>for</strong> the <strong>AS</strong>/<strong>400</strong><br />

distributed database function is called first failure data capture (FFDC). The<br />

purpose of FFDC support is to provide accurate in<strong>for</strong>mation on errors detected in<br />

the DDM components of the OS/<strong>400</strong> system from which an APAR 9 can be created.<br />

Chapter 17. Distributed Relational Database Function 279


9. Authorized Program Analysis Report (APAR).<br />

By means of this function, key structures and the DDM data stream are<br />

automatically dumped to a spool file. The first 1024 bytes of the error in<strong>for</strong>mation<br />

are also logged in the system error log. This automatic dumping of error<br />

in<strong>for</strong>mation on the first occurrence of an error means that the failure should not<br />

have to be recreated to be reported by the customer. FFDC is active in both the<br />

application requester and application server functions of the OS/<strong>400</strong> DDM<br />

component. However, <strong>for</strong> the FFDC data to be logged, the system value<br />

QSFWERRLOG must be set to *LOG.<br />

Note: Not all negative <strong>SQL</strong>CODEs are dumped; only those that can be used to<br />

produce an APAR are dumped. For more in<strong>for</strong>mation on handling problems<br />

on distributed relational database operations, see the Distributed Database<br />

Problem Determination Guide<br />

When an <strong>SQL</strong> error is detected, an <strong>SQL</strong>CODE with a corresponding <strong>SQL</strong>STATE is<br />

returned in the <strong>SQL</strong>CA. For more in<strong>for</strong>mation on these codes, see Appendix B.<br />

<strong>SQL</strong>CODEs and <strong>SQL</strong>STATEs.<br />

280 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


Appendix A. <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> Sample Tables<br />

This appendix contains the sample tables referred to and used in this guide and<br />

the <strong>SQL</strong> Reference book. Along with the tables are the <strong>SQL</strong> statements <strong>for</strong> creating<br />

the tables. For detailed in<strong>for</strong>mation on creating tables, see “Creating and using a<br />

table” on page 14.<br />

As a group, the EMPLOYEE, DEPARTMENT, PROJECT, and EMP_ACT tables<br />

include in<strong>for</strong>mation that describes employees, departments, projects, and activities.<br />

This in<strong>for</strong>mation makes up a sample application demonstrating some of the<br />

features of the <strong>DB2</strong> <strong>UDB</strong> Query Manager and <strong>SQL</strong> Development Kit licensed<br />

program. The tables are in a collection named CORPDATA (<strong>for</strong> corporate data).<br />

The tables are:<br />

v Department table (CORPDATA.DEPARTMENT)<br />

v Employee table (CORPDATA.EMPLOYEE)<br />

v Employee to project activity table (CORPDATA.EMP_ACT)<br />

v Project table (CORPDATA.PROJECT)<br />

v Class Schedule table (CL_SCHED)<br />

v In Tray table (IN_TRAY)<br />

Notes:<br />

1. In these sample tables, a question mark (?) indicates a null value.<br />

2. The IN_TRAY and CL_SCHED tables are used to illustrate examples that<br />

include dates and times given in the <strong>SQL</strong> Reference book. They are not related<br />

to the examples in the CORPDATA collection.<br />

Department Table (CORPDATA.DEPARTMENT)<br />

The department table describes each department in the enterprise and identifies its<br />

manager and the department it reports to. The department table is created with the<br />

following CREATE TABLE statement:<br />

CREATE TABLE CORPDATA.DEPARTMENT<br />

(DEPTNO CHAR(3) NOT NULL,<br />

DEPTNAME VARCHAR(29) NOT NULL,<br />

MGRNO CHAR(6) ,<br />

ADMRDEPT CHAR(3) NOT NULL )<br />

The following table shows the content of the columns:<br />

Table 30. Columns of the Department Table<br />

Column Name Description<br />

DEPTNO Department number or ID.<br />

DEPTNAME A name describing the general activities of the department.<br />

MGRNO Employee number (EMPNO) of the department manager.<br />

ADMRDEPT The department (DEPTNO) to which this department reports; the<br />

department at the highest level reports to itself.<br />

© Copyright IBM Corp. 2000 281


DEPARTMENT<br />

DEPTNO DEPTNAME MGRNO ADMRDEPT<br />

A00 SPIFFY COMPUTER SERVICE<br />

DIV.<br />

000010 A00<br />

B01 PLANNING 000020 A00<br />

C01 INFORMATION CENTER 000030 A00<br />

D01 DEVELOPMENT CENTER ? A00<br />

D11 MANUFACTURING SYSTEMS 000060 D01<br />

D21 ADMINISTRATION SYSTEMS 000070 D01<br />

E01 SUPPORT SERVICES 000050 A00<br />

E11 OPERATIONS 000090 E01<br />

E21 SOFTWARE SUPPORT 000100 E01<br />

Employee Table (CORPDATA.EMPLOYEE)<br />

The employee table identifies all employees by an employee number and lists basic<br />

personnel in<strong>for</strong>mation. The employee table is created with the following CREATE<br />

TABLE statement:<br />

CREATE TABLE CORPDATA.EMPLOYEE<br />

(EMPNO CHAR(6) NOT NULL,<br />

FIRSTNME VARCHAR(12) NOT NULL,<br />

MIDINIT CHAR(1) NOT NULL,<br />

L<strong>AS</strong>TNAME VARCHAR(15) NOT NULL,<br />

WORKDEPT CHAR(3) ,<br />

PHONENO CHAR(4) ,<br />

HIREDATE DATE ,<br />

JOB CHAR(8) ,<br />

EDLEVEL SMALLINT NOT NULL,<br />

SEX CHAR(1) ,<br />

BIRTHDATE DATE ,<br />

SALARY DECIMAL(9,2) ,<br />

BONUS DECIMAL(9,2) ,<br />

COMM DECIMAL(9,2) )<br />

The table below shows the content of the columns.<br />

Column Name Description<br />

EMPNO Employee number<br />

FIRSTNME First name of employee<br />

MIDINIT Middle initial of employee<br />

L<strong>AS</strong>TNAME Last name of employee<br />

WORKDEPT ID of department in which the employee works<br />

PHONENO Employee telephone number<br />

HIREDATE Date of hire<br />

JOB Job held by the employee<br />

EDLEVEL Number of years of <strong>for</strong>mal education<br />

SEX Sex of the employee (M or F)<br />

BIRTHDATE Date of birth<br />

SALARY Yearly salary in dollars<br />

282 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


Column Name Description<br />

BONUS Yearly bonus in dollars<br />

COMM Yearly commission in dollars<br />

FIRST MID WORK PHONE ED SAL-<br />

EMP NO NAME INIT L<strong>AS</strong>TNAME DEPT NO HIRE DATE JOB LEVEL SEX BIRTH DATE ARY BONUS COMM<br />

000010 CHRISTINE I HA<strong>AS</strong> A00 3978 1965-01-01 PRES 18 F 1933-08-24 52750 1000 4220<br />

000020 MICHAEL L THOMPSON B01 3476 1973-10-10 MANAGER 18 M 1948-02-02 41250 800 3300<br />

000030 SALLY A KWAN C01 4738 1975-04-05 MANAGER 20 F 1941-05-11 38250 800 3060<br />

000050 JOHN B GEYER E01 6789 1949-08-17 MANAGER 16 M 1925-09-15 40175 800 3214<br />

000060 IRVING F STERN D11 6423 1973-09-14 MANAGER 16 M 1945-07-07 32250 500 2580<br />

000070 EVA D PUL<strong>AS</strong>KI D21 7831 1980-09-30 MANAGER 16 F 1953-05-26 36170 700 2893<br />

000090 EILEEN W HENDERSON E11 5498 1970-08-15 MANAGER 16 F 1941-05-15 29750 600 2380<br />

000100 THEODORE Q SPENSER E21 0972 1980-06-19 MANAGER 14 M 1956-12-18 26150 500 2092<br />

000110 VINCENZO G LUCCHESSI A00 3490 1958-05-16 SALESREP 19 M 1929-11-05 46500 900 3720<br />

000120 SEAN O'CONNELL A00 2167 1963-12-05 CLERK 14 M 1942-10-18 29250 600 2340<br />

000130 DOLORES M QUINTANA C01 4578 1971-07-28 ANALYST 16 F 1925-09-15 23800 500 1904<br />

000140 HEATHER A NICHOLLS C01 1793 1976-12-15 ANALYST 18 F 1946-01-19 28420 600 2274<br />

000150 BRUCE ADAMSON D11 4510 1972-02-12 DESIGNER 16 M 1947-05-17 25280 500 2022<br />

000160 ELIZABETH R PIANKA D11 3782 1977-10-11 DESIGNER 17 F 1955-04-12 22250 <strong>400</strong> 1780<br />

000170 M<strong>AS</strong>ATOSHI J YOSHIMURA D11 2890 1978-09-15 DESIGNER 16 M 1951-01-05 24680 500 1974<br />

000180 MARILYN S SCOUTTEN D11 1682 1973-07-07 DESIGNER 17 F 1949-02-21 21340 500 1707<br />

000190 JAMES H WALKER D11 2986 1974-07-26 DESIGNER 16 M 1952-06-25 20450 <strong>400</strong> 1636<br />

000200 DAVID BROWN D11 4501 1966-03-03 DESIGNER 16 M 1941-05-29 27740 600 2217<br />

000210 WILLIAM T JONES D11 0942 1979-04-11 DESIGNER 17 M 1953-02-23 18270 <strong>400</strong> 1462<br />

000220 JENNIFER K LUTZ D11 0672 1968-08-29 DESIGNER 18 F 1948-03-19 29840 600 2387<br />

000230 JAMES J JEFFERSON D21 2094 1966-11-21 CLERK 14 M 1935-05-30 22180 <strong>400</strong> 1774<br />

000240 SALVATORE M MARINO D21 3780 1979-12-05 CLERK 17 M 1954-03-31 28760 600 2301<br />

000250 DANIEL S SMITH D21 0961 1969-10-30 CLERK 15 M 1939-11-12 19180 <strong>400</strong> 1534<br />

000260 SYBIL P JOHNSON D21 8953 1975-09-11 CLERK 16 F 1936-10-05 17250 300 1380<br />

000270 MARIA L PEREZ D21 9001 1980-09-30 CLERK 15 F 1953-05-26 27380 500 2190<br />

000280 ETHEL R SCHNEIDER E11 8997 1967-03-24 OPERATOR 17 F 1936-03-28 26250 500 2100<br />

000290 JOHN R PARKER E11 4502 1980-05-30 OPERATOR 12 M 1946-07-09 15340 300 1227<br />

000300 PHILIP X SMITH E11 2095 1972-06-19 OPERATOR 14 M 1936-10-27 17750 <strong>400</strong> 1420<br />

000310 MAUDE F SETRIGHT E11 3332 1964-09-12 OPERATOR 12 F 1931-04-21 15900 300 1272<br />

000320 RAMLAL V MEHTA E21 9990 1965-07-07 FILEREP 16 M 1932-08-11 19950 <strong>400</strong> 1596<br />

000330 WING LEE E21 2103 1976-02-23 FILEREP 14 M 1941-07-18 25370 500 2030<br />

000340 J<strong>AS</strong>ON R GOUNOT E21 5698 1947-05-05 FILEREP 16 M 1926-05-17 23840 500 1907<br />

Employee to Project Activity Table (CORPDATA.EMP_ACT)<br />

The employee to project activity table identifies the employee who per<strong>for</strong>ms each<br />

activity listed <strong>for</strong> each project. The employee’s level of involvement (full-time or<br />

part-time) and schedule <strong>for</strong> activity are also in the table. The employee to project<br />

activity table is created with the following CREATE TABLE statement:<br />

CREATE TABLE CORPDATA.EMP_ACT<br />

(EMPNO CHAR(6) NOT NULL,<br />

PROJNO CHAR(6) NOT NULL,<br />

ACTNO SMALLINT NOT NULL,<br />

EMPTIME DECIMAL(5,2) ,<br />

EMSTDATE DATE ,<br />

EMENDATE DATE )<br />

The table below shows the content of the columns.<br />

Table 31. Columns of the Employee to Project Activity Table<br />

Column Name Description<br />

EMPNO Employee ID number<br />

PROJNO PROJNO of the project to which the employee is assigned<br />

ACTNO ID of an activity within a project to which an employee is<br />

assigned<br />

EMPTIME A proportion of the employee’s full time (between 0.00 and<br />

1.00) to be spent on the project from EMSTDATE to<br />

EMENDATE<br />

EMSTDATE Start date of the activity<br />

Appendix A. <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> Sample Tables 283


EMP_ACT<br />

Table 31. Columns of the Employee to Project Activity Table (continued)<br />

Column Name Description<br />

EMENDATE Completion date of the activity<br />

EMPNO PROJNO ACTNO EMPTIME EMSTDATE EMENDATE<br />

000010 AD3100 10 .50 1982-01-01 1982-07-01<br />

000070 AD3110 10 1.00 1982-01-01 1983-02-01<br />

000230 AD3111 60 1.00 1982-01-01 1982-03-15<br />

000230 AD3111 60 .50 1982-03-15 1982-04-15<br />

000230 AD3111 70 .50 1982-03-15 1982-10-15<br />

000230 AD3111 80 .50 1982-04-15 1982-10-15<br />

000230 AD3111 180 1.00 1982-10-15 1983-01-01<br />

000240 AD3111 70 1.00 1982-02-15 1982-09-15<br />

000240 AD3111 80 1.00 1982-09-15 1983-01-01<br />

000250 AD3112 60 1.00 1982-01-01 1982-02-01<br />

000250 AD3112 60 .50 1982-02-01 1982-03-15<br />

000250 AD3112 60 .50 1982-12-01 1983-01-01<br />

000250 AD3112 60 1.00 1983-01-01 1983-02-01<br />

000250 AD3112 70 .50 1982-02-01 1982-03-15<br />

000250 AD3112 70 1.00 1982-03-15 1982-08-15<br />

000250 AD3112 70 .25 1982-08-15 1982-10-15<br />

000250 AD3112 80 .25 1982-08-15 1982-10-15<br />

000250 AD3112 80 .50 1982-10-15 1982-12-01<br />

000250 AD3112 180 .50 1982-08-15 1983-01-01<br />

000260 AD3113 70 .50 1982-06-15 1982-07-01<br />

000260 AD3113 70 1.00 1982-07-01 1983-02-01<br />

000260 AD3113 80 1.00 1982-01-01 1982-03-01<br />

000260 AD3113 80 .50 1982-03-01 1982-04-15<br />

000260 AD3113 180 .50 1982-03-01 1982-04-15<br />

000260 AD3113 180 1.00 1982-04-15 1982-06-01<br />

000260 AD3113 180 .50 1982-06-01 1982-07-01<br />

000270 AD3113 60 .50 1982-03-01 1982-04-01<br />

000270 AD3113 60 1.00 1982-04-01 1982-09-01<br />

000270 AD3113 60 .25 1982-09-01 1982-10-15<br />

000270 AD3113 70 .75 1982-09-01 1982-10-15<br />

000270 AD3113 70 1.00 1982-10-15 1983-02-01<br />

000270 AD3113 80 1.00 1982-01-01 1982-03-01<br />

000270 AD3113 80 .50 1982-03-01 1982-04-01<br />

000030 IF1000 10 .50 1982-06-01 1983-01-01<br />

000130 IF1000 90 1.00 1982-01-01 1982-10-01<br />

000130 IF1000 100 .50 1982-10-01 1983-01-01<br />

284 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


EMPNO PROJNO ACTNO EMPTIME EMSTDATE EMENDATE<br />

000140 IF1000 90 .50 1982-10-01 1983-01-01<br />

000030 IF2000 10 .50 1982-01-01 1983-01-01<br />

000140 IF2000 100 1.00 1982-01-01 1982-03-01<br />

000140 IF2000 100 .50 1982-03-01 1982-07-01<br />

000140 IF2000 110 .50 1982-03-01 1982-07-01<br />

000140 IF2000 110 .50 1982-10-01 1983-01-01<br />

000010 MA2100 10 .50 1982-01-01 1982-11-01<br />

000110 MA2100 20 1.00 1982-01-01 1982-03-01<br />

000010 MA2110 10 1.00 1982-01-01 1983-02-01<br />

000200 MA2111 50 1.00 1982-01-01 1982-06-15<br />

000200 MA2111 60 1.00 1982-06-15 1983-02-01<br />

000220 MA2111 40 1.00 1982-01-01 1983-02-01<br />

000150 MA2112 60 1.00 1982-01-01 1982-07-15<br />

000150 MA2112 180 1.00 1982-07-15 1983-02-01<br />

000170 MA2112 60 1.00 1982-01-01 1983-06-01<br />

000170 MA2112 70 1.00 1982-06-01 1983-02-01<br />

000190 MA2112 70 1.00 1982-02-01 1982-10-01<br />

000190 MA2112 80 1.00 1982-10-01 1983-10-01<br />

000160 MA2113 60 1.00 1982-07-15 1983-02-01<br />

000170 MA2113 80 1.00 1982-01-01 1983-02-01<br />

000180 MA2113 70 1.00 1982-04-01 1982-06-15<br />

000210 MA2113 80 .50 1982-10-01 1983-02-01<br />

000210 MA2113 180 .50 1982-10-01 1983-02-01<br />

000050 OP1000 10 .25 1982-01-01 1983-02-01<br />

000090 OP1010 10 1.00 1982-01-01 1983-02-01<br />

000280 OP1010 130 1.00 1982-01-01 1983-02-01<br />

000290 OP1010 130 1.00 1982-01-01 1983-02-01<br />

000300 OP1010 130 1.00 1982-01-01 1983-02-01<br />

000310 OP1010 130 1.00 1982-01-01 1983-02-01<br />

000050 OP2010 10 .75 1982-01-01 1983-02-01<br />

000100 OP2010 10 1.00 1982-01-01 1983-02-01<br />

000320 OP2011 140 .75 1982-01-01 1983-02-01<br />

000320 OP2011 150 .25 1982-01-01 1983-02-01<br />

000330 OP2012 140 .25 1982-01-01 1983-02-01<br />

000330 OP2012 160 .75 1982-01-01 1983-02-01<br />

000340 OP2013 140 .50 1982-01-01 1983-02-01<br />

000340 OP2013 170 .50 1982-01-01 1983-02-01<br />

000020 PL2100 30 1.00 1982-01-01 1982-09-15<br />

Appendix A. <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> Sample Tables 285


Project Table (CORPDATA.PROJECT)<br />

PROJECT<br />

The project table describes each project that the business is currently undertaking.<br />

Data contained in each row include the project number, name, person responsible,<br />

and schedule dates. The project table is created with the following CREATE TABLE<br />

statement:<br />

CREATE TABLE CORPDATA.PROJECT<br />

(PROJNO CHAR(6) NOT NULL,<br />

PROJNAME VARCHAR(24) NOT NULL,<br />

DEPTNO CHAR(3) NOT NULL,<br />

RESPEMP CHAR(6) NOT NULL,<br />

PRSTAFF DECIMAL(5,2) ,<br />

PRSTDATE DATE ,<br />

PRENDATE DATE ,<br />

MAJPROJ CHAR(6) )<br />

The table below shows the contents of the columns:<br />

Column Name Description<br />

PROJNO Project number<br />

PROJNAME Project name<br />

DEPTNO Department number of the department responsible <strong>for</strong> the<br />

project<br />

RESPEMP Employee number of the person responsible <strong>for</strong> the project<br />

PRSTAFF Estimated mean staffing<br />

PRSTDATE Estimated start date of the project<br />

PRENDATE Estimated end date of the project<br />

MAJPROJ Controlling project number <strong>for</strong> sub projects<br />

PROJNO PROJNAME DEPTNO RESPEMP PRSTAFF PRSTDATE PRENDATE MAJPROJ<br />

AD3100 ADMIN SERVICES D01 000010 6.5 1982-01-01 1983-02-01 ?<br />

AD3110 GENERAL<br />

ADMIN SYSTEMS<br />

D21 000070 6 1982-01-01 1983-02-01 AD3100<br />

AD3111 PAYROLL<br />

PROGRAMMING<br />

D21 000230 2 1982-01-01 1983-02-01 AD3110<br />

AD3112 PERSONNEL<br />

PROGRAMMING<br />

D21 000250 1 1982-01-01 1983-02-01 AD3110<br />

AD3113 ACCOUNT<br />

PROGRAMMING<br />

D21 000270 2 1982-01-01 1983-02-01 AD3110<br />

IF1000 QUERY SERVICES C01 000030 2 1982-01-01 1983-02-01 ?<br />

IF2000 USER<br />

EDUCATION<br />

C01 000030 1 1982-01-01 1983-02-01 ?<br />

MA2100 WELD LINE<br />

AUTOMATION<br />

D01 000010 12 1982-01-01 1983-02-01 ?<br />

MA2110 W L<br />

PROGRAMMING<br />

D11 000060 9 1982-01-01 1983-02-01 MA2100<br />

MA2111 W L PROGRAM<br />

DESIGN<br />

D11 000220 2 1982-01-01 1982-12-01 MA2110<br />

286 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


PROJNO PROJNAME DEPTNO RESPEMP PRSTAFF PRSTDATE PRENDATE MAJPROJ<br />

MA2112 W L ROBOT<br />

DESIGN<br />

D11 000150 3 1982-01-01 1982-12-01 MA2110<br />

MA2113 W L PROD CONT<br />

PROGS<br />

D11 000160 3 1982-02-15 1982-12-01 MA2110<br />

OP1000 OPERATION<br />

SUPPORT<br />

E01 000050 6 1982-01-01 1983-02-01 ?<br />

OP1010 OPERATION E11 000090 5 1982-01-01 1983-02-01 OP1000<br />

OP2000 GEN SYSTEMS<br />

SERVICES<br />

E01 000050 5 1982-01-01 1983-02-01 ?<br />

OP2010 SYSTEMS<br />

SUPPORT<br />

E21 000100 4 1982-01-01 1983-02-01 OP2000<br />

OP2011 SCP SYSTEMS<br />

SUPPORT<br />

E21 000320 1 1982-01-01 1983-02-01 OP2010<br />

OP2012 APPLICATIONS<br />

SUPPORT<br />

E21 000330 1 1982-01-01 1983-02-01 OP2010<br />

OP2013 DB/DC SUPPORT E21 000340 1 1982-01-01 1983-02-01 OP2010<br />

PL2100 WELD LINE<br />

PLANNING<br />

B01 000020 1 1982-01-01 1982-09-15 MA2100<br />

Class Schedule Table (CL_SCHED)<br />

In Tray Table (IN_TRAY)<br />

The class schedule table describes: each class, the start time <strong>for</strong> the class, the end<br />

time <strong>for</strong> the class, and the class code. The class schedule table is created with the<br />

following CREATE TABLE statement:<br />

CREATE TABLE CL_SCHED<br />

(CL<strong>AS</strong>S_CODE CHAR(7),<br />

DAY SMALLINT,<br />

STARTING TIME,<br />

ENDING TIME)<br />

The table below gives the contents of the columns.<br />

Column Name Description<br />

CL<strong>AS</strong>S_CODE Class code (room:teacher)<br />

DAY Day number of 4 day schedule<br />

STARTING Class start time<br />

ENDING Class end time<br />

Note: This table has no data.<br />

The in tray table describes an electronic in-basket containing: a timestamp from<br />

when the message was received, the user ID of the person sending the message,<br />

and the message itself. The in tray table is created with the following CREATE<br />

TABLE statement:<br />

Appendix A. <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> Sample Tables 287


CREATE TABLE IN_TRAY<br />

(RECEIVED TIMESTAMP,<br />

SOURCE CHAR(8),<br />

SUBJECT CHAR(64),<br />

NOTE_TEXT VARCHAR(3000))<br />

The table below gives the contents of the columns.<br />

Column Name Description<br />

RECEIVED Date and time received<br />

SOURCE User ID of person sending the note<br />

SUBJECT Brief description of the note<br />

NOTE_TEXT The note<br />

Note: This table has no data.<br />

288 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


Appendix B. <strong>SQL</strong>CODEs and <strong>SQL</strong>STATEs<br />

<strong>SQL</strong> returns error codes to the application program when an error occurs. This<br />

appendix lists <strong>SQL</strong>CODEs and their associated <strong>SQL</strong>STATEs. Detailed descriptions<br />

of all <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> messages, including <strong>SQL</strong>CODEs, are available on-line<br />

and can be displayed and printed from the Display Message Description display.<br />

You can access this display by using the CL command Display Message<br />

Description (DSPMSGD).<br />

<strong>SQL</strong>CODEs are returned in the <strong>SQL</strong>CA structure. <strong>SQL</strong>STATE is an additional<br />

return code that provides application programs with common return codes <strong>for</strong><br />

common error conditions found among the IBM relational database systems.<br />

<strong>SQL</strong>STATEs are particularly useful when handling errors in distributed <strong>SQL</strong><br />

applications.<br />

Every <strong>SQL</strong>CODE has a corresponding message in message file Q<strong>SQL</strong>MSG in<br />

library QSYS. The message ID <strong>for</strong> any <strong>SQL</strong>CODE is constructed by appending the<br />

absolute value (5 digits) of the <strong>SQL</strong>CODE to SQ and changing the third character<br />

to 'L' if the third character is a 0. For example, if the <strong>SQL</strong>CODE is 30070, the<br />

message ID is SQ30070.<br />

If <strong>SQL</strong> encounters an error while processing the statement, the first characters of<br />

the <strong>SQL</strong>STATE are not '00', '01' or '02', and the <strong>SQL</strong>CODE is a negative number. If<br />

<strong>SQL</strong> encounters a warning but valid condition while processing your statement,<br />

the <strong>SQL</strong>CODE is a positive number and bytes one and two of the <strong>SQL</strong>STATE are<br />

'01'. If your <strong>SQL</strong> statement is processed without encountering an error or warning<br />

condition, the <strong>SQL</strong>CODE returned is 0 and <strong>SQL</strong>STATE is '00000'.<br />

If you wish, you can quickly reference “Positive <strong>SQL</strong>CODEs” on page 291 or<br />

“Negative <strong>SQL</strong>CODEs” on page 293.<br />

When running in debug mode, <strong>SQL</strong> places a message corresponding to the<br />

<strong>SQL</strong>CODE in the job log <strong>for</strong> each <strong>SQL</strong> statement run. If you are not running in<br />

debug mode and get a negative <strong>SQL</strong>CODE, you will get a message in the job log<br />

also.<br />

An application can also send the <strong>SQL</strong> message corresponding to any <strong>SQL</strong>CODE to<br />

the job log by specifying the message ID and the replacement text on the CL<br />

commands Retrieve Message (RTVMSG), Send Program Message (SNDPGMMSG),<br />

and Send User Message (SNDUSRMSG).<br />

<strong>SQL</strong>STATE values consist of a two-character class code, followed by a<br />

three-character code. The class codes con<strong>for</strong>m to ISO/ANSI standards. The class<br />

codes are:<br />

v 00 Unqualified Successful Completion<br />

v 01 Warning<br />

v 02 No Data<br />

v 03 <strong>SQL</strong> Statement Not Yet Complete<br />

v 07 Dynamic <strong>SQL</strong> Error<br />

v 08 Connection Exception<br />

v 09 Triggered Action Exception<br />

© Copyright IBM Corp. 2000 289


v 0A Feature Not Supported<br />

v 09 Invalid Token<br />

v 20 Case Not Found <strong>for</strong> C<strong>AS</strong>E Statement<br />

v 21 Cardinality Violation<br />

v 22 Data Exception<br />

v 23 Constraint Violation<br />

v 24 Invalid Cursor State<br />

v 25 Invalid Transaction State<br />

v 26 Invalid <strong>SQL</strong> Statement Identifier<br />

v 27 Triggered Data Change Violation<br />

v 28 Invalid Authorization Specification<br />

v 2B Dependent Privilege Descriptors Still Exist<br />

v 2C Invalid Character Set Name<br />

v 2D Invalid Transaction Termination<br />

v 2E Invalid Connection Name<br />

v 2F <strong>SQL</strong> Function Exception<br />

v 33 Invalid <strong>SQL</strong> Descriptor Name<br />

v 34 Invalid Cursor Name<br />

v 35 Invalid Condition Number<br />

v 38 External Function Exception<br />

v 39 External Function Call Exception<br />

v 3C Ambiguous Cursor Name<br />

v 3D Invalid Catalog Name<br />

v 3F Invalid Collection (Schema) Name<br />

v 40 Transaction Rollback<br />

v 42 Syntax Error and Access Rule Violation<br />

v 44 WITH CHECK OPTION Violation<br />

v 51 Invalid Application State<br />

v 53 Invalid Operand or Inconsistent Specification<br />

v 54 <strong>SQL</strong> or Product Limit Exceeded<br />

v 55 Object Not in Prerequisite State<br />

v 56 Miscellaneous <strong>SQL</strong> or Product Error<br />

v 57 Resource Not Available or Operator Intervention<br />

v 58 System Error<br />

For a list of <strong>SQL</strong>STATEs that are used by the <strong>DB2</strong> family of products, see IBM <strong>SQL</strong><br />

Reference, Version 2, SC26-8416. Also available on CD-ROM as a part of the<br />

Transaction Processing Collection Kit CD-ROM, SK2T-0730-11.<br />

When an <strong>SQL</strong>STATE other than '00000' is returned from a non-<strong>DB2</strong> <strong>UDB</strong> <strong>for</strong><br />

<strong>AS</strong>/<strong>400</strong> application server, <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> attempts to map the <strong>SQL</strong>STATE<br />

to a <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong>CODE and message:<br />

v If the <strong>SQL</strong>STATE is not recognized by <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong>, the common<br />

message <strong>for</strong> the class is issued.<br />

290 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


v If the <strong>SQL</strong>STATE and <strong>SQL</strong>CODE correspond to a single <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong><br />

<strong>SQL</strong>CODE, <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> attempts to convert the tokens returned in<br />

<strong>SQL</strong>ERRM to the replacement data expected by the <strong>SQL</strong> message. If an error<br />

occurs while converting the tokens:<br />

– The <strong>SQL</strong>CA is not changed.<br />

– A common message <strong>for</strong> the class code of the <strong>SQL</strong>STATE is issued.<br />

<strong>SQL</strong>CODE and <strong>SQL</strong>STATE Descriptions<br />

N/A <strong>SQL</strong>CODE 0<br />

In the following brief descriptions of the <strong>SQL</strong>CODEs (and their associated<br />

<strong>SQL</strong>STATEs) message data fields are identified by an ampersand (&); and a<br />

number (<strong>for</strong> example, &1); The replacement text <strong>for</strong> these fields is stored in<br />

<strong>SQL</strong>ERRM in the <strong>SQL</strong>CA. More detailed cause and recovery in<strong>for</strong>mation <strong>for</strong> any<br />

<strong>SQL</strong>CODE can be found by using the Display Message Description (DSPMSGD)<br />

CL command.<br />

Positive <strong>SQL</strong>CODEs<br />

Explanation: The <strong>SQL</strong> statement has run successfully.<br />

If <strong>SQL</strong>WARN0 is blank, and <strong>SQL</strong>STATE is '00000', the<br />

statement was run successfully. Otherwise, a warning<br />

condition exists. Check the other warning indicators or<br />

<strong>SQL</strong>STATE to determine the particular warning<br />

condition. For example, if <strong>SQL</strong>WARN1 is not blank, a<br />

string has been truncated. The following warnings have<br />

an <strong>SQL</strong>CODE of zero:<br />

v <strong>SQL</strong>WARN1 <strong>SQL</strong>STATE 01004<br />

Explanation: The value of a string column was<br />

truncated when assigned to a host variable.<br />

v <strong>SQL</strong>WARN2 <strong>SQL</strong>STATE 01003<br />

Explanation: Null values were eliminated from the<br />

argument of a column function.<br />

v <strong>SQL</strong>WARN3 <strong>SQL</strong>STATE 01503<br />

Explanation: The number of result columns is larger<br />

than the number of host variables provided.<br />

v <strong>SQL</strong>WARN4 <strong>SQL</strong>STATE 01504<br />

Explanation: The UPDATE or DELETE statement<br />

does not include a WHERE clause.<br />

v <strong>SQL</strong>WARN6 <strong>SQL</strong>STATE 01506<br />

Explanation: An adjustment was made to a DATE or<br />

TIMESTAMP value to correct a date the was not<br />

valid. The date resulted from an arithmetic<br />

operation.<br />

<strong>SQL</strong>0012 <strong>SQL</strong>CODE +12 <strong>SQL</strong>STATE 01545<br />

Explanation: Correlation without qualification<br />

occurred <strong>for</strong> column &1 to table &2.<br />

<strong>SQL</strong>0030 <strong>SQL</strong>CODE +30 <strong>SQL</strong>STATE 01503<br />

Explanation: Number of INTO host-variable incorrect.<br />

<strong>SQL</strong>0088 <strong>SQL</strong>CODE +88 <strong>SQL</strong>STATE 01504<br />

Explanation: No WHERE on UPDATE or DELETE.<br />

<strong>SQL</strong>0100 <strong>SQL</strong>CODE +100 <strong>SQL</strong>STATE 02000<br />

Explanation: Row not found <strong>for</strong> &1.<br />

<strong>SQL</strong>0114 <strong>SQL</strong>CODE +114 <strong>SQL</strong>STATE 01536<br />

Explanation: Relational database &1 not the same as<br />

current server &2.<br />

<strong>SQL</strong>0138 <strong>SQL</strong>CODE +138 <strong>SQL</strong>STATE 01544<br />

Explanation: Argument &1 of SUBSTR function not<br />

valid.<br />

<strong>SQL</strong>0177 <strong>SQL</strong>CODE +177 <strong>SQL</strong>STATE 01009<br />

Explanation: CHECK condition text too long.<br />

<strong>SQL</strong>0178 <strong>SQL</strong>CODE +178 <strong>SQL</strong>STATE 0100A<br />

Explanation: Query expression text <strong>for</strong> view &1 in &2<br />

too long.<br />

<strong>SQL</strong>0180 <strong>SQL</strong>CODE +180 <strong>SQL</strong>STATE 01534<br />

Explanation: Syntax of date, time, or timestamp value<br />

not valid.<br />

<strong>SQL</strong>0181 <strong>SQL</strong>CODE +181 <strong>SQL</strong>STATE 01534<br />

Explanation: Value in date, time, or timestamp string<br />

not valid.<br />

Appendix B. <strong>SQL</strong>CODEs and <strong>SQL</strong>STATEs 291


<strong>SQL</strong>0183 <strong>SQL</strong>CODE +183 <strong>SQL</strong>STATE 01535<br />

Explanation: The result of a date or timestamp<br />

expression not valid.<br />

<strong>SQL</strong>0191 <strong>SQL</strong>CODE +191 <strong>SQL</strong>STATE 01547<br />

Explanation: MIXED data not properly <strong>for</strong>med.<br />

<strong>SQL</strong>0204 <strong>SQL</strong>CODE +204 <strong>SQL</strong>STATE 01532<br />

Explanation: Object &1 in &2 type *&3 not found.<br />

<strong>SQL</strong>0237 <strong>SQL</strong>CODE +237 <strong>SQL</strong>STATE 01005<br />

Explanation: Not enough <strong>SQL</strong>VAR entries were<br />

provided in the <strong>SQL</strong>DA.<br />

<strong>SQL</strong>0239 <strong>SQL</strong>CODE +239 <strong>SQL</strong>STATE 01005<br />

Explanation: Not enough <strong>SQL</strong>VAR entries were<br />

provided in the <strong>SQL</strong>DA.<br />

<strong>SQL</strong>0304 <strong>SQL</strong>CODE +304 <strong>SQL</strong>STATE 01515,<br />

01547, 01565<br />

Explanation: Conversion error in assignment to host<br />

variable &2.<br />

<strong>SQL</strong>0326 <strong>SQL</strong>CODE +326 <strong>SQL</strong>STATE 01557<br />

Explanation: Too many host variables specified.<br />

<strong>SQL</strong>0331 <strong>SQL</strong>CODE +331 <strong>SQL</strong>STATE 01520<br />

Explanation: Characters conversion cannot be<br />

per<strong>for</strong>med.<br />

<strong>SQL</strong>0335 <strong>SQL</strong>CODE +335 <strong>SQL</strong>STATE 01517<br />

Explanation: Characters conversion has resulted in<br />

substitution characters.<br />

<strong>SQL</strong>0360 <strong>SQL</strong>CODE +360 <strong>SQL</strong>STATE 01627<br />

Explanation: Datalink in table &1 in &2 may not be<br />

valid due to pending links.<br />

<strong>SQL</strong>0403 <strong>SQL</strong>CODE +403 <strong>SQL</strong>STATE 01522<br />

Explanation: Alias &1 in &2 created but table or view<br />

not found.<br />

<strong>SQL</strong>0420 <strong>SQL</strong>CODE +420 <strong>SQL</strong>STATE 01565<br />

Explanation: Character in C<strong>AS</strong>T argument not valid.<br />

292 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5<br />

<strong>SQL</strong>0445 <strong>SQL</strong>CODE +445 <strong>SQL</strong>STATE 01004<br />

Explanation: Value of parameter &4 in procedure &1<br />

in &2 too long.<br />

<strong>SQL</strong>0460 <strong>SQL</strong>CODE +460 <strong>SQL</strong>STATE 01593<br />

Explanation: Truncation of data may have occurred<br />

<strong>for</strong> ALTER TABLE in &1 of &2.<br />

<strong>SQL</strong>0462 <strong>SQL</strong>CODE +462 <strong>SQL</strong>STATE 01Hxx<br />

Explanation: Procedure or user-defined function &1 in<br />

&2 returned a warning <strong>SQL</strong>STATE.<br />

<strong>SQL</strong>0551 <strong>SQL</strong>CODE +551 <strong>SQL</strong>STATE 01548<br />

Explanation: Not authorized to object &1 in &2 type<br />

*&3.<br />

<strong>SQL</strong>0552 <strong>SQL</strong>CODE +552 <strong>SQL</strong>STATE 01542<br />

Explanation: Not authorized to &1.<br />

<strong>SQL</strong>0569 <strong>SQL</strong>CODE +569 <strong>SQL</strong>STATE 01006<br />

Explanation: Not all requested privileges revoked<br />

from object &1 in &2 type &3.<br />

<strong>SQL</strong>0570 <strong>SQL</strong>CODE +570 <strong>SQL</strong>STATE 01007<br />

Explanation: Not all requested privileges to object &1<br />

in &2 type &3 granted.<br />

<strong>SQL</strong>0595 <strong>SQL</strong>CODE +595 <strong>SQL</strong>STATE 01526<br />

Explanation: Commit level &1 escalated to &2 lock.<br />

<strong>SQL</strong>0596 <strong>SQL</strong>CODE +596 <strong>SQL</strong>STATE 01002<br />

Explanation: Error occurred during disconnect.<br />

<strong>SQL</strong>0645 <strong>SQL</strong>CODE +645 <strong>SQL</strong>STATE 01528<br />

Explanation: WHERE NOT NULL clause ignored <strong>for</strong><br />

index &1 in &2.<br />

<strong>SQL</strong>0802 <strong>SQL</strong>CODE +802 <strong>SQL</strong>STATE 01519,<br />

01547, 01564, 01565<br />

Explanation: Data conversion or data mapping error.<br />

<strong>SQL</strong>0863 <strong>SQL</strong>CODE +863 <strong>SQL</strong>STATE 01539<br />

Explanation: Mixed or DBCS CCSID not supported by<br />

relational database &1.


<strong>SQL</strong>0990 <strong>SQL</strong>CODE +990 <strong>SQL</strong>STATE 01587<br />

Explanation: Outcome unknown <strong>for</strong> the unit of work.<br />

<strong>SQL</strong>7905 <strong>SQL</strong>CODE +7905 <strong>SQL</strong>STATE 01567<br />

Explanation: Table &1 in &2 created but could not be<br />

journaled.<br />

Negative <strong>SQL</strong>CODEs<br />

<strong>SQL</strong>0007 <strong>SQL</strong>CODE -07 <strong>SQL</strong>STATE 42601<br />

Explanation: Character &1 (HEX &2) not valid in <strong>SQL</strong><br />

statement.<br />

<strong>SQL</strong>0010 <strong>SQL</strong>CODE -10 <strong>SQL</strong>STATE 42603<br />

Explanation: String constant beginning &1 not<br />

delimited.<br />

<strong>SQL</strong>0029 <strong>SQL</strong>CODE -29 <strong>SQL</strong>STATE 42601<br />

Explanation: INTO clause missing from embedded<br />

SELECT statement.<br />

<strong>SQL</strong>0051 <strong>SQL</strong>CODE -51 <strong>SQL</strong>STATE 3C000<br />

Explanation: Cursor or procedure &1 previously<br />

declared.<br />

<strong>SQL</strong>0060 <strong>SQL</strong>CODE -60 <strong>SQL</strong>STATE 42815<br />

Explanation: Value &3 <strong>for</strong> argument &1 of &2<br />

function not valid.<br />

<strong>SQL</strong>0078 <strong>SQL</strong>CODE -78 <strong>SQL</strong>STATE 42629<br />

Explanation: Parameter name required <strong>for</strong> routine &1<br />

in &2.<br />

<strong>SQL</strong>0080 <strong>SQL</strong>CODE -80 <strong>SQL</strong>STATE 42978<br />

Explanation: Indicator variable &1 not SMALLINT<br />

type.<br />

<strong>SQL</strong>0084 <strong>SQL</strong>CODE -84 <strong>SQL</strong>STATE 42612<br />

Explanation: <strong>SQL</strong> statement not allowed.<br />

<strong>SQL</strong>0090 <strong>SQL</strong>CODE -90 <strong>SQL</strong>STATE 42618<br />

Explanation: Host variable not permitted here.<br />

<strong>SQL</strong>0097 <strong>SQL</strong>CODE -97 <strong>SQL</strong>STATE 42601<br />

Explanation: Use of data type not valid.<br />

<strong>SQL</strong>0099 <strong>SQL</strong>CODE -99 <strong>SQL</strong>STATE 42992<br />

Explanation: Operator in join condition not valid.<br />

<strong>SQL</strong>0101 <strong>SQL</strong>CODE -101 <strong>SQL</strong>STATE 5<strong>400</strong>1,<br />

54010, 54011<br />

Explanation: <strong>SQL</strong> statement too long or complex.<br />

<strong>SQL</strong>0102 <strong>SQL</strong>CODE -102 <strong>SQL</strong>STATE 5<strong>400</strong>2<br />

Explanation: String constant beginning with &1 too<br />

long.<br />

<strong>SQL</strong>0103 <strong>SQL</strong>CODE -103 <strong>SQL</strong>STATE 42604<br />

Explanation: Numeric constant &1 not valid.<br />

<strong>SQL</strong>0104 <strong>SQL</strong>CODE -104 <strong>SQL</strong>STATE 42601<br />

Explanation: Token &1 was not valid. Valid tokens:<br />

&2.<br />

<strong>SQL</strong>0105 <strong>SQL</strong>CODE -105 <strong>SQL</strong>STATE 42604<br />

Explanation: Mixed or graphic string constant not<br />

valid.<br />

<strong>SQL</strong>0106 <strong>SQL</strong>CODE -106 <strong>SQL</strong>STATE 42611<br />

Explanation: Precision specified <strong>for</strong> FLOAT column<br />

not valid.<br />

<strong>SQL</strong>0107 <strong>SQL</strong>CODE -107 <strong>SQL</strong>STATE 42622<br />

Explanation: &1 too long. Maximum &2 characters.<br />

<strong>SQL</strong>0109 <strong>SQL</strong>CODE -109 <strong>SQL</strong>STATE 42601<br />

Explanation: &1 clause not allowed.<br />

<strong>SQL</strong>0110 <strong>SQL</strong>CODE -110 <strong>SQL</strong>STATE 42606<br />

Explanation: Hexadecimal constant beginning with &1<br />

not valid.<br />

Appendix B. <strong>SQL</strong>CODEs and <strong>SQL</strong>STATEs 293


<strong>SQL</strong>0112 <strong>SQL</strong>CODE -112 <strong>SQL</strong>STATE 42607<br />

Explanation: Argument of function &1 is another<br />

function.<br />

<strong>SQL</strong>0113 <strong>SQL</strong>CODE -113 <strong>SQL</strong>STATE 28000,<br />

2E000, 42602<br />

Explanation: Name &1 not allowed.<br />

<strong>SQL</strong>0114 <strong>SQL</strong>CODE -114 <strong>SQL</strong>STATE 42961<br />

Explanation: Relational database &1 not the same as<br />

current server &2.<br />

<strong>SQL</strong>0115 <strong>SQL</strong>CODE -115 <strong>SQL</strong>STATE 42601<br />

Explanation: Comparison operator &1 not valid.<br />

<strong>SQL</strong>0117 <strong>SQL</strong>CODE -117 <strong>SQL</strong>STATE 42802<br />

Explanation: Statement inserts wrong number of<br />

values.<br />

<strong>SQL</strong>0118 <strong>SQL</strong>CODE -118 <strong>SQL</strong>STATE 42902<br />

Explanation: Table &1 in &2 also specified in a FROM<br />

clause.<br />

<strong>SQL</strong>0119 <strong>SQL</strong>CODE -119 <strong>SQL</strong>STATE 42803<br />

Explanation: Column &1 in HAVING clause not in<br />

GROUP BY.<br />

<strong>SQL</strong>0120 <strong>SQL</strong>CODE -120 <strong>SQL</strong>STATE 42903<br />

Explanation: Use of column function &2 not valid.<br />

<strong>SQL</strong>0121 <strong>SQL</strong>CODE -121 <strong>SQL</strong>STATE 42701<br />

Explanation: Duplicate column name &1 in INSERT or<br />

UPDATE.<br />

<strong>SQL</strong>0122 <strong>SQL</strong>CODE -122 <strong>SQL</strong>STATE 42803<br />

Explanation: Column specified in SELECT list not<br />

valid.<br />

<strong>SQL</strong>0125 <strong>SQL</strong>CODE -125 <strong>SQL</strong>STATE 42805<br />

Explanation: ORDER BY column number &1 not<br />

valid.<br />

<strong>SQL</strong>0128 <strong>SQL</strong>CODE -128 <strong>SQL</strong>STATE 42601<br />

Explanation: Use of NULL is not valid.<br />

294 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5<br />

<strong>SQL</strong>0129 <strong>SQL</strong>CODE -129 <strong>SQL</strong>STATE 5<strong>400</strong>4<br />

Explanation: Too many tables in <strong>SQL</strong> statement.<br />

<strong>SQL</strong>0130 <strong>SQL</strong>CODE -130 <strong>SQL</strong>STATE 22019,<br />

22025<br />

Explanation: Escape character &1 or LIKE pattern not<br />

valid.<br />

<strong>SQL</strong>0131 <strong>SQL</strong>CODE -131 <strong>SQL</strong>STATE 42818<br />

Explanation: Operands of LIKE not compatible or not<br />

valid.<br />

<strong>SQL</strong>0132 <strong>SQL</strong>CODE -132 <strong>SQL</strong>STATE 42824<br />

Explanation: LIKE predicate not valid.<br />

<strong>SQL</strong>0133 <strong>SQL</strong>CODE -133 <strong>SQL</strong>STATE 42906<br />

Explanation: Operator on correlated column in <strong>SQL</strong><br />

function not valid.<br />

<strong>SQL</strong>0134 <strong>SQL</strong>CODE -134 <strong>SQL</strong>STATE 42907<br />

Explanation: Argument of function too long.<br />

<strong>SQL</strong>0136 <strong>SQL</strong>CODE -136 <strong>SQL</strong>STATE 5<strong>400</strong>5<br />

Explanation: ORDER BY or GROUP BY columns too<br />

long.<br />

<strong>SQL</strong>0137 <strong>SQL</strong>CODE -137 <strong>SQL</strong>STATE 5<strong>400</strong>6<br />

Explanation: Result too long.<br />

<strong>SQL</strong>0138 <strong>SQL</strong>CODE -138 <strong>SQL</strong>STATE 22011<br />

Explanation: Argument &1 of SUBSTR function not<br />

valid.<br />

<strong>SQL</strong>0144 <strong>SQL</strong>CODE -144 <strong>SQL</strong>STATE 58003<br />

Explanation: Section number not valid.<br />

<strong>SQL</strong>0145 <strong>SQL</strong>CODE -145 <strong>SQL</strong>STATE 55005<br />

Explanation: Recursion not supported <strong>for</strong> an<br />

application server other than the <strong>AS</strong>/<strong>400</strong> system.<br />

<strong>SQL</strong>0150 <strong>SQL</strong>CODE -150 <strong>SQL</strong>STATE 42807<br />

Explanation: View or logical file &1 in &2 read-only.


<strong>SQL</strong>0151 <strong>SQL</strong>CODE -151 <strong>SQL</strong>STATE 42808<br />

Explanation: Column &1 in table &2 in &3 read-only.<br />

<strong>SQL</strong>0152 <strong>SQL</strong>CODE -152 <strong>SQL</strong>STATE 42809<br />

Explanation: Constraint type not valid <strong>for</strong> constraint<br />

&1 in &2.<br />

<strong>SQL</strong>0153 <strong>SQL</strong>CODE -153 <strong>SQL</strong>STATE 42908<br />

Explanation: Column list required <strong>for</strong> CREATE VIEW.<br />

<strong>SQL</strong>0154 <strong>SQL</strong>CODE -154 <strong>SQL</strong>STATE 42909<br />

Explanation: UNION and UNION ALL <strong>for</strong> CREATE<br />

VIEW not valid.<br />

<strong>SQL</strong>0156 <strong>SQL</strong>CODE -156 <strong>SQL</strong>STATE 42809<br />

Explanation: &1 in &2 not a table.<br />

<strong>SQL</strong>0157 <strong>SQL</strong>CODE -157 <strong>SQL</strong>STATE 42810<br />

Explanation: View &1 in &2 not valid in FOREIGN<br />

KEY clause.<br />

<strong>SQL</strong>0158 <strong>SQL</strong>CODE -158 <strong>SQL</strong>STATE 42811<br />

Explanation: Number of columns specified not<br />

consistent.<br />

<strong>SQL</strong>0159 <strong>SQL</strong>CODE -159 <strong>SQL</strong>STATE 42809<br />

Explanation: &1 in &2 not correct type.<br />

<strong>SQL</strong>0160 <strong>SQL</strong>CODE -160 <strong>SQL</strong>STATE 42813<br />

Explanation: WITH CHECK OPTION not allowed <strong>for</strong><br />

view &1 in &2.<br />

<strong>SQL</strong>0161 <strong>SQL</strong>CODE -161 <strong>SQL</strong>STATE 4<strong>400</strong>0<br />

Explanation: INSERT/UPDATE not allowed due to<br />

WITH CHECK OPTION.<br />

<strong>SQL</strong>0170 <strong>SQL</strong>CODE -170 <strong>SQL</strong>STATE 42605<br />

Explanation: Number of arguments <strong>for</strong> function &1<br />

not valid.<br />

<strong>SQL</strong>0171 <strong>SQL</strong>CODE -171 <strong>SQL</strong>STATE 42815<br />

Explanation: Argument &1 of function &2 not valid.<br />

<strong>SQL</strong>0175 <strong>SQL</strong>CODE -175 <strong>SQL</strong>STATE 58028<br />

Explanation: COMMIT failed.<br />

<strong>SQL</strong>0180 <strong>SQL</strong>CODE -180 <strong>SQL</strong>STATE 22007<br />

Explanation: Syntax of date, time, or timestamp value<br />

not valid.<br />

<strong>SQL</strong>0181 <strong>SQL</strong>CODE -181 <strong>SQL</strong>STATE 22007<br />

Explanation: Value in date, time, or timestamp string<br />

not valid.<br />

<strong>SQL</strong>0182 <strong>SQL</strong>CODE -182 <strong>SQL</strong>STATE 42816<br />

Explanation: A date, time, or timestamp expression<br />

not valid.<br />

<strong>SQL</strong>0183 <strong>SQL</strong>CODE -183 <strong>SQL</strong>STATE 22008<br />

Explanation: The result of a date or timestamp<br />

expression not valid.<br />

<strong>SQL</strong>0184 <strong>SQL</strong>CODE -184 <strong>SQL</strong>STATE 42610<br />

Explanation: Parameter marker not valid in<br />

expression.<br />

<strong>SQL</strong>0187 <strong>SQL</strong>CODE -187 <strong>SQL</strong>STATE 42816<br />

Explanation: Use of labeled duration is not valid.<br />

<strong>SQL</strong>0188 <strong>SQL</strong>CODE -188 <strong>SQL</strong>STATE 22503,<br />

28000, 2E000<br />

Explanation: &1 is not a valid string representation of<br />

an authorization name or a relational database name.<br />

<strong>SQL</strong>0189 <strong>SQL</strong>CODE -189 <strong>SQL</strong>STATE 22522<br />

Explanation: Coded Character Set Identifier &1 is not<br />

valid.<br />

<strong>SQL</strong>0190 <strong>SQL</strong>CODE -190 <strong>SQL</strong>STATE 42837<br />

Explanation: Attributes of column &3 in &1 in &2 not<br />

compatible.<br />

<strong>SQL</strong>0191 <strong>SQL</strong>CODE -191 <strong>SQL</strong>STATE 22504<br />

Explanation: MIXED data not properly <strong>for</strong>med.<br />

<strong>SQL</strong>0192 <strong>SQL</strong>CODE -192 <strong>SQL</strong>STATE 42937<br />

Explanation: Argument of TRANSLATE function not<br />

valid.<br />

Appendix B. <strong>SQL</strong>CODEs and <strong>SQL</strong>STATEs 295


<strong>SQL</strong>0194 <strong>SQL</strong>CODE -194 <strong>SQL</strong>STATE 42848<br />

Explanation: KEEP LOCKS not allowed.<br />

<strong>SQL</strong>0195 <strong>SQL</strong>CODE -195 <strong>SQL</strong>STATE 42814<br />

Explanation: Last column of &1 in &2 cannot be<br />

dropped.<br />

<strong>SQL</strong>0196 <strong>SQL</strong>CODE -196 <strong>SQL</strong>STATE 42817<br />

Explanation: Column &3 in &1 in &2 cannot be<br />

dropped with RESTRICT.<br />

<strong>SQL</strong>0197 <strong>SQL</strong>CODE -197 <strong>SQL</strong>STATE 42877<br />

Explanation: Column &1 cannot be qualified.<br />

<strong>SQL</strong>0198 <strong>SQL</strong>CODE -198 <strong>SQL</strong>STATE 42617<br />

Explanation: <strong>SQL</strong> statement empty or blank.<br />

<strong>SQL</strong>0199 <strong>SQL</strong>CODE -199 <strong>SQL</strong>STATE 42601<br />

Explanation: Keyword &1 not expected. Valid tokens:<br />

&2.<br />

<strong>SQL</strong>0203 <strong>SQL</strong>CODE -203 <strong>SQL</strong>STATE 42702<br />

Explanation: Column &1 is ambiguous.<br />

<strong>SQL</strong>0204 <strong>SQL</strong>CODE -204 <strong>SQL</strong>STATE 42704<br />

Explanation: &1 in &2 type *&3 not found.<br />

<strong>SQL</strong>0205 <strong>SQL</strong>CODE -205 <strong>SQL</strong>STATE 42703<br />

Explanation: Column &1 not in table &2.<br />

<strong>SQL</strong>0206 <strong>SQL</strong>CODE -206 <strong>SQL</strong>STATE 42703<br />

Explanation: Column &1 not in specified tables.<br />

<strong>SQL</strong>0208 <strong>SQL</strong>CODE -208 <strong>SQL</strong>STATE 42707<br />

Explanation: ORDER BY column &1 not in results<br />

table.<br />

<strong>SQL</strong>0212 <strong>SQL</strong>CODE -212 <strong>SQL</strong>STATE 42712<br />

Explanation: Duplicate table designator &1 not valid.<br />

<strong>SQL</strong>0214 <strong>SQL</strong>CODE -214 <strong>SQL</strong>STATE 42822<br />

Explanation: ORDER BY expression is not valid.<br />

296 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5<br />

<strong>SQL</strong>0221 <strong>SQL</strong>CODE -221 <strong>SQL</strong>STATE 42873<br />

Explanation: Number of rows &2 not valid.<br />

<strong>SQL</strong>0225 <strong>SQL</strong>CODE -225 <strong>SQL</strong>STATE 42872<br />

Explanation: FETCH not valid; cursor &1 not declared<br />

with SCROLL.<br />

<strong>SQL</strong>0226 <strong>SQL</strong>CODE -226 <strong>SQL</strong>STATE 24507<br />

Explanation: Current row deleted or moved <strong>for</strong> cursor<br />

&1.<br />

<strong>SQL</strong>0227 <strong>SQL</strong>CODE -227 <strong>SQL</strong>STATE 24513<br />

Explanation: FETCH not valid, cursor &1 in unknown<br />

position.<br />

<strong>SQL</strong>0228 <strong>SQL</strong>CODE -228 <strong>SQL</strong>STATE 42620<br />

Explanation: FOR UPDATE OF clause not valid with<br />

SCROLL <strong>for</strong> cursor &1.<br />

<strong>SQL</strong>0231 <strong>SQL</strong>CODE -231 <strong>SQL</strong>STATE 22006<br />

Explanation: Position of cursor &1 not valid <strong>for</strong><br />

FETCH of current row.<br />

<strong>SQL</strong>0250 <strong>SQL</strong>CODE -250 <strong>SQL</strong>STATE 42718<br />

Explanation: Local relational database not defined in<br />

the directory.<br />

<strong>SQL</strong>0251 <strong>SQL</strong>CODE -251 <strong>SQL</strong>STATE 2E000,<br />

42602<br />

Explanation: Character in relational database name &1<br />

is not valid.<br />

<strong>SQL</strong>0255 <strong>SQL</strong>CODE -255 <strong>SQL</strong>STATE 42999<br />

Explanation: <strong>DB2</strong> Multisystem query error.<br />

<strong>SQL</strong>0256 <strong>SQL</strong>CODE -256 <strong>SQL</strong>STATE 42998<br />

Explanation: Constraint &1 in &2 not allowed on<br />

distributed file.<br />

<strong>SQL</strong>0270 <strong>SQL</strong>CODE -270 <strong>SQL</strong>STATE 42997<br />

Explanation: Unique index not allowed.<br />

<strong>SQL</strong>0301 <strong>SQL</strong>CODE -301 <strong>SQL</strong>STATE<br />

07006,42895<br />

Explanation: Input host variable &2 or argument &1<br />

not valid.


<strong>SQL</strong>0302 <strong>SQL</strong>CODE -302 <strong>SQL</strong>STATE 22001,<br />

22003, 22023, 22024<br />

Explanation: Conversion error on input host variable<br />

&2.<br />

<strong>SQL</strong>0303 <strong>SQL</strong>CODE -303 <strong>SQL</strong>STATE 22001,<br />

42806<br />

Explanation: Host variable &1 not compatible with<br />

SELECT item.<br />

<strong>SQL</strong>0304 <strong>SQL</strong>CODE -304 <strong>SQL</strong>STATE 22003,<br />

22023, 22504<br />

Explanation: Conversion error in assignment to host<br />

variable &2.<br />

<strong>SQL</strong>0305 <strong>SQL</strong>CODE -305 <strong>SQL</strong>STATE 22002<br />

Explanation: Indicator variable required.<br />

<strong>SQL</strong>0306 <strong>SQL</strong>CODE -306 <strong>SQL</strong>STATE 42863<br />

Explanation: Undefined host variable in REXX.<br />

<strong>SQL</strong>0311 <strong>SQL</strong>CODE -311 <strong>SQL</strong>STATE 22501<br />

Explanation: Length in a varying-length host variable<br />

not valid.<br />

<strong>SQL</strong>0312 <strong>SQL</strong>CODE -312 <strong>SQL</strong>STATE 42618<br />

Explanation: Host variable &1 not defined or not<br />

usable.<br />

<strong>SQL</strong>0313 <strong>SQL</strong>CODE -313 <strong>SQL</strong>STATE 07001,<br />

07004<br />

Explanation: Number of host variables not valid.<br />

<strong>SQL</strong>0328 <strong>SQL</strong>CODE -328 <strong>SQL</strong>STATE 42996<br />

Explanation: Column &1 not allowed in partitioning<br />

key.<br />

<strong>SQL</strong>0329 <strong>SQL</strong>CODE -329 <strong>SQL</strong>STATE 0E000<br />

Explanation: The SET PATH name list is not valid.<br />

<strong>SQL</strong>0330 <strong>SQL</strong>CODE -330 <strong>SQL</strong>STATE 22021<br />

Explanation: Character conversion cannot be<br />

per<strong>for</strong>med.<br />

<strong>SQL</strong>0331 <strong>SQL</strong>CODE -331 <strong>SQL</strong>STATE 22021<br />

Explanation: Character conversion cannot be<br />

per<strong>for</strong>med.<br />

<strong>SQL</strong>0332 <strong>SQL</strong>CODE -332 <strong>SQL</strong>STATE 57017<br />

Explanation: Character conversion between CCSID &1<br />

and CCSID &2 not valid.<br />

<strong>SQL</strong>0334 <strong>SQL</strong>CODE -334 <strong>SQL</strong>STATE 22524<br />

Explanation: Character conversion has resulted in<br />

truncation.<br />

<strong>SQL</strong>0338 <strong>SQL</strong>CODE -338 <strong>SQL</strong>STATE 42972<br />

Explanation: JOIN expression not valid.<br />

<strong>SQL</strong>0340 <strong>SQL</strong>CODE -340 <strong>SQL</strong>STATE 42726<br />

Explanation: Duplicate name &1 <strong>for</strong> common table<br />

expression.<br />

<strong>SQL</strong>0341 <strong>SQL</strong>CODE -341 <strong>SQL</strong>STATE 42835<br />

Explanation: Cyclic references between common table<br />

expressions.<br />

<strong>SQL</strong>0346 <strong>SQL</strong>CODE -346 <strong>SQL</strong>STATE 42836<br />

Explanation: Recursion not allowed <strong>for</strong> common table<br />

expressions.<br />

<strong>SQL</strong>0350 <strong>SQL</strong>CODE -350 <strong>SQL</strong>STATE 42962<br />

Explanation: Column &1 is not valid as key field <strong>for</strong><br />

index or constraint.<br />

<strong>SQL</strong>0351 <strong>SQL</strong>CODE -351 <strong>SQL</strong>STATE 56084<br />

Explanation: The AR is not at the same level and<br />

<strong>DB2</strong>/<strong>400</strong> cannot trans<strong>for</strong>m the data type to a<br />

compatible type.<br />

<strong>SQL</strong>0352 <strong>SQL</strong>CODE -352 <strong>SQL</strong>STATE 56084<br />

Explanation: The <strong>AS</strong> is not at the same level and<br />

<strong>DB2</strong>/<strong>400</strong> cannot trans<strong>for</strong>m the data type to a<br />

compatible type.<br />

<strong>SQL</strong>0357 <strong>SQL</strong>CODE -357 <strong>SQL</strong>STATE 57050<br />

Explanation: File server &1 used in DataLink not<br />

currently available.<br />

Appendix B. <strong>SQL</strong>CODEs and <strong>SQL</strong>STATEs 297


<strong>SQL</strong>0358 <strong>SQL</strong>CODE -358 <strong>SQL</strong>STATE 428D1<br />

Explanation: Error &1 occurred using DataLink data<br />

type.<br />

<strong>SQL</strong>0392 <strong>SQL</strong>CODE -392 <strong>SQL</strong>STATE 42855<br />

Explanation: Assignment of LOB to specified host<br />

variable not allowed.<br />

<strong>SQL</strong>0398 <strong>SQL</strong>CODE -398 <strong>SQL</strong>STATE 428D2<br />

Explanation: <strong>AS</strong> LOCATOR cannot be specified <strong>for</strong> a<br />

non-LOB parameter.<br />

<strong>SQL</strong>0401 <strong>SQL</strong>CODE -401 <strong>SQL</strong>STATE 42818<br />

Explanation: Comparison operator &1 operands not<br />

compatible.<br />

<strong>SQL</strong>0402 <strong>SQL</strong>CODE -402 <strong>SQL</strong>STATE 42819<br />

Explanation: &1 use not valid.<br />

<strong>SQL</strong>0404 <strong>SQL</strong>CODE -404 <strong>SQL</strong>STATE 22001<br />

Explanation: Value <strong>for</strong> column &1 too long.<br />

<strong>SQL</strong>0405 <strong>SQL</strong>CODE -405 <strong>SQL</strong>STATE 42820<br />

Explanation: Numeric constant &1 out of range.<br />

<strong>SQL</strong>0406 <strong>SQL</strong>CODE -406 <strong>SQL</strong>STATE 22003,<br />

22023, 22504<br />

Explanation: Conversion error on assignment to<br />

column &2.<br />

<strong>SQL</strong>0407 <strong>SQL</strong>CODE -407 <strong>SQL</strong>STATE 23502<br />

Explanation: Null values are not allowed in column<br />

&1.<br />

<strong>SQL</strong>0408 <strong>SQL</strong>CODE -408 <strong>SQL</strong>STATE 42821<br />

Explanation: INSERT or UPDATE value <strong>for</strong> column<br />

&1 not compatible.<br />

<strong>SQL</strong>0410 <strong>SQL</strong>CODE -410 <strong>SQL</strong>STATE 42820<br />

Explanation: Floating point literal &1 not valid.<br />

<strong>SQL</strong>0412 <strong>SQL</strong>CODE -412 <strong>SQL</strong>STATE 42823<br />

Explanation: Subquery with more than one result<br />

column not valid.<br />

298 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5<br />

<strong>SQL</strong>0414 <strong>SQL</strong>CODE -414 <strong>SQL</strong>STATE 42824<br />

Explanation: Column &1 not valid in LIKE predicate.<br />

<strong>SQL</strong>0415 <strong>SQL</strong>CODE -415 <strong>SQL</strong>STATE 42825<br />

Explanation: UNION operands not compatible.<br />

<strong>SQL</strong>0417 <strong>SQL</strong>CODE -417 <strong>SQL</strong>STATE 42609<br />

Explanation: Combination of parameter markers not<br />

valid.<br />

<strong>SQL</strong>0418 <strong>SQL</strong>CODE -418 <strong>SQL</strong>STATE 42610<br />

Explanation: Use of parameter marker is not valid.<br />

<strong>SQL</strong>0419 <strong>SQL</strong>CODE -419 <strong>SQL</strong>STATE 42911<br />

Explanation: Negative scale not valid.<br />

<strong>SQL</strong>0420 <strong>SQL</strong>CODE -420 <strong>SQL</strong>STATE 22018<br />

Explanation: Character in C<strong>AS</strong>T argument not valid.<br />

<strong>SQL</strong>0421 <strong>SQL</strong>CODE -421 <strong>SQL</strong>STATE 42826<br />

Explanation: Number of UNION operands not equal.<br />

<strong>SQL</strong>0423 <strong>SQL</strong>CODE -423 <strong>SQL</strong>STATE 0F001<br />

Explanation: LOB locator &1 not valid.<br />

<strong>SQL</strong>0428 <strong>SQL</strong>CODE -428 <strong>SQL</strong>STATE 25501<br />

Explanation: <strong>SQL</strong> statement cannot be run.<br />

<strong>SQL</strong>0429 <strong>SQL</strong>CODE -429 <strong>SQL</strong>STATE 54028<br />

Explanation: The maximum number of concurrent<br />

LOB locators has been reached.<br />

<strong>SQL</strong>0432 <strong>SQL</strong>CODE -432 <strong>SQL</strong>STATE 42841<br />

Explanation: A parameter marker cannot have the<br />

user-defined type name &1.<br />

<strong>SQL</strong>0433 <strong>SQL</strong>CODE -433 <strong>SQL</strong>STATE 22001<br />

Explanation: Significant digits truncated during C<strong>AS</strong>T<br />

from numeric to character.<br />

<strong>SQL</strong>0440 <strong>SQL</strong>CODE -440 <strong>SQL</strong>STATE 42884<br />

Explanation: Number of arguments on CALL must<br />

match procedure.


<strong>SQL</strong>0441 <strong>SQL</strong>CODE -441 <strong>SQL</strong>STATE 42601<br />

Explanation: Clause or keyword &1 not valid where<br />

specified.<br />

<strong>SQL</strong>0442 <strong>SQL</strong>CODE -442 <strong>SQL</strong>STATE 54023<br />

Explanation: Maximum # of parameters on CALL<br />

exceeded.<br />

<strong>SQL</strong>0443 <strong>SQL</strong>CODE -443 <strong>SQL</strong>STATE 2Fxxx,<br />

38501<br />

Explanation: Trigger program or external procedure<br />

detected on error.<br />

<strong>SQL</strong>0444 <strong>SQL</strong>CODE -444 <strong>SQL</strong>STATE 42724<br />

Explanation: External program &4 in &1 not found.<br />

<strong>SQL</strong>0446 <strong>SQL</strong>CODE -446 <strong>SQL</strong>STATE 22003<br />

Explanation: Conversion error in assignment of<br />

argument &2.<br />

<strong>SQL</strong>0448 <strong>SQL</strong>CODE -448 <strong>SQL</strong>STATE 54023<br />

Explanation: Maximum parameters on DECLARE<br />

PROCEDURE exceeded.<br />

<strong>SQL</strong>0449 <strong>SQL</strong>CODE -449 <strong>SQL</strong>STATE 42878<br />

Explanation: External program name <strong>for</strong> procedure &1<br />

in &2 not valid.<br />

<strong>SQL</strong>0451 <strong>SQL</strong>CODE -451 <strong>SQL</strong>STATE 42815<br />

Explanation: Attributes of parameter &1 not valid <strong>for</strong><br />

procedure.<br />

<strong>SQL</strong>0452 <strong>SQL</strong>CODE -452 <strong>SQL</strong>STATE 428A1<br />

Explanation: Unable to access a file that is referred to<br />

by a file reference variable.<br />

<strong>SQL</strong>0453 <strong>SQL</strong>CODE -453 <strong>SQL</strong>STATE 42880<br />

Explanation: Return type <strong>for</strong> function &1 in &2 not<br />

compatible with C<strong>AS</strong>T TO type.<br />

<strong>SQL</strong>0454 <strong>SQL</strong>CODE -454 <strong>SQL</strong>STATE 42723<br />

Explanation: Function &1 in &2 with the same<br />

signature already exists.<br />

<strong>SQL</strong>0455 <strong>SQL</strong>CODE -455 <strong>SQL</strong>STATE 42882<br />

Explanation: Specific name not same as procedure<br />

name.<br />

<strong>SQL</strong>0456 <strong>SQL</strong>CODE -456 <strong>SQL</strong>STATE 42710<br />

Explanation: Specific name &3 in &2 already exists.<br />

<strong>SQL</strong>0457 <strong>SQL</strong>CODE -457 <strong>SQL</strong>STATE 42939<br />

Explanation: Name &1 in &2 not allowed <strong>for</strong> function.<br />

<strong>SQL</strong>0458 <strong>SQL</strong>CODE -458 <strong>SQL</strong>STATE 42883<br />

Explanation: Function &1 in &2 not found with<br />

matching signature.<br />

<strong>SQL</strong>0461 <strong>SQL</strong>CODE -461 <strong>SQL</strong>STATE 42846<br />

Explanation: Cast from &1 to &2 not supported.<br />

<strong>SQL</strong>0463 <strong>SQL</strong>CODE -463 <strong>SQL</strong>STATE 39001<br />

Explanation: <strong>SQL</strong>STATE &4 returned from routine &1<br />

in &2 not valid..<br />

<strong>SQL</strong>0469 <strong>SQL</strong>CODE -469 <strong>SQL</strong>STATE 42886<br />

Explanation: IN, OUT, INOUT not valid <strong>for</strong> parameter<br />

&4 in procedure &1 in &2.<br />

<strong>SQL</strong>0470 <strong>SQL</strong>CODE -470 <strong>SQL</strong>STATE 39002<br />

Explanation: NULL values not allowed <strong>for</strong> parameter<br />

&4 in procedure.<br />

<strong>SQL</strong>0473 <strong>SQL</strong>CODE -473 <strong>SQL</strong>STATE 42918<br />

Explanation: User-defined type &1 cannot be created.<br />

<strong>SQL</strong>0475 <strong>SQL</strong>CODE -475 <strong>SQL</strong>STATE 42866<br />

Explanation: RETURNS data type <strong>for</strong> function &3 in<br />

&4 not valid.<br />

<strong>SQL</strong>0476 <strong>SQL</strong>CODE -476 <strong>SQL</strong>STATE 42725<br />

Explanation: Function &1 in &2 not unique.<br />

<strong>SQL</strong>0478 <strong>SQL</strong>CODE -478 <strong>SQL</strong>STATE 42893<br />

Explanation: Object &1 in &2 of type &3 cannot be<br />

dropped.<br />

Appendix B. <strong>SQL</strong>CODEs and <strong>SQL</strong>STATEs 299


<strong>SQL</strong>0483 <strong>SQL</strong>CODE -483 <strong>SQL</strong>STATE 42885<br />

Explanation: Parameters <strong>for</strong> function &1 in &2 not<br />

same as sourced function.<br />

<strong>SQL</strong>0484 <strong>SQL</strong>CODE -484 <strong>SQL</strong>STATE 42733<br />

Explanation: Routine &1 in &2 already exists.<br />

<strong>SQL</strong>0487 <strong>SQL</strong>CODE -487 <strong>SQL</strong>STATE 38001<br />

Explanation: <strong>SQL</strong> statements not allowed.<br />

<strong>SQL</strong>0490 <strong>SQL</strong>CODE -490 <strong>SQL</strong>STATE 428B7<br />

Explanation: Numeric value &1 not valid.<br />

<strong>SQL</strong>0491 <strong>SQL</strong>CODE -491 <strong>SQL</strong>STATE 42601<br />

Explanation: RETURNS clause required on CREATE<br />

FUNCTION statement.<br />

<strong>SQL</strong>0492 <strong>SQL</strong>CODE -492 <strong>SQL</strong>STATE 42879<br />

Explanation: Data type <strong>for</strong> function &1 in &2 not<br />

valid <strong>for</strong> source type.<br />

<strong>SQL</strong>0501 <strong>SQL</strong>CODE -501 <strong>SQL</strong>STATE 24501<br />

Explanation: Cursor &1 not open.<br />

<strong>SQL</strong>0502 <strong>SQL</strong>CODE -502 <strong>SQL</strong>STATE 24502<br />

Explanation: Cursor &1 already open.<br />

<strong>SQL</strong>0503 <strong>SQL</strong>CODE -503 <strong>SQL</strong>STATE 42912<br />

Explanation: Column &3 cannot be updated.<br />

<strong>SQL</strong>0504 <strong>SQL</strong>CODE -504 <strong>SQL</strong>STATE 3<strong>400</strong>0<br />

Explanation: Cursor &1 not declared.<br />

<strong>SQL</strong>0507 <strong>SQL</strong>CODE -507 <strong>SQL</strong>STATE 24501<br />

Explanation: Cursor &1 not open.<br />

<strong>SQL</strong>0508 <strong>SQL</strong>CODE -508 <strong>SQL</strong>STATE 24504<br />

Explanation: Cursor &1 not positioned on locked row.<br />

<strong>SQL</strong>0509 <strong>SQL</strong>CODE -509 <strong>SQL</strong>STATE 42827<br />

Explanation: Table &2 in &3 not same as table in<br />

cursor &1.<br />

300 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5<br />

<strong>SQL</strong>0510 <strong>SQL</strong>CODE -510 <strong>SQL</strong>STATE 42828<br />

Explanation: Cursor &1 <strong>for</strong> file &2 is read-only.<br />

<strong>SQL</strong>0511 <strong>SQL</strong>CODE -511 <strong>SQL</strong>STATE 42829<br />

Explanation: FOR UPDATE OF clause not valid.<br />

<strong>SQL</strong>0513 <strong>SQL</strong>CODE -513 <strong>SQL</strong>STATE 42924<br />

Explanation: Alias &1 in &2 cannot reference another<br />

alias.<br />

<strong>SQL</strong>0514 <strong>SQL</strong>CODE -514 <strong>SQL</strong>STATE 26501<br />

Explanation: Prepared statement &2 not found.<br />

<strong>SQL</strong>0516 <strong>SQL</strong>CODE -516 <strong>SQL</strong>STATE 26501<br />

Explanation: Prepared statement &2 not found.<br />

<strong>SQL</strong>0517 <strong>SQL</strong>CODE -517 <strong>SQL</strong>STATE 07005<br />

Explanation: Prepared statement &2 not SELECT<br />

statement.<br />

<strong>SQL</strong>0518 <strong>SQL</strong>CODE -518 <strong>SQL</strong>STATE 07003<br />

Explanation: Prepared statement &1 not found.<br />

<strong>SQL</strong>0519 <strong>SQL</strong>CODE -519 <strong>SQL</strong>STATE 24506<br />

Explanation: Prepared statement &2 in use.<br />

<strong>SQL</strong>0520 <strong>SQL</strong>CODE -520 <strong>SQL</strong>STATE 42828<br />

Explanation: Cannot UPDATE or DELETE on cursor<br />

&1.<br />

<strong>SQL</strong>0525 <strong>SQL</strong>CODE -525 <strong>SQL</strong>STATE 51015<br />

Explanation: Statement not valid on application<br />

server.<br />

<strong>SQL</strong>0527 <strong>SQL</strong>CODE -527 <strong>SQL</strong>STATE 42874<br />

Explanation: ALWCPYDTA(*NO) specified but<br />

temporary result required <strong>for</strong> &1.<br />

<strong>SQL</strong>0530 <strong>SQL</strong>CODE -530 <strong>SQL</strong>STATE 23503<br />

Explanation: Insert or UPDATE value not allowed by<br />

referential constraint.<br />

<strong>SQL</strong>0531 <strong>SQL</strong>CODE -531 <strong>SQL</strong>STATE 23001,<br />

23504<br />

Explanation: Update prevented by referential<br />

constraint.


<strong>SQL</strong>0532 <strong>SQL</strong>CODE -532 <strong>SQL</strong>STATE 23001,<br />

23504<br />

Explanation: Delete prevented by referential<br />

constraint.<br />

<strong>SQL</strong>0536 <strong>SQL</strong>CODE -536 <strong>SQL</strong>STATE 42914<br />

Explanation: Delete not allowed because table<br />

referenced in subquery can be affected.<br />

<strong>SQL</strong>0537 <strong>SQL</strong>CODE -537 <strong>SQL</strong>STATE 42709<br />

Explanation: Duplicate column name in definition of<br />

key.<br />

<strong>SQL</strong>0538 <strong>SQL</strong>CODE -538 <strong>SQL</strong>STATE 42830<br />

Explanation: Foreign key attributes do not match<br />

parent key.<br />

<strong>SQL</strong>0539 <strong>SQL</strong>CODE -539 <strong>SQL</strong>STATE 42888<br />

Explanation: Table does not have primary key.<br />

<strong>SQL</strong>0541 <strong>SQL</strong>CODE -541 <strong>SQL</strong>STATE 42891<br />

Explanation: Duplicate UNIQUE constraint already<br />

exists.<br />

<strong>SQL</strong>0543 <strong>SQL</strong>CODE -543 <strong>SQL</strong>STATE 23511<br />

Explanation: Constraint &1 conflicts with SET NULL<br />

or SET DEFAULT rule.<br />

<strong>SQL</strong>0544 <strong>SQL</strong>CODE -544 <strong>SQL</strong>STATE 23512<br />

Explanation: CHECK constraint &1 cannot be added.<br />

<strong>SQL</strong>0545 <strong>SQL</strong>CODE -545 <strong>SQL</strong>STATE 23513<br />

Explanation: INSERT or UPDATE not allowed by<br />

CHECK constraint.<br />

<strong>SQL</strong>0546 <strong>SQL</strong>CODE -546 <strong>SQL</strong>STATE 42621<br />

Explanation: CHECK condition of constraint &1 not<br />

valid.<br />

<strong>SQL</strong>0551 <strong>SQL</strong>CODE -551 <strong>SQL</strong>STATE 42501<br />

Explanation: Not authorized to object &1 in &2 type<br />

*&3.<br />

<strong>SQL</strong>0552 <strong>SQL</strong>CODE -552 <strong>SQL</strong>STATE 42502<br />

Explanation: Not authorized to &1.<br />

<strong>SQL</strong>0557 <strong>SQL</strong>CODE -557 <strong>SQL</strong>STATE 42852<br />

Explanation: Privilege not valid <strong>for</strong> table or view &1<br />

in &2.<br />

<strong>SQL</strong>0573 <strong>SQL</strong>CODE -573 <strong>SQL</strong>STATE 42890<br />

Explanation: Table does not have matching parent key.<br />

<strong>SQL</strong>0574 <strong>SQL</strong>CODE -574 <strong>SQL</strong>STATE 42894<br />

Explanation: Default value not valid.<br />

<strong>SQL</strong>0577 <strong>SQL</strong>CODE -577 <strong>SQL</strong>STATE 38002,<br />

2F002<br />

Explanation: Modifying <strong>SQL</strong> data not permitted.<br />

<strong>SQL</strong>0578 <strong>SQL</strong>CODE -578 <strong>SQL</strong>STATE 2F005<br />

Explanation: RETURN statement not executed <strong>for</strong> <strong>SQL</strong><br />

function &1 in &2.<br />

<strong>SQL</strong>0579 <strong>SQL</strong>CODE -579 <strong>SQL</strong>STATE 38004,<br />

2F004<br />

Explanation: Reading <strong>SQL</strong> data not permitted.<br />

<strong>SQL</strong>0580 <strong>SQL</strong>CODE -580 <strong>SQL</strong>STATE 42625<br />

Explanation: At least one result in C<strong>AS</strong>E expression<br />

must be not NULL.<br />

<strong>SQL</strong>0581 <strong>SQL</strong>CODE -581 <strong>SQL</strong>STATE 42804<br />

Explanation: The results in a C<strong>AS</strong>E expression are not<br />

compatible.<br />

<strong>SQL</strong>0583 <strong>SQL</strong>CODE -583 <strong>SQL</strong>STATE 42845<br />

Explanation: Use of function &1 in &2 not valid.<br />

<strong>SQL</strong>0585 <strong>SQL</strong>CODE -585 <strong>SQL</strong>STATE 42732<br />

Explanation: Library &1 is used incorrectly on the SET<br />

PATH statement<br />

<strong>SQL</strong>0590 <strong>SQL</strong>CODE -590 <strong>SQL</strong>STATE 42734<br />

Explanation: Name &1 specified in &2 not unique.<br />

<strong>SQL</strong>0601 <strong>SQL</strong>CODE -601 <strong>SQL</strong>STATE 42710<br />

Explanation: Object &1 in &2 type *&3 already exists.<br />

Appendix B. <strong>SQL</strong>CODEs and <strong>SQL</strong>STATEs 301


<strong>SQL</strong>0602 <strong>SQL</strong>CODE -602 <strong>SQL</strong>STATE 5<strong>400</strong>8<br />

Explanation: More than 120 columns specified <strong>for</strong><br />

CREATE INDEX.<br />

<strong>SQL</strong>0603 <strong>SQL</strong>CODE -603 <strong>SQL</strong>STATE 23515<br />

Explanation: Unique index cannot be created because<br />

of duplicate keys.<br />

<strong>SQL</strong>0604 <strong>SQL</strong>CODE -604 <strong>SQL</strong>STATE 42611<br />

Explanation: Attributes of column not valid.<br />

<strong>SQL</strong>0607 <strong>SQL</strong>CODE -607 <strong>SQL</strong>STATE 42832<br />

Explanation: Operation not allowed on system table<br />

&1 in &2.<br />

<strong>SQL</strong>0612 <strong>SQL</strong>CODE -612 <strong>SQL</strong>STATE 42711<br />

Explanation: &1 is a duplicate column name.<br />

<strong>SQL</strong>0613 <strong>SQL</strong>CODE -613 <strong>SQL</strong>STATE 5<strong>400</strong>8<br />

Explanation: Primary or unique key constraint too<br />

long.<br />

<strong>SQL</strong>0614 <strong>SQL</strong>CODE -614 <strong>SQL</strong>STATE 5<strong>400</strong>8<br />

Explanation: Length of columns <strong>for</strong> CREATE INDEX<br />

too long.<br />

<strong>SQL</strong>0615 <strong>SQL</strong>CODE -615 <strong>SQL</strong>STATE 55006<br />

Explanation: Object &1 in &2 type *&3 not dropped. It<br />

is in use.<br />

<strong>SQL</strong>0616 <strong>SQL</strong>CODE -616 <strong>SQL</strong>STATE 42893<br />

Explanation: &1 in &2 type &3 cannot be dropped<br />

with RESTRICT.<br />

<strong>SQL</strong>0624 <strong>SQL</strong>CODE -624 <strong>SQL</strong>STATE 42889<br />

Explanation: Table already has primary key.<br />

<strong>SQL</strong>0628 <strong>SQL</strong>CODE -628 <strong>SQL</strong>STATE 42613<br />

Explanation: Clauses are mutually exclusive.<br />

<strong>SQL</strong>0629 <strong>SQL</strong>CODE -629 <strong>SQL</strong>STATE 42834<br />

Explanation: SET NULL not allowed <strong>for</strong> referential<br />

constraint.<br />

302 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5<br />

<strong>SQL</strong>0631 <strong>SQL</strong>CODE -631 <strong>SQL</strong>STATE 5<strong>400</strong>8<br />

Explanation: Foreign key <strong>for</strong> referential constraint too<br />

long.<br />

<strong>SQL</strong>0637 <strong>SQL</strong>CODE -637 <strong>SQL</strong>STATE 42614<br />

Explanation: Duplicate &1 keyword.<br />

<strong>SQL</strong>0642 <strong>SQL</strong>CODE -642 <strong>SQL</strong>STATE 54021<br />

Explanation: Maximum number of constraints<br />

exceeded.<br />

<strong>SQL</strong>0658 <strong>SQL</strong>CODE -658 <strong>SQL</strong>STATE 42917<br />

Explanation: Function cannot be dropped.<br />

<strong>SQL</strong>0666 <strong>SQL</strong>CODE -666 <strong>SQL</strong>STATE 57005<br />

Explanation: Estimated query processing time exceeds<br />

limit.<br />

<strong>SQL</strong>0667 <strong>SQL</strong>CODE -667 <strong>SQL</strong>STATE 23520<br />

Explanation: Foreign key does not match a value in<br />

the parent key.<br />

<strong>SQL</strong>0675 <strong>SQL</strong>CODE -675 <strong>SQL</strong>STATE 42892<br />

Explanation: Specified delete rule not allowed with<br />

existing trigger.<br />

<strong>SQL</strong>0679 <strong>SQL</strong>CODE -679 <strong>SQL</strong>STATE 57006<br />

Explanation: Object &1 in &2 type *&3 not created<br />

due to pending operation.<br />

<strong>SQL</strong>0683 <strong>SQL</strong>CODE -683 <strong>SQL</strong>STATE 42842<br />

Explanation: FOR DATA or CCSID clause not valid<br />

<strong>for</strong> specified type.<br />

<strong>SQL</strong>0707 <strong>SQL</strong>CODE -707 <strong>SQL</strong>STATE 42939<br />

Explanation: Name &1 in &2 not allowed <strong>for</strong> distinct<br />

type.<br />

<strong>SQL</strong>0713 <strong>SQL</strong>CODE -713 <strong>SQL</strong>STATE 42815<br />

Explanation: Host variable <strong>for</strong> &2 is NULL.<br />

<strong>SQL</strong>0724 <strong>SQL</strong>CODE -724 <strong>SQL</strong>STATE 54038<br />

Explanation: Too many cascaded trigger programs.


<strong>SQL</strong>0751 <strong>SQL</strong>CODE -751 <strong>SQL</strong>STATE 42987<br />

Explanation: <strong>SQL</strong> statement &1 not allowed in stored<br />

procedure or trigger.<br />

<strong>SQL</strong>0752 <strong>SQL</strong>CODE -752 <strong>SQL</strong>STATE 0A001<br />

Explanation: Connection cannot be changed. Reason<br />

code is &1.<br />

<strong>SQL</strong>0773 <strong>SQL</strong>CODE -773 <strong>SQL</strong>STATE 20000<br />

Explanation: Case not found <strong>for</strong> C<strong>AS</strong>E statement.<br />

<strong>SQL</strong>0774 <strong>SQL</strong>CODE -774 <strong>SQL</strong>STATE 2D522<br />

Explanation: Statement cannot be executed within a<br />

compound <strong>SQL</strong> statement.<br />

<strong>SQL</strong>0775 <strong>SQL</strong>CODE -775 <strong>SQL</strong>STATE 42910<br />

Explanation: Statement not allowed in a compound<br />

<strong>SQL</strong> statement.<br />

<strong>SQL</strong>0776 <strong>SQL</strong>CODE -776 <strong>SQL</strong>STATE 428D4<br />

Explanation: Cursor &1 specified in FOR statement<br />

not allowed.<br />

<strong>SQL</strong>0777 <strong>SQL</strong>CODE -777 <strong>SQL</strong>STATE 42919<br />

Explanation: Nested compound statements not<br />

allowed.<br />

<strong>SQL</strong>0778 <strong>SQL</strong>CODE -778 <strong>SQL</strong>STATE 428D5<br />

Explanation: End label &1 not same as begin label.<br />

<strong>SQL</strong>0779 <strong>SQL</strong>CODE -779 <strong>SQL</strong>STATE 42736<br />

Explanation: Label &1 specified on LEAVE statement<br />

not valid.<br />

<strong>SQL</strong>0780 <strong>SQL</strong>CODE -780 <strong>SQL</strong>STATE 428D6<br />

Explanation: UNDO specified <strong>for</strong> a handler and<br />

ATOMIC not specified.<br />

<strong>SQL</strong>0781 <strong>SQL</strong>CODE -781 <strong>SQL</strong>STATE 42737<br />

Explanation: Condition &1 specified in handler not<br />

defined.<br />

<strong>SQL</strong>0782 <strong>SQL</strong>CODE -782 <strong>SQL</strong>STATE 428D7<br />

Explanation: Condition value &1 specified in handler<br />

not valid.<br />

<strong>SQL</strong>0783 <strong>SQL</strong>CODE -783 <strong>SQL</strong>STATE 42738<br />

Explanation: Select list <strong>for</strong> cursor &1 in FOR<br />

statement not valid.<br />

<strong>SQL</strong>0784 <strong>SQL</strong>CODE -784 <strong>SQL</strong>STATE 42860<br />

Explanation: Check constraint &1 cannot be dropped.<br />

<strong>SQL</strong>0785 <strong>SQL</strong>CODE -785 <strong>SQL</strong>STATE 428D8<br />

Explanation: Use of <strong>SQL</strong>CODE or <strong>SQL</strong>STATE not<br />

valid.<br />

<strong>SQL</strong>0802 <strong>SQL</strong>CODE -802 <strong>SQL</strong>STATE 22003,<br />

22012, 22023, 22504<br />

Explanation: Data conversion or data mapping error.<br />

<strong>SQL</strong>0803 <strong>SQL</strong>CODE -803 <strong>SQL</strong>STATE 23505<br />

Explanation: Duplicate key value specified.<br />

<strong>SQL</strong>0804 <strong>SQL</strong>CODE -804 <strong>SQL</strong>STATE 07002<br />

Explanation: <strong>SQL</strong>DA not valid.<br />

<strong>SQL</strong>0805 <strong>SQL</strong>CODE -805 <strong>SQL</strong>STATE 51002<br />

Explanation: <strong>SQL</strong> package &1 in &2 not found.<br />

<strong>SQL</strong>0811 <strong>SQL</strong>CODE -811 <strong>SQL</strong>STATE 21000<br />

Explanation: Result of SELECT INTO or subquery<br />

more than one row.<br />

<strong>SQL</strong>0818 <strong>SQL</strong>CODE -818 <strong>SQL</strong>STATE 51003<br />

Explanation: Consistency tokens do not match.<br />

<strong>SQL</strong>0822 <strong>SQL</strong>CODE -822 <strong>SQL</strong>STATE 51004<br />

Explanation: Address in <strong>SQL</strong>DA not valid.<br />

<strong>SQL</strong>0827 <strong>SQL</strong>CODE -827 <strong>SQL</strong>STATE 42862<br />

Explanation: &1 in &2 type *<strong>SQL</strong>PKG cannot be<br />

accessed.<br />

<strong>SQL</strong>0840 <strong>SQL</strong>CODE -840 <strong>SQL</strong>STATE 5<strong>400</strong>4<br />

Explanation: Number of selected items exceeds 8000.<br />

<strong>SQL</strong>0842 <strong>SQL</strong>CODE -842 <strong>SQL</strong>STATE 08002<br />

Explanation: Connection already exists.<br />

Appendix B. <strong>SQL</strong>CODEs and <strong>SQL</strong>STATEs 303


<strong>SQL</strong>0843 <strong>SQL</strong>CODE -843 <strong>SQL</strong>STATE 08003<br />

Explanation: Connection does not exist.<br />

<strong>SQL</strong>0858 <strong>SQL</strong>CODE -858 <strong>SQL</strong>STATE 08501<br />

Explanation: Cannot disconnect relational database<br />

due to LU 6.2 protected conversation.<br />

<strong>SQL</strong>0862 <strong>SQL</strong>CODE -862 <strong>SQL</strong>STATE 55029<br />

Explanation: Local program attempted to connect to a<br />

remote relational database.<br />

<strong>SQL</strong>0871 <strong>SQL</strong>CODE -871 <strong>SQL</strong>STATE 54019<br />

Explanation: Too many CCSID values specified.<br />

<strong>SQL</strong>0900 <strong>SQL</strong>CODE -900 <strong>SQL</strong>STATE 08003<br />

Explanation: Application process not in a connected<br />

state.<br />

<strong>SQL</strong>0901 <strong>SQL</strong>CODE -901 <strong>SQL</strong>STATE 58004<br />

Explanation: <strong>SQL</strong> system error.<br />

<strong>SQL</strong>0904 <strong>SQL</strong>CODE -904 <strong>SQL</strong>STATE 57011<br />

Explanation: Resource limit exceeded.<br />

<strong>SQL</strong>0906 <strong>SQL</strong>CODE -906 <strong>SQL</strong>STATE 24514<br />

Explanation: Operation not per<strong>for</strong>med because of<br />

previous error.<br />

<strong>SQL</strong>0907 <strong>SQL</strong>CODE -907 <strong>SQL</strong>STATE 27000<br />

Explanation: Attempt to change same row twice.<br />

<strong>SQL</strong>0910 <strong>SQL</strong>CODE -910 <strong>SQL</strong>STATE 57007<br />

Explanation: Object &1 in &2 type *&3 has a pending<br />

change.<br />

<strong>SQL</strong>0913 <strong>SQL</strong>CODE -913 <strong>SQL</strong>STATE 57033<br />

Explanation: Row or object &1 in &2 type *&3 in use.<br />

<strong>SQL</strong>0917 <strong>SQL</strong>CODE -917 <strong>SQL</strong>STATE 42969<br />

Explanation: Package not created.<br />

<strong>SQL</strong>0918 <strong>SQL</strong>CODE -918 <strong>SQL</strong>STATE 51021<br />

Explanation: Rollback required.<br />

304 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5<br />

<strong>SQL</strong>0950 <strong>SQL</strong>CODE -950 <strong>SQL</strong>STATE 42705<br />

Explanation: Relational database &1 not in relational<br />

database directory.<br />

<strong>SQL</strong>0951 <strong>SQL</strong>CODE -951 <strong>SQL</strong>STATE 55007<br />

Explanation: Object &1 in &2 not altered. It is in use.<br />

<strong>SQL</strong>0952 <strong>SQL</strong>CODE -952 <strong>SQL</strong>STATE 57014<br />

Explanation: Processing of the <strong>SQL</strong> statement ended<br />

by ENDRDBRQS command.<br />

<strong>SQL</strong>0969 <strong>SQL</strong>CODE -969 <strong>SQL</strong>STATE 58033<br />

Explanation: Unexpected client driver error.<br />

<strong>SQL</strong>0971 <strong>SQL</strong>CODE -971 <strong>SQL</strong>STATE 57011<br />

Explanation: Referential constraint &4 in check<br />

pending state.<br />

<strong>SQL</strong>5001 <strong>SQL</strong>CODE -5001 <strong>SQL</strong>STATE 42703<br />

Explanation: Column qualifier &2 undefined.<br />

<strong>SQL</strong>5002 <strong>SQL</strong>CODE -5002 <strong>SQL</strong>STATE 42812<br />

Explanation: Collection must be specified <strong>for</strong> table &1.<br />

<strong>SQL</strong>5003 <strong>SQL</strong>CODE -5003 <strong>SQL</strong>STATE 42922<br />

Explanation: Cannot per<strong>for</strong>m operation under<br />

commitment control.<br />

<strong>SQL</strong>5005 <strong>SQL</strong>CODE -5005 <strong>SQL</strong>STATE 42815<br />

Explanation: Operator &4 not consistent with<br />

operands.<br />

<strong>SQL</strong>5012 <strong>SQL</strong>CODE -5012 <strong>SQL</strong>STATE 42618<br />

Explanation: Host variable not a numeric with zero<br />

scale.<br />

<strong>SQL</strong>5016 <strong>SQL</strong>CODE -5016 <strong>SQL</strong>STATE 42833<br />

Explanation: Object name &1 not valid <strong>for</strong> naming<br />

option.<br />

<strong>SQL</strong>5021 <strong>SQL</strong>CODE -5021 <strong>SQL</strong>STATE 42930<br />

Explanation: FOR UPDATE OF column &1 also in<br />

ORDER BY.


<strong>SQL</strong>5023 <strong>SQL</strong>CODE -5023 <strong>SQL</strong>STATE 26510<br />

Explanation: Duplicate statement name in DECLARE<br />

CURSOR.<br />

<strong>SQL</strong>5024 <strong>SQL</strong>CODE -5024 <strong>SQL</strong>STATE 42618<br />

Explanation: Host variable &1 not character.<br />

<strong>SQL</strong>5047 <strong>SQL</strong>CODE -5047 <strong>SQL</strong>STATE 42616<br />

Explanation: Error processing SRTSEQ or LANGID<br />

parameter.<br />

<strong>SQL</strong>5051 <strong>SQL</strong>CODE -5051 <strong>SQL</strong>STATE 42875<br />

Explanation: Incorrect qualifier.<br />

<strong>SQL</strong>7001 <strong>SQL</strong>CODE -7001 <strong>SQL</strong>STATE 42858<br />

Explanation: File &1 in &2 not database file.<br />

<strong>SQL</strong>7002 <strong>SQL</strong>CODE -7002 <strong>SQL</strong>STATE 42847<br />

Explanation: Override parameter not valid.<br />

<strong>SQL</strong>7003 <strong>SQL</strong>CODE -7003 <strong>SQL</strong>STATE 42857<br />

Explanation: File &1 in &2 has more than one <strong>for</strong>mat.<br />

<strong>SQL</strong>7006 <strong>SQL</strong>CODE -7006 <strong>SQL</strong>STATE 55018<br />

Explanation: Cannot drop collection &1.<br />

<strong>SQL</strong>7007 <strong>SQL</strong>CODE -7007 <strong>SQL</strong>STATE 51009<br />

Explanation: COMMIT or ROLLBACK not valid.<br />

<strong>SQL</strong>7008 <strong>SQL</strong>CODE -7008 <strong>SQL</strong>STATE 55019<br />

Explanation: &1 in &2 not valid <strong>for</strong> operation.<br />

<strong>SQL</strong>7010 <strong>SQL</strong>CODE -7010 <strong>SQL</strong>STATE 42850<br />

Explanation: Logical file &1 in &2 not valid <strong>for</strong><br />

CREATE VIEW.<br />

<strong>SQL</strong>7011 <strong>SQL</strong>CODE -7011 <strong>SQL</strong>STATE 42851<br />

Explanation: &1 in &2 not table, view, or physical file.<br />

<strong>SQL</strong>7017 <strong>SQL</strong>CODE -7017 <strong>SQL</strong>STATE 42971<br />

Explanation: Commitment control is already active to<br />

a DDM target.<br />

<strong>SQL</strong>7018 <strong>SQL</strong>CODE -7018 <strong>SQL</strong>STATE 42970<br />

Explanation: COMMIT HOLD or ROLLBACK HOLD<br />

not allowed.<br />

<strong>SQL</strong>7021 <strong>SQL</strong>CODE -7021 <strong>SQL</strong>STATE 57043<br />

Explanation: Local program attempting to run on<br />

application server.<br />

<strong>SQL</strong>7022 <strong>SQL</strong>CODE -7022 <strong>SQL</strong>STATE 42977<br />

Explanation: User &1 not the same as current user &2<br />

<strong>for</strong> connect to local relational database.<br />

<strong>SQL</strong>7024 <strong>SQL</strong>CODE -7024 <strong>SQL</strong>STATE 42876<br />

Explanation: Index cannot be created because of<br />

CCSID incompatibility.<br />

<strong>SQL</strong>7026 <strong>SQL</strong>CODE -7026 <strong>SQL</strong>STATE 42896<br />

Explanation: Auxiliary storage pool not found.<br />

<strong>SQL</strong>7027 <strong>SQL</strong>CODE -7027 <strong>SQL</strong>STATE 42984<br />

Explanation: Unable to grant to a view.<br />

<strong>SQL</strong>7028 <strong>SQL</strong>CODE -7028 <strong>SQL</strong>STATE 42944<br />

Explanation: Unable to CHGOBJOWN <strong>for</strong> primary<br />

group.<br />

<strong>SQL</strong>7029 <strong>SQL</strong>CODE -7029 <strong>SQL</strong>STATE 428B8<br />

Explanation: New name &3 is not valid.<br />

<strong>SQL</strong>7031 <strong>SQL</strong>CODE -7031 <strong>SQL</strong>STATE 54044<br />

Explanation: Sort sequence table &1 too long.<br />

<strong>SQL</strong>7032 <strong>SQL</strong>CODE -7032 <strong>SQL</strong>STATE 42904<br />

Explanation: <strong>SQL</strong> procedure &1 in &2 not created.<br />

<strong>SQL</strong>7033 <strong>SQL</strong>CODE -7033 <strong>SQL</strong>STATE 42923<br />

Explanation: Alias name &1 in &2 not allowed.<br />

<strong>SQL</strong>7034 <strong>SQL</strong>CODE -7034 <strong>SQL</strong>STATE 42926<br />

Explanation: LOB locators are not allowed with<br />

COMMIT(*NONE).<br />

<strong>SQL</strong>7037 <strong>SQL</strong>CODE -7037 <strong>SQL</strong>STATE 42835<br />

Explanation: Data in a distributed file &1 in &2<br />

cannot be redistributed.<br />

Appendix B. <strong>SQL</strong>CODEs and <strong>SQL</strong>STATEs 305


<strong>SQL</strong>7038 <strong>SQL</strong>CODE -7038 <strong>SQL</strong>STATE 429B7<br />

Explanation: Delete cascade not valid <strong>for</strong> &1 in &2.<br />

<strong>SQL</strong>7941 <strong>SQL</strong>CODE -7941 <strong>SQL</strong>STATE 42981<br />

Explanation: Application process not at commit<br />

boundary.<br />

<strong>SQL</strong>9012 <strong>SQL</strong>CODE -9012 <strong>SQL</strong>STATE 42968<br />

Explanation: <strong>DB2</strong> <strong>UDB</strong> Query Manager and <strong>SQL</strong><br />

Development Kit not available.<br />

SQ30000 <strong>SQL</strong>CODE -30000 <strong>SQL</strong>STATE 58008<br />

Explanation: Distributed Relational Database<br />

Architecture (DRDA) protocol error.<br />

SQ30001 <strong>SQL</strong>CODE -30001 <strong>SQL</strong>STATE 57042<br />

Explanation: Call to distributed <strong>SQL</strong> program not<br />

allowed.<br />

SQ30020 <strong>SQL</strong>CODE -30020 <strong>SQL</strong>STATE 58009<br />

Explanation: Distributed Relational Database<br />

Architecture (DRDA) protocol error.<br />

SQ30021 <strong>SQL</strong>CODE -30021 <strong>SQL</strong>STATE 58010<br />

Explanation: Distributed relational database not<br />

supported by the remote system.<br />

SQ30040 <strong>SQL</strong>CODE -30040 <strong>SQL</strong>STATE 57012<br />

Explanation: DDM resource &2 at relational database<br />

&1 not available.<br />

SQ30041 <strong>SQL</strong>CODE -30041 <strong>SQL</strong>STATE 57013<br />

Explanation: DDM resources at relational database &1<br />

not available.<br />

SQ30050 <strong>SQL</strong>CODE -30050 <strong>SQL</strong>STATE 58011<br />

Explanation: DDM command &1 is not valid while<br />

bind process is in progress.<br />

SQ30051 <strong>SQL</strong>CODE -30051 <strong>SQL</strong>STATE 58012<br />

Explanation: Bind process <strong>for</strong> specified package name<br />

and consistency token not active.<br />

SQ30052 <strong>SQL</strong>CODE -30052 <strong>SQL</strong>STATE 42932<br />

Explanation: Program preparation assumptions not<br />

correct.<br />

306 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5<br />

SQ30053 <strong>SQL</strong>CODE -30053 <strong>SQL</strong>STATE 42506<br />

Explanation: Not authorized to create package <strong>for</strong><br />

owner &1.<br />

SQ30060 <strong>SQL</strong>CODE -30060 <strong>SQL</strong>STATE 08004<br />

Explanation: User not authorized to relational<br />

database &1.<br />

SQ30061 <strong>SQL</strong>CODE -30061 <strong>SQL</strong>STATE 08004<br />

Explanation: Relational database &1 not found.<br />

SQ30070 <strong>SQL</strong>CODE -30070 <strong>SQL</strong>STATE 58014<br />

Explanation: Distributed Data Management (DDM)<br />

command &1 not supported.<br />

SQ30071 <strong>SQL</strong>CODE -30071 <strong>SQL</strong>STATE 58015<br />

Explanation: Distributed Data Management (DDM)<br />

object &1 not supported.<br />

SQ30072 <strong>SQL</strong>CODE -30072 <strong>SQL</strong>STATE 58016<br />

Explanation: Distributed Data Management (DDM)<br />

parameter &1 not supported.<br />

SQ30073 <strong>SQL</strong>CODE -30073 <strong>SQL</strong>STATE 58017<br />

Explanation: Distributed Data Management (DDM)<br />

parameter value &1 not supported.<br />

SQ30074 <strong>SQL</strong>CODE -30074 <strong>SQL</strong>STATE 58018<br />

Explanation: Distributed Data Management (DDM)<br />

reply message &1 not supported.<br />

SQ30080 <strong>SQL</strong>CODE -30080 <strong>SQL</strong>STATE 08001<br />

Explanation: Communication error occurred during<br />

distributed database processing.<br />

SQ30089 <strong>SQL</strong>CODE -30089 <strong>SQL</strong>STATE 08001<br />

Explanation: Communication error occurred during<br />

<strong>DB2</strong> Multisystem processing.<br />

SQ30090 <strong>SQL</strong>CODE -30090 <strong>SQL</strong>STATE 25000,<br />

2D528, 2D529<br />

Explanation: Change request not valid <strong>for</strong> read-only<br />

application server.


Appendix C. <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> CL Command Descriptions<br />

This appendix contains the syntax diagrams referred to and used in this book and<br />

the <strong>SQL</strong> Reference book.<br />

CRT<strong>SQL</strong>PKG (Create Structured Query Language Package) Command<br />

Job: B,I Pgm: B,I REXX: B,I Exec<br />

►► CRT<strong>SQL</strong>PKG<br />

►<br />

►<br />

►<br />

►<br />

►<br />

►<br />

*LIBL/<br />

PGM( program-name )<br />

*CURLIB/<br />

library-name/<br />

*PGM<br />

RDB( relational-database-name )<br />

*CURRENT<br />

USER( user-name )<br />

10<br />

GENLVL( severity-level )<br />

*PGM<br />

DFTRDBCOL(*NONE )<br />

collection-name<br />

(1)<br />

*NONE<br />

P<strong>AS</strong>SWORD( password )<br />

*YES<br />

REPLACE(*NO )<br />

*LIBL/ QSYSPRT<br />

PRTFILE( printer-file-name )<br />

*CURLIB/<br />

library-name/<br />

*PGM<br />

OBJTYPE(*SRVPGM )<br />

© Copyright IBM Corp. 2000 307<br />

►<br />

►<br />

►<br />

►<br />

►<br />

►<br />


CRT<strong>SQL</strong>PKG<br />

►<br />

►<br />

*ALL<br />

(2)<br />

MODULE( ▼ module-name )<br />

*PGMTXT<br />

TEXT(*BLANK )<br />

'description'<br />

Notes:<br />

1 All parameters preceding this point can be specified in positional <strong>for</strong>m.<br />

2 A maximum of 256 modules may be specified.<br />

Purpose:<br />

The Create Structured Query Language Package (CRT<strong>SQL</strong>PKG) command is used<br />

to create (or re-create) an <strong>SQL</strong> package on a relational database from an existing<br />

distributed <strong>SQL</strong> program. A distributed <strong>SQL</strong> program is a program created by<br />

specifying the RDB parameter on a CRT<strong>SQL</strong>xxx (where xxx = C, CI, CBL, CBLI,<br />

FTN, PLI, or RPG or RPGI) command.<br />

Parameters:<br />

PGM<br />

Specifies the qualified name of the program <strong>for</strong> which the <strong>SQL</strong> package is<br />

being created. The program must be a distributed <strong>SQL</strong> program.<br />

The name of the program can be qualified by one of the following library<br />

values:<br />

*LIBL: All libraries in the job’s library list are searched until the first match<br />

is found.<br />

*CURLIB: The current library <strong>for</strong> the job is searched. If no library is<br />

specified as the current library <strong>for</strong> the job, the QGPL library is used.<br />

library-name: Specify the name of the library to be searched.<br />

program-name: Specify the name of the program <strong>for</strong> which the package is being<br />

created.<br />

RDB<br />

Specifies the name of the relational database where the <strong>SQL</strong> package is being<br />

created.<br />

308 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5<br />

*PGM: The relational database name specified <strong>for</strong> the <strong>SQL</strong> program is used.<br />

The relational database name is specified on the RDB parameter of the<br />

distributed <strong>SQL</strong> program.<br />

relational-database-name: Specify the name of the relational database where the<br />

<strong>SQL</strong> package is to be created. Use the Work with Relational Database <strong>Directory</strong><br />

Entry (WRKRDBDIRE) command to show the relational database names that<br />

are valid on this parameter.<br />

►<br />

►◄


USER<br />

Specifies the user name sent to the remote system when starting the<br />

conversation.<br />

*CURRENT: The user name associated with the current job is used.<br />

user-name: Specify the user name being used <strong>for</strong> the application server job.<br />

P<strong>AS</strong>SWORD<br />

Specifies the password to be used on the remote system.<br />

*NONE: No password is sent. If this value is specified, USER(*CURRENT)<br />

must also be specified.<br />

password: Specify the password of the user name specified on the USER<br />

parameter.<br />

GENLVL<br />

Specifies the maximum severity level allowed <strong>for</strong> errors detected during <strong>SQL</strong><br />

package creation. If errors occur at a level that exceeds the specified level, the<br />

<strong>SQL</strong> package is not created.<br />

10: The default severity-level is 10.<br />

CRT<strong>SQL</strong>PKG<br />

severity-level: Specify the maximum severity level. Valid values range from 0<br />

through 40.<br />

REPLACE<br />

Specifies whether an existing package is being replaced with the new package.<br />

More in<strong>for</strong>mation on this parameter is in Appendix A, ″Expanded Parameter<br />

Descriptions″ in the CL Reference book.<br />

*YES: An existing <strong>SQL</strong> package of the same name is replaced by the new <strong>SQL</strong><br />

package.<br />

*NO: An existing <strong>SQL</strong> package of the same name is not replaced; a new <strong>SQL</strong><br />

package is not created if the package already exists in the specified library.<br />

DFTRDBCOL<br />

Specifies the collection name to be used <strong>for</strong> unqualified names of tables, views,<br />

indexes, and <strong>SQL</strong> packages. This parameter applies only to static <strong>SQL</strong><br />

statements in the package.<br />

*PGM: The collection name specified <strong>for</strong> the <strong>SQL</strong> program is used. The default<br />

relational database collection name is specified on the DFTRDBCOL parameter<br />

of the distributed <strong>SQL</strong> program.<br />

*NONE: Unqualified names <strong>for</strong> tables, views, indexes, and <strong>SQL</strong> packages use<br />

the search conventions specified on the OPTION parameter of the CRT<strong>SQL</strong>xxx<br />

command used to create the program.<br />

collection-name: Specify the collection name that is used <strong>for</strong> unqualified tables,<br />

views, indexes, and <strong>SQL</strong> packages.<br />

PRTFILE<br />

Specifies the qualified name of the printer device file to which the create <strong>SQL</strong><br />

package error listing is directed. If no errors are detected during the creation of<br />

the <strong>SQL</strong> package, no listing is produced.<br />

Appendix C. <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> CL Command Descriptions 309


CRT<strong>SQL</strong>PKG<br />

The name of the printer file can be qualified by one of the following library<br />

values:<br />

*LIBL: All libraries in the job’s library list are searched until the first match<br />

is found.<br />

*CURLIB: The current library <strong>for</strong> the job is searched. If no library is<br />

specified as the current library <strong>for</strong> the job, the QGPL library is used.<br />

library-name: Specify the name of the library to be searched.<br />

QSYSPRT: If a file name is not specified, the create <strong>SQL</strong> package error listing<br />

is directed to the IBM-supplied printer file QSYSPRT.<br />

printer-file-name: Specify the name of the printer device file to which the create<br />

<strong>SQL</strong> package error listing is directed.<br />

OBJTYPE<br />

Specifies the type of program <strong>for</strong> which an <strong>SQL</strong> package is created.<br />

*PGM: Create an <strong>SQL</strong> package from the program specified on the PGM<br />

parameter.<br />

*SRVPGM: Create an <strong>SQL</strong> package from the service program specified on the<br />

PGM parameter.<br />

MODULE<br />

Specifies a list of modules in a bound program.<br />

*ALL: An <strong>SQL</strong> package is created <strong>for</strong> each module in the program. An error<br />

message is sent if none of the modules in the program contain <strong>SQL</strong> statements<br />

or none of the modules is a distributed module.<br />

Note: CRT<strong>SQL</strong>PKG can process programs that do not contain more than 1024<br />

modules.<br />

module-name: Specify the names of up to 256 modules in the program <strong>for</strong> which<br />

an <strong>SQL</strong> package is to be created. If more than 256 modules exist that need to<br />

have an <strong>SQL</strong> package created, multiple CRT<strong>SQL</strong>PKG commands must be used.<br />

Duplicate module names in the same program are allowed. This command<br />

looks at each module in the program and if *ALL or the module name is<br />

specified on the MODULE parameter, processing continues to determine<br />

whether an <strong>SQL</strong> package should be created. If the module is created using <strong>SQL</strong><br />

and the RDB parameter is specified on the precompile command, an <strong>SQL</strong><br />

package is created <strong>for</strong> the module. The <strong>SQL</strong> package is associated with the<br />

module of the bound program.<br />

TEXT<br />

Specifies text that briefly describes the <strong>SQL</strong> package and its function.<br />

*PGMTXT: The text from the program <strong>for</strong> which the <strong>SQL</strong> package is being<br />

created is used.<br />

*BLANK: No text is specified.<br />

’description’: Specify a maximum of 50 characters of text, enclosed in<br />

apostrophes.<br />

Example:<br />

310 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


CRT<strong>SQL</strong>PKG PAYROLL RDB(SYSTEMA)<br />

TEXT('Payroll Program')<br />

This command creates an <strong>SQL</strong> package from the distributed <strong>SQL</strong> program<br />

PAYROLL on relational database SYSTEMA.<br />

DLT<strong>SQL</strong>PKG (Delete Structured Query Language Package) Command<br />

Job: B,I Pgm: B,I REXX: B,I Exec<br />

►► DLT<strong>SQL</strong>PKG ►<br />

►<br />

*LIBL/ (1)<br />

<strong>SQL</strong>PKG( <strong>SQL</strong>-package-name )<br />

*CURLIB/ generic*-<strong>SQL</strong>-package name<br />

*USRLIBL/<br />

*ALL/<br />

*ALLUSR/<br />

library-name/<br />

Notes:<br />

1 All parameters preceding this point can be specified in positional <strong>for</strong>m.<br />

Purpose:<br />

CRT<strong>SQL</strong>PKG<br />

The Delete Structured Query Language Package (DLT<strong>SQL</strong>PKG) command is used<br />

to delete one or more <strong>SQL</strong> packages.<br />

DLT<strong>SQL</strong>PKG is a local command and must be used on the <strong>AS</strong>/<strong>400</strong> system where<br />

the <strong>SQL</strong> package being deleted is located.<br />

To delete an <strong>SQL</strong> package on a remote system that is also an <strong>AS</strong>/<strong>400</strong> system, use<br />

the Submit Remote Command (SBMRMTCMD) command to run the DLT<strong>SQL</strong>PKG<br />

command on the remote system.<br />

The user can do the following to delete an <strong>SQL</strong> package from a remote system that<br />

is not an <strong>AS</strong>/<strong>400</strong> system:<br />

v Use interactive <strong>SQL</strong> to run the CONNECT and DROP PACKAGE operations.<br />

v Sign on the remote system and use a command local to that system.<br />

v Create and run an <strong>SQL</strong> program that contains a DROP PACKAGE <strong>SQL</strong><br />

statement.<br />

Parameters:<br />

<strong>SQL</strong>PKG<br />

Specifies the qualified name of the <strong>SQL</strong> package being deleted. A specific or<br />

generic <strong>SQL</strong> package name can be specified.<br />

The name of the <strong>SQL</strong> Package can be qualified by one of the following library<br />

values:<br />

*LIBL: All libraries in the job’s library list are searched until the first match is<br />

found.<br />

Appendix C. <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> CL Command Descriptions 311<br />

►◄


DLT<strong>SQL</strong>PKG<br />

*CURLIB: The current library <strong>for</strong> the job is searched. If no library is specified<br />

as the current library <strong>for</strong> the job, the QGPL library is used.<br />

*USRLIBL: Only the libraries in the user portion of the job’s library list are<br />

searched.<br />

*ALL: All libraries in the system, including QSYS, are searched.<br />

*ALLUSR: All user libraries are searched. All libraries with names that do not<br />

begin with the letter Q are searched except <strong>for</strong> the following:<br />

#CGULIB #DFULIB #RPGLIB #SEULIB<br />

#COBLIB #DSULIB #SDALIB<br />

Although the following Qxxx libraries are provided by IBM, they typically<br />

contain user data that changes frequently. There<strong>for</strong>e, these libraries are<br />

considered user libraries and are also searched:<br />

QDSNX QRCL QUSRBRM QUSRSYS<br />

QGPL QS36F QUSRIJS QUSRVxRxMx<br />

QGPL38 QUSER38 QUSRINFSKR<br />

QPFRDATA QUSRADSM QUSRRDARS<br />

Note: A different library name, of the <strong>for</strong>m QUSRVxRxMx, can be created by<br />

the user <strong>for</strong> each release that IBM supports. VxRxMx is the version, release,<br />

and modification level of the library.<br />

library-name: Specify the name of the library to be searched.<br />

<strong>SQL</strong>-package-name: Specify the name of the <strong>SQL</strong> package being deleted.<br />

generic*-<strong>SQL</strong>-package-name: Specify the generic name of the <strong>SQL</strong> package to be<br />

deleted. A generic name is a character string of one or more characters<br />

followed by an asterisk (*); <strong>for</strong> example, ABC*. If a generic name is specified,<br />

all <strong>SQL</strong> packages with names that begin with the generic name, and <strong>for</strong> which<br />

the user has authority, are deleted. If an asterisk is not included with the<br />

generic (prefix) name, the system assumes it to be the complete <strong>SQL</strong> package<br />

name.<br />

Example:<br />

DLT<strong>SQL</strong>PKG <strong>SQL</strong>PKG(JONES)<br />

This command deletes the <strong>SQL</strong> package JONES.<br />

RUN<strong>SQL</strong>STM (Run Structured Query Language Statement) Command<br />

Job: B,I Pgm: B,I REXX: B,I Exec<br />

►► RUN<strong>SQL</strong>STM<br />

312 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5<br />

*LIBL/<br />

SRCFILE ( source-file-name )<br />

*CURLIB/<br />

library-name/<br />


► SRCMBR ( source-file-member-name )<br />

►<br />

►<br />

►<br />

►<br />

►<br />

*SYS<br />

NAMING (*<strong>SQL</strong> )<br />

*OPTIMIZE<br />

ALWCPYDTA (*YES )<br />

*NO<br />

10<br />

ERRLVL ( severity-level )<br />

*JOB<br />

DATSEP ('/' )<br />

'.'<br />

','<br />

'-'<br />

''<br />

*BLANK<br />

*JOB<br />

TIMSEP (':' )<br />

'.'<br />

','<br />

''<br />

*BLANK<br />

(1)<br />

*RUN<br />

PROCESS(*SYN )<br />

*UR<br />

*CHG<br />

COMMIT (*ALL )<br />

*RS<br />

*CS<br />

*NONE<br />

*NC<br />

*RR<br />

*ALLREAD<br />

ALWBLK (*NONE )<br />

*READ<br />

*JOB<br />

DATFMT (*USA )<br />

*ISO<br />

*EUR<br />

*JIS<br />

*MDY<br />

*DMY<br />

*YMD<br />

*JUL<br />

*HMS<br />

TIMFMT (*USA )<br />

*ISO<br />

*EUR<br />

*JIS<br />

*SYSVAL<br />

*JOB<br />

DECMPT (*PERIOD )<br />

*COMMA<br />

RUN<strong>SQL</strong>STM<br />

Appendix C. <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> CL Command Descriptions 313<br />

►<br />

►<br />

►<br />

►<br />

►<br />


RUN<strong>SQL</strong>STM<br />

►<br />

►<br />

►<br />

►<br />

►<br />

*JOB<br />

SRTSEQ (*LANGIDUNQ )<br />

*LANGIDSHR<br />

*HEX<br />

*LIBL/<br />

table-name<br />

*CURLIB/<br />

library-name/<br />

*JOB<br />

LANGID ( language-identifier )<br />

*NONE<br />

DFTRDBCOL ( collection-name )<br />

*NOFLAG<br />

SAAFLAG (*FLAG )<br />

*LIBL/ QSYSPRT<br />

PRTFILE ( printer-file-name )<br />

*CURLIB/<br />

library-name/<br />

<strong>SQL</strong>-procedure-parameters:<br />

►<br />

►<br />

►<br />

*CURRENT<br />

TGTRLS (VxRxMx )<br />

*NONE<br />

OUTPUT (*PRINT )<br />

*NAMING<br />

USRPRF (*OWNER )<br />

*USER<br />

*NO<br />

DLYPRP (*YES )<br />

314 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5<br />

*NONE<br />

FLAGSTD (*ANS )<br />

*ENDACTGRP<br />

CLO<strong>SQL</strong>CSR (*ENDMOD )<br />

*NONE<br />

DBGVIEW (*STMT )<br />

*LIST<br />

*USER<br />

DYNUSRPRF (*OWNER )<br />

►<br />

►<br />

►<br />

►<br />

►◄<br />

►<br />

►<br />


Notes:<br />

1 All parameters preceding this point can be specified in positional <strong>for</strong>m.<br />

Purpose:<br />

The Run Structured Query Language Statement (RUN<strong>SQL</strong>STM) command<br />

processes a source file of <strong>SQL</strong> statements.<br />

RUN<strong>SQL</strong>STM<br />

Parameters:<br />

SRCFILE<br />

Specifies the qualified name of the source file that contains the <strong>SQL</strong> statements<br />

to be run.<br />

The name of the source file can be qualified by one of the following library<br />

values:<br />

*LIBL: All libraries in the job’s library list are searched until the first match<br />

is found.<br />

*CURLIB: The current library <strong>for</strong> the job is searched. If no library is<br />

specified as the current library <strong>for</strong> the job, the QGPL library is used.<br />

library-name: Specify the name of the library to be searched.<br />

source-file-name: Specify the name of the source file that contains the <strong>SQL</strong><br />

statements to be run. The source file can be a database file or an inline data<br />

file.<br />

SRCMBR<br />

Specifies the name of the source file member that contains the <strong>SQL</strong> statements<br />

to be run.<br />

COMMIT<br />

Specifies whether <strong>SQL</strong> statements in the source file are run under commitment<br />

control.<br />

*CHG or *UR: Specifies the objects referred to in <strong>SQL</strong> ALTER, CALL,<br />

COMMENT ON, CREATE, DROP, GRANT, LABEL ON, RENAME, and<br />

REVOKE statements and the rows updated, deleted, and inserted are locked<br />

until the end of the unit of work (transaction). Uncommitted changes in other<br />

jobs can be seen.<br />

*ALL or *RS: Specifies the objects referred to in <strong>SQL</strong> ALTER, CALL,<br />

COMMENT ON, CREATE, DROP, GRANT, LABEL ON, RENAME, and<br />

REVOKE statements and the rows selected, updated, deleted, and inserted are<br />

locked until the end of the unit of work (transaction). Uncommitted changes in<br />

other jobs cannot be seen.<br />

*CS: Specifies the objects referred to in <strong>SQL</strong> ALTER, CALL, COMMENT ON,<br />

CREATE, DROP, GRANT, LABEL ON, RENAME, and REVOKE statements and<br />

the rows updated, deleted, and inserted are locked until the end of the unit of<br />

work (transaction). A row that is selected, but not updated, is locked until the<br />

next row is selected. Uncommitted changes in other jobs cannot be seen.<br />

*NONE or *NC: Specifies that commitment control is not used. Uncommitted<br />

changes in other jobs can be seen. If the <strong>SQL</strong> DROP COLLECTION statement<br />

is included in the program, *NONE or *NC must be used. If a relational<br />

Appendix C. <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> CL Command Descriptions 315


RUN<strong>SQL</strong>STM<br />

database is specified on the RDB parameter and the relational database is on a<br />

system that is not on an <strong>AS</strong>/<strong>400</strong>, *NONE or *NC cannot be specified.<br />

*RR: Specifies the objects referred to in <strong>SQL</strong> ALTER, CALL, COMMENT ON,<br />

CREATE, DROP, GRANT, LABEL ON, RENAME, and REVOKE statements and<br />

the rows selected, updated, deleted, and inserted are locked until the end of<br />

the unit of work (transaction). Uncommitted changes in other jobs cannot be<br />

seen. All tables referred to in SELECT, UPDATE, DELETE, and INSERT<br />

statements are locked exclusively until the end of the unit of work<br />

(transaction).<br />

NAMING<br />

Specifies the naming convention used <strong>for</strong> naming objects in <strong>SQL</strong> statements.<br />

*SYS: The system naming convention (library-name/file-name) is used.<br />

*<strong>SQL</strong>: The <strong>SQL</strong> naming convention (collection-name.table-name) is used.<br />

PROCESS<br />

Specifies whether <strong>SQL</strong> statements in the source file member are executed or<br />

syntax-checked only.<br />

*RUN: Statement are syntax-checked and run.<br />

*SYN: Statements are syntax-checked only.<br />

ALWCPYDTA<br />

Specifies whether a copy of the data can be used in a SELECT statement.<br />

*OPTIMIZE: The system determines whether to use the data retrieved directly<br />

from the database or to use a copy of the data. The decision is based on which<br />

method provides the best per<strong>for</strong>mance. If COMMIT is *CHG or *CS and<br />

ALWBLK is not *ALLREAD, or if COMMIT is *ALL or *RR, then a copy of the<br />

data is used only when it is necessary to run a query.<br />

*YES: A copy of the data is used only when necessary.<br />

*NO: A copy of the data is not used. If temporary copy of the data is required<br />

to per<strong>for</strong>m the query, an error message is returned.<br />

ALWBLK<br />

Specifies whether the database manager can use record blocking, and the<br />

extent to which blocking can be used <strong>for</strong> read-only cursors.<br />

316 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5<br />

*ALLREAD: Rows are blocked <strong>for</strong> read-only cursors if *NONE or *CHG is<br />

specified on the COMMIT parameter. All cursors in a program that are not<br />

explicitly able to be updated are opened <strong>for</strong> read-only processing even though<br />

EXECUTE or EXECUTE IMMEDIATE statements may be in the program.<br />

Specifying *ALLREAD:<br />

v Allows record blocking under commitment control level *CHG in addition to<br />

the blocking allowed <strong>for</strong> *READ.<br />

v Can improve the per<strong>for</strong>mance of almost all read-only cursors in programs,<br />

but limits queries in the following ways:<br />

– The Rollback (ROLLBACK) command, a ROLLBACK statement in host<br />

languages, or the ROLLBACK HOLD <strong>SQL</strong> statement does not reposition a<br />

read-only cursor when *ALLREAD is specified.


– Dynamic running of a positioned UPDATE or DELETE statement (<strong>for</strong><br />

example, using EXECUTE IMMEDIATE), cannot be used to update a row<br />

in a cursor unless the DECLARE statement <strong>for</strong> the cursor includes the<br />

FOR UPDATE clause.<br />

*NONE: Rows are not blocked <strong>for</strong> retrieval of data <strong>for</strong> cursors.<br />

Specifying *NONE:<br />

v Guarantees that the data retrieved is current.<br />

v May reduce the amount of time required to retrieve the first row of data <strong>for</strong><br />

a query.<br />

v Stops the database manager from retrieving a block of data rows that is not<br />

used by the program when only the first few rows of a query are retrieved<br />

be<strong>for</strong>e the query is closed.<br />

v Can degrade the overall per<strong>for</strong>mance of a query that retrieves a large<br />

number of rows.<br />

*READ: Records are blocked <strong>for</strong> read-only retrieval of data <strong>for</strong> cursors when:<br />

v *NONE is specified on the COMMIT parameter, which indicates that<br />

commitment control is not used.<br />

v The cursor is declared with a FOR FETCH ONLY clause or there are no<br />

dynamic statements that could run a positioned UPDATE or DELETE<br />

statement <strong>for</strong> the cursor.<br />

Specifying *READ can improve the overall per<strong>for</strong>mance of queries that meet<br />

the above conditions and retrieve a large number of records.<br />

ERRLVL<br />

Specifies whether the processing is successful, based on the severity of the<br />

messages generated by the processing of the <strong>SQL</strong> statements. If errors that are<br />

greater than the value specified on this parameter occur during processing, no<br />

more statements are processed and the statements are rolled back if they are<br />

running under commitment control.<br />

10: Statement processing is stopped when error messages with a severity level<br />

greater than 10 are received.<br />

severity-level: Specify the severity level to be used.<br />

DATFMT<br />

Specifies the <strong>for</strong>mat used when accessing date result columns. For input date<br />

strings, the specified value is used to determine whether the date is specified<br />

in a valid <strong>for</strong>mat.<br />

Note: An input date string that uses the <strong>for</strong>mat *USA, *ISO, *EUR, or *JIS is<br />

always valid.<br />

*JOB: The <strong>for</strong>mat specified <strong>for</strong> the job is used. Use the Display Job (DSPJOB)<br />

command to determine the current date <strong>for</strong>mat <strong>for</strong> the job.<br />

*USA: The United States date <strong>for</strong>mat (mm/dd/yyyy) is used.<br />

RUN<strong>SQL</strong>STM<br />

*ISO: The International Organization <strong>for</strong> Standardization (ISO) date <strong>for</strong>mat<br />

(yyyy-mm-dd) is used.<br />

Appendix C. <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> CL Command Descriptions 317


RUN<strong>SQL</strong>STM<br />

*EUR: The European date <strong>for</strong>mat (dd.mm.yyyy) is used.<br />

*JIS: The Japanese Industrial Standard date <strong>for</strong>mat (yyyy-mm-dd) is used.<br />

*MDY: The date <strong>for</strong>mat (mm/dd/yy) is used.<br />

*DMY: The date <strong>for</strong>mat (dd/mm/yy) is used.<br />

*YMD: The date <strong>for</strong>mat (yy/mm/dd) is used.<br />

*JUL: The Julian date <strong>for</strong>mat (yy/ddd) is used.<br />

DATSEP<br />

Specifies the separator used when accessing date result columns.<br />

Note: This parameter applies only when *JOB, *MDY, *DMY, *YMD, or *JUL is<br />

specified on the DATFMT parameter.<br />

*JOB: The date separator specified <strong>for</strong> the job is used. Use the Display Job<br />

(DSPJOB) command to determine the current value <strong>for</strong> the job.<br />

’/’: A slash (/) is used.<br />

’.’: A period (.) is used.<br />

’,’: A comma (,) is used.<br />

’-’: A dash (-) is used.<br />

’’:A blank ( ) is used.<br />

*BLANK: A blank ( ) is used.<br />

TIMFMT<br />

Specifies the <strong>for</strong>mat used when accessing time result columns. For input time<br />

strings, the specified value is used to determine whether the time is specified<br />

in a valid <strong>for</strong>mat.<br />

Note: An input date string that uses the <strong>for</strong>mat *USA, *ISO, *EUR, or *JIS is<br />

always valid.<br />

*HMS: The hh:mm:ss <strong>for</strong>mat is used.<br />

*USA: The United States time <strong>for</strong>mat hh:mm xx is used, where xx is AM or<br />

PM.<br />

*ISO: The International Organization <strong>for</strong> Standardization (ISO) time <strong>for</strong>mat<br />

hh.mm.ss is used.<br />

*EUR: The European time <strong>for</strong>mat hh.mm.ss is used.<br />

*JIS: The Japanese Industrial Standard time <strong>for</strong>mat hh:mm:ss is used.<br />

TIMSEP<br />

Specifies the separator used when accessing time result columns.<br />

318 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


Note: This parameter applies only when *HMS is specified on the TIMFMT<br />

parameter.<br />

*JOB: The time separator specified <strong>for</strong> the job is used. Use the Display Job<br />

(DSPJOB) command to determine the current value <strong>for</strong> the job.<br />

’:’: A colon (:) is used.<br />

’.’: A period (.) is used.<br />

’,’: A comma (,) is used.<br />

’’: A blank ( ) is used.<br />

*BLANK: A blank ( ) is used.<br />

DECMPT<br />

Specifies the decimal point value used <strong>for</strong> numeric constants in <strong>SQL</strong><br />

statements.<br />

*JOB: The value used as the decimal point <strong>for</strong> numeric constants in <strong>SQL</strong> is the<br />

representation of decimal point specified by the job running the statement.<br />

*SYSVAL: The QDECFMT system value is used as the decimal point.<br />

*PERIOD: A period represents the decimal point.<br />

*COMMA: A comma represents the decimal point.<br />

SRTSEQ<br />

Specifies the sort sequence table to be used <strong>for</strong> string comparisons in <strong>SQL</strong><br />

statements.<br />

*JOB: The LANGID value <strong>for</strong> the job is retrieved.<br />

*LANGIDSHR: The sort sequence table uses the same weight <strong>for</strong> multiple<br />

characters, and is the shared-weight sort sequence table associated with the<br />

language specified on the LANGID parameter.<br />

*LANGIDUNQ: The unique-weight sort table <strong>for</strong> the language specified on the<br />

LANGID parameter is used.<br />

*HEX: A sort sequence table is not used. The hexadecimal values of the<br />

characters are used to determine the sort sequence.<br />

The name of the table name can be qualified by one of the following library<br />

values:<br />

*LIBL: All libraries in the job’s library list are searched until the first match<br />

is found.<br />

*CURLIB: The current library <strong>for</strong> the job is searched. If no library is<br />

specified as the current library <strong>for</strong> the job, the QGPL library is used.<br />

library-name: Specify the name of the library to be searched.<br />

table-name: Specify the name of the sort sequence table to be used.<br />

RUN<strong>SQL</strong>STM<br />

Appendix C. <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> CL Command Descriptions 319


RUN<strong>SQL</strong>STM<br />

LANGID<br />

Specifies the language identifier to be used when SRTSEQ(*LANGIDUNQ) or<br />

SRTSEQ(*LANGIDSHR) is specified.<br />

*JOB: The LANGID value <strong>for</strong> the job is retrieved during the precompile.<br />

language-identifier: Specify a language identifier.<br />

DFTRDBCOL<br />

Specifies the collection name used <strong>for</strong> the unqualified names of tables, views,<br />

indexes, and <strong>SQL</strong> packages. This parameter applies only to static <strong>SQL</strong><br />

statements.<br />

*NONE: The naming convention defined on the OPTION parameter is used.<br />

collection-name: Specify the name of the collection identifier. This value is used<br />

instead of the naming convention specified on the OPTION parameter.<br />

FLAGSTD<br />

Specifies the American National Standards Institute (ANSI) flagging function.<br />

This parameter flags <strong>SQL</strong> statements to verify whether they con<strong>for</strong>m to the<br />

following standards.<br />

ANSI X3.135-1992 entry<br />

ISO 9075-1992 entry<br />

FIPS 127.2 entry<br />

*NONE: The <strong>SQL</strong> statements are not checked to determine whether they<br />

con<strong>for</strong>m to ANSI standards.<br />

*ANS: The <strong>SQL</strong> statements are checked to determine whether they con<strong>for</strong>m to<br />

ANSI standards.<br />

SAAFLAG<br />

Specifies the IBM <strong>SQL</strong> flagging function. This parameter flags <strong>SQL</strong> statements<br />

to verify whether they con<strong>for</strong>m to IBM <strong>SQL</strong> syntax More in<strong>for</strong>mation about<br />

which IBM database products IBM <strong>SQL</strong> syntax is in the DRDA IBM <strong>SQL</strong><br />

Reference, SC26-3255-00.<br />

*NOFLAG: The <strong>SQL</strong> statements are not checked to determine whether they<br />

con<strong>for</strong>m to IBM <strong>SQL</strong> syntax.<br />

*FLAG: The <strong>SQL</strong> statements are checked to determine whether they con<strong>for</strong>m<br />

to IBM <strong>SQL</strong> syntax.<br />

PRTFILE<br />

Specifies the qualified name of the printer device file to which the<br />

RUN<strong>SQL</strong>STM printout is directed. The file must have a minimum length of<br />

132 bytes. If a file with a record length of less than 132 bytes is specified,<br />

in<strong>for</strong>mation is lost.<br />

The name of the printer file can be qualified by one of hte following library<br />

values:<br />

*LIBL: All libraries in the job’s library list are searched until the first match<br />

is found.<br />

*CURLIB: The current library <strong>for</strong> the job is searched. If no library is<br />

specified as the current library <strong>for</strong> the job, the QGPL library is used.<br />

library-name: Specify the name of the library to be searched.<br />

320 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


QSYSPRT: If a file name is not specified, the RUN<strong>SQL</strong>STM printout is directed<br />

to the IBM-supplied printer file QSYSPRT.<br />

printer-file-name: Specify the name of the printer device file to which the<br />

RUN<strong>SQL</strong>STM printout is directed.<br />

Parameters <strong>for</strong> <strong>SQL</strong> procedures:<br />

The parameters listed below only apply to statements within the source file that<br />

create <strong>SQL</strong> procedures. The parameters are used during the creation of the<br />

program object associated with the <strong>SQL</strong> procedure.<br />

TGTRLS<br />

Specifies the release of the operating system on which the user intends to use<br />

the object being created.<br />

In the examples given <strong>for</strong> the *CURRENT value, and when specifying the<br />

release-level value, the <strong>for</strong>mat VxRxMx is used to specify the release, where Vx<br />

is the version, Rx is the release, and Mx is the modification level. For example,<br />

V2R3M0 is version 2, release 3, modification level 0.<br />

*CURRENT The object is to be used on the release of the operating system<br />

currently running on the user’s system. For example, if V2R3M5 is running on<br />

the system, *CURRENT means the user intends to use the object on a system<br />

with V2R3M5 installed. The user can also use the object on a system with any<br />

subsequent release of the operating system installed.<br />

Note: If V2R3M5 is running on the system, and the object is to be used on a<br />

system with V2R3M0 installed, specify TGTRLS(V2R3M0) not<br />

TGRRLS(*CURRENT).<br />

release-level: Specify the release in the <strong>for</strong>mat VxRxMx. The object can be used<br />

on a system with the specified release or with any subsequent release of the<br />

operating system installed.<br />

Valid values depend on the current version, release, and modification level,<br />

and they change with each new release. If you specify a release-level which is<br />

earlier than the earliest release level supported by this command, an error<br />

message is sent indicating the earliest supported release.<br />

CLO<strong>SQL</strong>CSR<br />

Specifies when <strong>SQL</strong> cursors are implicitly closed, <strong>SQL</strong> prepared statements are<br />

implicitly discarded, and LOCK TABLE locks are released. <strong>SQL</strong> cursors are<br />

explicitly closed when you issue the CLOSE, COMMIT, or ROLLBACK<br />

(without HOLD) <strong>SQL</strong> statements.<br />

*ENDACTGRP: <strong>SQL</strong> cursors are closed and <strong>SQL</strong> prepared statements are<br />

implicitly discarded.<br />

ENDMOD: <strong>SQL</strong> cursors are closed and <strong>SQL</strong> prepared statements are implicitly<br />

discarded when the module is exited. LOCK TABLE locks are released when<br />

the first <strong>SQL</strong> program on the call stack ends.<br />

OUTPUT<br />

Specifies whether the precompiler listing is generated.<br />

*NONE: The precompiler listing is not generated.<br />

RUN<strong>SQL</strong>STM<br />

Appendix C. <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> CL Command Descriptions 321


RUN<strong>SQL</strong>STM<br />

*PRINT: The precompiler listing is generated.<br />

DBGVIEW<br />

Specifies the type of source debug in<strong>for</strong>mation to be provided by the <strong>SQL</strong><br />

precompiler.<br />

*NONE: The source view will not be generated.<br />

*STMT: Allows the compiled module to be debugged using program statement<br />

numbers and symbolic identifiers.<br />

*LIST: Generates the listing view <strong>for</strong> debugging the compiled module object.<br />

USRPRF<br />

Specifies the user profile that is used when the compiled program object is run,<br />

including the authority that the program object has <strong>for</strong> each object in static<br />

<strong>SQL</strong> statements. The profile of either the program owner or the program user<br />

is used to control which objects can be used by the program object.<br />

*NAMING: The user profile is determined by the naming convention. If the<br />

naming convention is *<strong>SQL</strong>, USRPRF(*OWNER) is used. If the naming<br />

convention is *SYS, USRPRF(*USER) is used.<br />

*USER: The profile of the user running the program object is used.<br />

*OWNER: The user profiles of both the program owner and the program user<br />

are used when the program is run.<br />

DYNUSRPRF<br />

Specifies the user profile to be used <strong>for</strong> dynamic <strong>SQL</strong> statements.<br />

*USER: For local, dynamic <strong>SQL</strong> statements run under the user of the<br />

program’s user. For distributed, dynamic <strong>SQL</strong> statements run under the profile<br />

of the <strong>SQL</strong> package’s user.<br />

*OWNER: For local, dynamic <strong>SQL</strong> statements run under the profile of the<br />

program’s owner. For distributed, dynamic <strong>SQL</strong> statements run under the<br />

profile of the <strong>SQL</strong> package’s owner.<br />

DLYPRP<br />

Specifies whether the dynamic statement validation <strong>for</strong> a PREPARE statement<br />

is delayed until an OPEN, EXECUTE, or DESCRIBE statement is run. Delaying<br />

validation improves per<strong>for</strong>mance by eliminating redundant validation.<br />

322 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5<br />

*NO: Dynamic statement validation is not delayed. When the dynamic<br />

statement is prepared, the access plan is validated. When the dynamic<br />

statement is used in an OPEN or EXECUTE statement, the access plan is<br />

revalidated. Because the authority or the existence of objects referred to by the<br />

dynamic statement may change, you must still check the <strong>SQL</strong>CODE or<br />

<strong>SQL</strong>STATE after issuing the OPEN or EXECUTE statement to ensure that the<br />

dynamic statement is still valid.<br />

*YES: Dynamic statement validation is delayed until the dynamic statement is<br />

used in an OPEN, EXECUTE, or DESCRIBE <strong>SQL</strong> statement. When the dynamic<br />

statement is used, the validation is completed and an access plan is built. If<br />

you specify *YES on this parameter, you should check the <strong>SQL</strong>CODE and<br />

<strong>SQL</strong>STATE after running an OPEN, EXECUTE, or DESCRIBE statement to<br />

ensure that the dynamic statement is valid.


Note: If you specify *YES, per<strong>for</strong>mance is not improved if the INTO clause is<br />

used on the PREPARE statement or if a DESCRIBE statement uses the<br />

dynamic statement be<strong>for</strong>e an OPEN is issued <strong>for</strong> the statement.<br />

Example:<br />

RUN<strong>SQL</strong>STM SRCFILE(MYLIB/MYFILE) SRCMBR(MYMBR)<br />

This command processes the <strong>SQL</strong> statements in member MYMBR found in file<br />

MYFILE in library MYLIB.<br />

STR<strong>SQL</strong> (Start Structured Query Language) Command<br />

Job: I Pgm: I REXX: I Exec<br />

►► STR<strong>SQL</strong><br />

►<br />

►<br />

►<br />

*NC<br />

*NONE<br />

COMMIT(*CHG )<br />

*UR<br />

*CS<br />

*RS<br />

*ALL<br />

*RR<br />

*RUN<br />

PROCESS(*VLD )<br />

*SYN<br />

*ALL<br />

LISTTYPE(*<strong>SQL</strong> )<br />

*YES<br />

ALWCPYDTA(*OPTIMIZE )<br />

*NO<br />

*SYS<br />

NAMING(*<strong>SQL</strong> )<br />

*LIBL<br />

LIBOPT(*CURLIB )<br />

*USRLIBL<br />

*ALL<br />

*ALLUSR<br />

library-name<br />

*ALWAYS<br />

REFRESH(*FORWARD )<br />

*JOB<br />

DATFMT(*USA )<br />

*ISO<br />

*EUR<br />

*JIS<br />

*MDY<br />

*DMY<br />

*YMD<br />

*JUL<br />

(1)<br />

RUN<strong>SQL</strong>STM<br />

Appendix C. <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> CL Command Descriptions 323<br />

►<br />

►<br />

►<br />


STR<strong>SQL</strong><br />

►<br />

►<br />

►<br />

►<br />

►<br />

►<br />

(2) *JOB<br />

DATSEP(*BLANK )<br />

’/’<br />

’.’<br />

’,’<br />

’-’<br />

’ ’<br />

(3) *JOB<br />

TIMSEP(*BLANK )<br />

’:’<br />

’.’<br />

’,’<br />

’ ’<br />

(4) *NONE<br />

PGMLNG(*C )<br />

*CBL<br />

*PLI<br />

*RPG<br />

*FTN<br />

(5) (6) *QUOTE<strong>SQL</strong><br />

<strong>SQL</strong>STRDLM(*APOST<strong>SQL</strong> )<br />

*HMS<br />

TIMFMT(*USA )<br />

*ISO<br />

*EUR<br />

*JIS<br />

*SYSVAL<br />

DECPNT(*PERIOD )<br />

*COMMA<br />

*JOB<br />

*JOB<br />

SRTSEQ(*JOBRUN )<br />

*LANGIDUNQ<br />

*LANGIDSHR<br />

*HEX<br />

*LIBL/<br />

table-name<br />

*CURLIB/<br />

library-name/<br />

*JOB<br />

LANGID(*JOBRUN )<br />

language-ID<br />

Notes:<br />

1 All parameters preceding this point can be specified in positional <strong>for</strong>m.<br />

2 DATSEP is only valid when *MDY, *DMY, *YMD, or *JUL is specified on the<br />

DATFMT parameter.<br />

3 TIMSEP is only valid when TIMFMT(*HMS) is specified.<br />

4 PGMLNG and <strong>SQL</strong>STRDLM are valid only when PROCESS(*SYN) is<br />

specified.<br />

324 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5<br />

►<br />

►<br />

►<br />

►<br />

►<br />

►◄


5 PGMLNG and <strong>SQL</strong>STRDLM are valid only when PROCESS(*SYN) is<br />

specified.<br />

6 <strong>SQL</strong>STRDLM is valid only when PGMLNG(*CBL) is specified.<br />

Purpose:<br />

The Start Structured Query Language (STR<strong>SQL</strong>) command starts the interactive<br />

Structured Query Language (<strong>SQL</strong>) program. The program starts the statement<br />

entry of the interactive <strong>SQL</strong> program which immediately shows the Enter <strong>SQL</strong><br />

Statements display. This display allows the user to build, edit, enter, and run an<br />

<strong>SQL</strong> statement in an interactive environment. Messages received during the<br />

running of the program are shown on this display.<br />

Parameters:<br />

COMMIT<br />

Specifies whether the <strong>SQL</strong> statements are run under commitment control.<br />

STR<strong>SQL</strong><br />

*NONE or *NC: Specifies that commitment control is not used. Uncommitted<br />

changes in other jobs can be seen. If the <strong>SQL</strong> DROP COLLECTION statement<br />

is included in the program, *NONE or *NC must be used. If a relational<br />

database is specified on the RDB parameter and the relational database is on a<br />

system that is not on an <strong>AS</strong>/<strong>400</strong>, *NONE or *NC cannot be specified.<br />

*CHG or *UR: Specifies the objects referred to in <strong>SQL</strong> ALTER, CALL,<br />

COMMENT ON, CREATE, DROP, GRANT, LABEL ON, RENAME, and<br />

REVOKE statements and the rows updated, deleted, and inserted are locked<br />

until the end of the unit of work (transaction). Uncommitted changes in other<br />

jobs can be seen.<br />

*CS: Specifies the objects referred to in <strong>SQL</strong> ALTER, CALL, COMMENT ON,<br />

CREATE, DROP, GRANT, LABEL ON, RENAME, and REVOKE statements and<br />

the rows updated, deleted, and inserted are locked until the end of the unit of<br />

work (transaction). A row that is selected, but not updated, is locked until the<br />

next row is selected. Uncommitted changes in other jobs cannot be seen.<br />

*ALL or *RS: Specifies the objects referred to in <strong>SQL</strong> ALTER, CALL,<br />

COMMENT ON, CREATE, DROP, GRANT, LABEL ON, RENAME, and<br />

REVOKE statements and the rows selected, updated, deleted, and inserted are<br />

locked until the end of the unit of work (transaction). Uncommitted changes in<br />

other jobs cannot be seen.<br />

*RR: Specifies the objects referred to in <strong>SQL</strong> ALTER, CALL, COMMENT ON,<br />

CREATE, DROP, GRANT, LABEL ON, RENAME, and REVOKE statements and<br />

the rows selected, updated, deleted, and inserted are locked until the end of<br />

the unit of work (transaction). Uncommitted changes in other jobs cannot be<br />

seen. All tables referred to in SELECT, UPDATE, DELETE, and INSERT<br />

statements are locked exclusively until the end of the unit of work<br />

(transaction).<br />

Note: The default <strong>for</strong> this parameter <strong>for</strong> the CRT<strong>SQL</strong>XXX commands (when<br />

XXX=CI, CPPI, CBL, FTN, PLI, CBLI, RPG or RPGI) is *CHG.<br />

NAMING<br />

Specifies the naming convention used <strong>for</strong> naming objects in <strong>SQL</strong> statements.<br />

Appendix C. <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> CL Command Descriptions 325


STR<strong>SQL</strong><br />

*SYS: The system naming convention (library-name/file-name) is used.<br />

*<strong>SQL</strong>: The <strong>SQL</strong> naming convention (collection-name.table-name) is used.<br />

PROCESS<br />

Specifies the values used to process the <strong>SQL</strong> statements.<br />

*RUN: The statements are syntax checked, data checked, and then run.<br />

*VLD: The statements are syntax checked and data checked, but not run.<br />

*SYN: The statements are syntax checked only.<br />

LIBOPT<br />

Specifies which collections and libraries are used as a basis <strong>for</strong> building a<br />

collection list when the F4, F16, F17, or F18 function key is pressed.<br />

The name of the collection list can be qualified by one of the following library<br />

values:<br />

*LIBL: All libraries in the job’s library list are searched until the first match<br />

is found.<br />

*CURLIB: The current library <strong>for</strong> the job is searched. If no library is<br />

specified as the current library <strong>for</strong> the job, the QGPL library is used.<br />

*USRLIBL: Only the libraries in the user portion of the job’s library list are<br />

searched.<br />

*ALL: All libraries in the system, including QSYS, are searched.<br />

*ALLUSR: All user libraries are searched. All libraries with names that do<br />

not begin with the letter Q are searched except <strong>for</strong> the following:<br />

#CGULIB #DFULIB #RPGLIB #SEULIB<br />

#COBLIB #DSULIB #SDALIB<br />

Although the following Qxxx libraries are provided by IBM, they typically<br />

contain user data that changes frequently. There<strong>for</strong>e, these libraries are<br />

considered user libraries and are also searched:<br />

QDSNX QRCL QUSRBRM QUSRSYS<br />

QGPL QS36F QUSRIJS QUSRVxRxMx<br />

QGPL38 QUSER38 QUSRINFSKR<br />

QPFRDATA QUSRADSM QUSRRDARS<br />

Note: A different library name, of the <strong>for</strong>m QUSRVxRxMx, can be created<br />

by the user <strong>for</strong> each release that IBM supports. VxRxMx is the<br />

version, release, and modification level of the library.<br />

library-name: Specify the name of the library to be searched.<br />

LISTTYPE<br />

Specifies the types of objects that are displayed with list support by pressing<br />

the F4, F16, F17, or F18 function key.<br />

*ALL: All objects are displayed.<br />

*<strong>SQL</strong>: Only <strong>SQL</strong>-created objects are displayed.<br />

REFRESH<br />

Specifies when the display select output data is refreshed.<br />

326 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


*ALWAYS: Data is normally refreshed during <strong>for</strong>ward and backward scrolling.<br />

*FORWARD: Data is refreshed only during <strong>for</strong>ward scrolling to the end of the<br />

data <strong>for</strong> the first time. When scrolling backward, a copy of the data already<br />

viewed is shown.<br />

ALWCPYDTA<br />

Specifies whether a copy of the data can be used in a SELECT statement. If<br />

COMMIT(*ALL) is specified, <strong>SQL</strong> run time ignores the ALWCPYDTA value<br />

and uses current data.<br />

*YES: A copy of the data is used when necessary.<br />

*OPTIMIZE: The system determines whether to use the data retrieved from<br />

the database or to use a copy of the data. The determination is based on which<br />

will provide the best per<strong>for</strong>mance.<br />

*NO: A copy of the data is not allowed. If a temporary copy of the data is<br />

required to per<strong>for</strong>m the query, an error message is returned.<br />

DATFMT<br />

Specifies the date <strong>for</strong>mat used in <strong>SQL</strong> statements.<br />

*JOB: The <strong>for</strong>mat specified on the job attribute DATFMT is used.<br />

*USA: The United States date <strong>for</strong>mat (mm/dd/yyyy) is used.<br />

*ISO: The International Standards Organization date <strong>for</strong>mat (yyyy-mm-dd) is<br />

used.<br />

*EUR: The European date <strong>for</strong>mat (dd.mm.yyyy) is used.<br />

*JIS: The Japanese Industry Standard Christian Era date <strong>for</strong>mat (yyyy-mm-dd)<br />

is used.<br />

*MDY: The month, day, and year date <strong>for</strong>mat (mm/dd/yy) is used.<br />

*DMY: The day, month, and year date <strong>for</strong>mat (dd/mm/yy) is used.<br />

*YMD: The year, month, and day date <strong>for</strong>mat (yy/mm/dd) is used.<br />

*JUL: The Julian date <strong>for</strong>mat (yy/ddd) is used.<br />

DATSEP<br />

Specifies the date separator used in <strong>SQL</strong> statements.<br />

*JOB: The date separator specified on the job attribute is used. If the user<br />

specifies *JOB on a new interactive <strong>SQL</strong> session, the current value is stored and<br />

used. Later changes to the job’s date separator are not detected by interactive<br />

<strong>SQL</strong>.<br />

*BLANK: A blank ( ) is used.<br />

’/’: A slash (/) is used.<br />

’.’: A period (.) is used.<br />

STR<strong>SQL</strong><br />

Appendix C. <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> CL Command Descriptions 327


STR<strong>SQL</strong><br />

’,’: A comma (,) is used.<br />

’-’: A dash (-) is used.<br />

’’: A blank ( ) is used.<br />

TIMFMT<br />

Specifies the time <strong>for</strong>mat used in <strong>SQL</strong> statements.<br />

*HMS: The Hour-Minute-Second time <strong>for</strong>mat (hh:mm:ss) is used.<br />

*USA: The United States time <strong>for</strong>mat (hh:mm xx, where xx is AM or PM) is<br />

used.<br />

*ISO: The International Standards Organization time <strong>for</strong>mat (hh.mm.ss) is<br />

used.<br />

*EUR: The European time <strong>for</strong>mat (hh.mm.ss) is used.<br />

*JIS: The Japanese Industry Standard Christian Era time <strong>for</strong>mat (hh:mm:ss) is<br />

used.<br />

TIMSEP<br />

Specifies the time separator used in <strong>SQL</strong> statements.<br />

*JOB: The time separator specified on the job attribute is used. If the user<br />

specifies *JOB on a new interactive <strong>SQL</strong> session, the current value is stored and<br />

used. Later changes to the job’s time separator are not detected by interactive<br />

<strong>SQL</strong>.<br />

*BLANK: A blank ( ) is used.<br />

’:’: A colon (:) is used.<br />

’.’: A period (.) is used.<br />

’,’: A comma (,) is used.<br />

’’: A blank ( ) is used.<br />

DECPNT<br />

Specifies the kind of decimal point to use.<br />

*JOB: The value used as the decimal point <strong>for</strong> numeric constants in <strong>SQL</strong> is the<br />

representation of decimal point specified <strong>for</strong> the job running the statement.<br />

*SYSVAL: The decimal point is extracted from the system value. If the user<br />

specifies *SYSVAL on a new interactive <strong>SQL</strong> session, the current value is stored<br />

and used. Later changes to the system’s time separator are not detected by<br />

interactive <strong>SQL</strong>.<br />

*PERIOD: A period represents the decimal point.<br />

*COMMA: A comma represents the decimal point.<br />

PGMLNG<br />

Specifies which program language syntax rules to use. To use this parameter,<br />

*SYN must be selected at the PROCESS parameter.<br />

328 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


*NONE: No specific language’s syntax check rules are used.<br />

The supported languages are:<br />

*C: Syntax checking is done according to the C language syntax rules.<br />

*CBL: Syntax checking is done according to the COBOL language syntax rules.<br />

*PLI: Syntax checking is done according to the PL/I language syntax rules.<br />

*RPG: Syntax checking is done according to the RPG language syntax rules.<br />

*FTN: Syntax checking is done according to the FORTRAN language syntax<br />

rules.<br />

<strong>SQL</strong>STRDLM<br />

Specifies the <strong>SQL</strong> string delimiter. Use of this parameter requires using the<br />

COBOL (*CBL) character set.<br />

*QUOTE<strong>SQL</strong>: A quotation mark represents the <strong>SQL</strong> string delimiter.<br />

*APOST<strong>SQL</strong>: An apostrophe represents the <strong>SQL</strong> string delimiter.<br />

SRTSEQ<br />

Specifies the sort sequence table to be used <strong>for</strong> string comparisons in <strong>SQL</strong><br />

statements on the Enter <strong>SQL</strong> Statements display.<br />

*JOB: The SRTSEQ value <strong>for</strong> the job is retrieved.<br />

*JOBRUN: The SRTSEQ value <strong>for</strong> the job is retrieved each time the user starts<br />

interactive <strong>SQL</strong>.<br />

*LANGIDUNQ: The unique-weight sort table <strong>for</strong> the language specified on the<br />

LANGID parameter is used.<br />

*LANGIDSHR: The shared-weight sort table <strong>for</strong> the language specified on the<br />

LANGID parameter is used.<br />

*HEX: A sort sequence table is not used. The hexadecimal values of the<br />

characters are used to determine the sort sequence.<br />

The name of the table name can be qualified by one of the following library<br />

values:<br />

*LIBL: All libraries in the job’s library list are searched until the first match<br />

is found.<br />

*CURLIB: The current library <strong>for</strong> the job is searched. If no library is<br />

specified as the current library <strong>for</strong> the job, the QGPL library is used.<br />

library-name: Specify the name of the library to be searched.<br />

table-name: Specify the name of the sort sequence table to be used with the<br />

interactive <strong>SQL</strong> session.<br />

LANGID<br />

Specifies the language identifier to be used when SRTSEQ(*LANGIDUNQ) or<br />

SRTSEQ(*LANGIDSHR) is specified.<br />

*JOB: The LANGID value <strong>for</strong> the job is retrieved.<br />

STR<strong>SQL</strong><br />

Appendix C. <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> CL Command Descriptions 329


STR<strong>SQL</strong><br />

*JOBRUN: The LANGID value <strong>for</strong> the job is retrieved each time interactive<br />

<strong>SQL</strong> is started.<br />

language-ID: Specify the language identifier to be used.<br />

Example:<br />

STR<strong>SQL</strong> PROCESS(*SYN) NAMING(*<strong>SQL</strong>)<br />

DECPNT(*COMMA) PGMLNG(*CBL)<br />

<strong>SQL</strong>STRDLM(*APOST<strong>SQL</strong>)<br />

This command starts an interactive <strong>SQL</strong> session that checks only the syntax of <strong>SQL</strong><br />

statements. The character set used by the syntax checker uses the COBOL language<br />

syntax rules. The <strong>SQL</strong> naming convention is used <strong>for</strong> this session. The decimal<br />

point is represented by a comma, and the <strong>SQL</strong> string delimiter is represented by an<br />

apostrophe.<br />

330 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


Bibliography<br />

This guide lists publications that provide<br />

additional in<strong>for</strong>mation about topics described or<br />

referred to in this guide. The manuals in this<br />

section are listed with their full title and order<br />

number, but when referred to in text, a shortened<br />

version of the title is used.<br />

v Backup and Recovery, SC41-5304-04<br />

This guide contains a subset of the in<strong>for</strong>mation<br />

found in the Backup and Recovery book The<br />

manual contains in<strong>for</strong>mation about planning a<br />

backup and recovery strategy, the different<br />

types of media available to save and restore<br />

procedures, and disk recovery procedures. It<br />

also describes how to install the system again<br />

from backup.<br />

v File Management<br />

This guide provides in<strong>for</strong>mation about using<br />

files in application programs.<br />

v Database <strong>Programming</strong><br />

This guide provides a detailed description of<br />

the <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> database<br />

organization, including in<strong>for</strong>mation on how to<br />

create, describe, and update database files on<br />

the system.<br />

v CL <strong>Programming</strong>, SC41-5721-03<br />

This guide provides a wide-ranging discussion<br />

of the <strong>AS</strong>/<strong>400</strong> programming topics, including a<br />

general discussion of objects and libraries, CL<br />

programming, controlling flow and<br />

communicating between programs, working<br />

with objects in CL programs, and creating CL<br />

programs. Other topics include predefined and<br />

impromptu messages and handling, defining<br />

and creating user-defined commands and<br />

menus, application testing, including debug<br />

mode, breakpoints, traces, and display<br />

functions.<br />

v Control Language (CL)<br />

This guide provides a description of the<br />

<strong>AS</strong>/<strong>400</strong> control language (CL) and its OS/<strong>400</strong><br />

commands. (Non-OS/<strong>400</strong> commands are<br />

described in the respective licensed program<br />

publications.) It also provides an overview of<br />

all the CL commands <strong>for</strong> the <strong>AS</strong>/<strong>400</strong> system,<br />

and it describes the syntax rules needed to<br />

code them.<br />

v Security - Reference, SC41-5302-04<br />

This guide provides in<strong>for</strong>mation about system<br />

security concepts, planning <strong>for</strong> security, and<br />

setting up security on the system. It also gives<br />

in<strong>for</strong>mation about protecting the system and<br />

data from being used by people who do not<br />

have the proper authorization, protecting the<br />

data from intentional or unintentional damage<br />

or destruction, keeping security up-to-date, and<br />

setting up security on the system.<br />

v <strong>SQL</strong> Reference<br />

This guide provides in<strong>for</strong>mation about <strong>DB2</strong><br />

<strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> statements and their<br />

parameters. It also includes an appendix<br />

describing the <strong>SQL</strong> communications area<br />

(<strong>SQL</strong>CA) and <strong>SQL</strong> description area (<strong>SQL</strong>DA).<br />

v IDDU Use, SC41-5704-00<br />

This guide describes how to use <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong><br />

<strong>AS</strong>/<strong>400</strong> interactive data definition utility<br />

(IDDU) to describe data dictionaries, files, and<br />

records to the system.<br />

v DATAB<strong>AS</strong>E 2/<strong>400</strong> Advanced Database Functions,<br />

GG24-4249<br />

This guide provides suggestions, guidelines,<br />

and practical examples of when and how<br />

functions offered by <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> such<br />

as triggers, referential integrity, DRDA-2,<br />

2-phase commit, and stored procedures, can be<br />

effectively used. The book reports examples<br />

developed in several programming languages<br />

(RPG, COBOL, C), using native and <strong>SQL</strong> data<br />

access interface, both in the Integrated<br />

Language Environment and with the Original<br />

Program Model.<br />

v ILE COBOL <strong>for</strong> <strong>AS</strong>/<strong>400</strong> Programmer’s Guide,<br />

SC09-2540-01<br />

This guide provides in<strong>for</strong>mation you need to<br />

design, write, test, and maintain COBOL <strong>for</strong><br />

<strong>AS</strong>/<strong>400</strong> programs on the <strong>AS</strong>/<strong>400</strong> system.<br />

v ILE RPG <strong>for</strong> <strong>AS</strong>/<strong>400</strong> Programmer’s Guide,<br />

SC09-2507-02<br />

This guide provides in<strong>for</strong>mation you need to<br />

design, write, test, and maintain ILE RPG <strong>for</strong><br />

<strong>AS</strong>/<strong>400</strong> programs on the <strong>AS</strong>/<strong>400</strong> system.<br />

v ILE C <strong>for</strong> <strong>AS</strong>/<strong>400</strong> Run-Time Library Reference,<br />

SC09-2711-01<br />

This guide provides in<strong>for</strong>mation you need to<br />

design, write, test, and maintain ILE C <strong>for</strong><br />

<strong>AS</strong>/<strong>400</strong> programs on the <strong>AS</strong>/<strong>400</strong> system.<br />

© Copyright IBM Corp. 2000 331


v ILE C <strong>for</strong> <strong>AS</strong>/<strong>400</strong> Programmer’s Guide,<br />

SC09-2712-01<br />

This guide provides in<strong>for</strong>mation you need to<br />

design, write, test, and maintain ILE C <strong>for</strong><br />

<strong>AS</strong>/<strong>400</strong> programs on the <strong>AS</strong>/<strong>400</strong> system.<br />

v ILE COBOL <strong>for</strong> <strong>AS</strong>/<strong>400</strong> Reference, SC09-2539-01<br />

This guide provides in<strong>for</strong>mation you need to<br />

design, write, test, and maintain COBOL <strong>for</strong><br />

<strong>AS</strong>/<strong>400</strong> programs on the <strong>AS</strong>/<strong>400</strong> system.<br />

v REXX/<strong>400</strong> Programmer’s Guide, SC41-5728-00<br />

This guide provides in<strong>for</strong>mation you need to<br />

design, write, test, and maintain REXX/<strong>400</strong><br />

programs on the <strong>AS</strong>/<strong>400</strong> system.<br />

v PL/I User’s Guide and Reference, SC09-1825<br />

This guide provides in<strong>for</strong>mation about using<br />

<strong>AS</strong>/<strong>400</strong> PL/I in the System/38 environment.<br />

Differences between the System/38<br />

environment and the <strong>AS</strong>/<strong>400</strong> environment are<br />

identified as well as the enhancements<br />

available in the <strong>AS</strong>/<strong>400</strong> environment.<br />

v <strong>DB2</strong> Multisystem<br />

This guide describes the fundamental concepts<br />

of distributed relational database files,<br />

nodegroups, and partitioning. The book<br />

provides the in<strong>for</strong>mation you need to create<br />

and use database files that are partitioned<br />

across multiple <strong>AS</strong>/<strong>400</strong> systems. In<strong>for</strong>mation is<br />

provided on how to configure the systems, how<br />

to create the files, and how the files can be<br />

used in applications.<br />

v Per<strong>for</strong>mance Tools <strong>for</strong> <strong>AS</strong>/<strong>400</strong>, SC41-5340-00<br />

This guide provides the programmer with the<br />

in<strong>for</strong>mation needed to collect data about the<br />

system, job, or program per<strong>for</strong>mance. This book<br />

also has tips <strong>for</strong> printing and analyzing<br />

per<strong>for</strong>mance data to identify and correct<br />

inefficiencies that might exist. In<strong>for</strong>mation<br />

about the manager and agent feature is<br />

included.<br />

v <strong>SQL</strong> Call Level Interface (ODBC)<br />

This guide provides the in<strong>for</strong>mation necessary<br />

<strong>for</strong> application programmers to write<br />

applications using the <strong>DB2</strong> call level interface.<br />

v <strong>AS</strong>/<strong>400</strong> Developer Kit <strong>for</strong> Java<br />

This guide provides in<strong>for</strong>mation you need to<br />

design, write, test, and maintain Java programs<br />

on the <strong>AS</strong>/<strong>400</strong> system. It also contains a<br />

chapter, <strong>AS</strong>/<strong>400</strong> Developer Kit <strong>for</strong> Java JDBC<br />

driver, which provides in<strong>for</strong>mation about<br />

accessing <strong>AS</strong>/<strong>400</strong> database files from Java<br />

programs by using JDBC or <strong>SQL</strong>j.<br />

332 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


Index<br />

Special Characters<br />

% (percent sign)<br />

use with LIKE 73<br />

A<br />

access plan<br />

definition 11<br />

in a package 12<br />

in a program 11<br />

accessing remote databases<br />

interactive <strong>SQL</strong> 229<br />

activation groups<br />

connection management<br />

example 263<br />

add row to table 32<br />

adding a column 92<br />

adding data to end of table 254<br />

adding indexes 96<br />

address variable, in dynamic <strong>SQL</strong> 199<br />

advanced coding technique<br />

complex search condition 72<br />

inserting multiple rows into a<br />

table 69<br />

joining data from multiple tables 75<br />

aggregating functions 163<br />

ALI<strong>AS</strong> names<br />

creating 48<br />

ALI<strong>AS</strong> statement 48<br />

ALL 86<br />

allocating storage <strong>for</strong> <strong>SQL</strong>DA 210<br />

ALTER TABLE 92<br />

AND keyword<br />

description 74<br />

multiple search condition 74<br />

ANY 86<br />

API<br />

QSQCHKS 2<br />

QSQPRCED 2<br />

application<br />

dynamic <strong>SQL</strong><br />

designing and running 201<br />

overview 199<br />

application design<br />

user-defined function (UDF) 189<br />

application domain and<br />

object-orientation 149<br />

application <strong>for</strong>ms using CREATE TABLE<br />

example 175<br />

application program<br />

creating 9<br />

testing <strong>SQL</strong> statements in 249<br />

application requester 257<br />

application requester driver (ARD)<br />

programs<br />

package creation 279<br />

running statements 279<br />

application server 257<br />

ARD (application requester driver)<br />

programs 279<br />

arithmetic error<br />

in UDFs 192, 195<br />

arithmetic expression error 37, 38<br />

arranging rows 41<br />

assignments in dynamic <strong>SQL</strong><br />

example 179<br />

assignments involving different UDTs<br />

example 180<br />

assignments involving UDTs<br />

example 179<br />

asterisk (select all columns) 38<br />

atomic operation<br />

data definition statements (DDL) 243<br />

data integrity 243<br />

definition 243<br />

Auditing<br />

C2 security 236<br />

authority, public 235<br />

authorization<br />

Create <strong>SQL</strong> Package (CRT<strong>SQL</strong>PKG)<br />

command 260<br />

<strong>for</strong> creating package 259<br />

<strong>for</strong> running using a package 259<br />

ID 236<br />

testing 249, 250<br />

auxiliary storage pools 239, 247<br />

AVG over a UDT example 167<br />

B<br />

basic <strong>SQL</strong> statements and clauses 31<br />

BETWEEN clause, multiple search<br />

condition 72<br />

BETWEEN keyword 72<br />

bibliography 331<br />

Binary Large OBjects 150<br />

BLOBs (Binary Large OBjects)<br />

uses and definition 150<br />

blocked insert statement 70<br />

C<br />

C2 security<br />

auditing 236<br />

call level interface 2<br />

call-type<br />

contents with table functions 194<br />

call-type, passing to UDF 194<br />

C<strong>AS</strong>T FROM clause 192, 194, 195<br />

castability 161<br />

casting, UDFs 172<br />

catalog<br />

database design, use in 97<br />

definition 6<br />

getting in<strong>for</strong>mation about 97<br />

column 97<br />

integrity 247<br />

LABEL ON in<strong>for</strong>mation 48<br />

QSYS2 views 6<br />

table 97<br />

CCSID<br />

connection to non-<strong>DB2</strong> <strong>UDB</strong> <strong>for</strong><br />

<strong>AS</strong>/<strong>400</strong> 263<br />

delimited identifier effect 263<br />

dynamic <strong>SQL</strong> statement 202<br />

package considerations 263<br />

Change Class (CHGCLS) command 237<br />

change in<strong>for</strong>mation<br />

in table<br />

host variables 33, 34<br />

Change Job (CHGJOB) command 237<br />

Change Logical File (CHGLF)<br />

command 237<br />

Change Physical File (CHGPF)<br />

command 237<br />

change session attributes<br />

interactive <strong>SQL</strong> 227<br />

changing<br />

data 33<br />

in<strong>for</strong>mation in a table 25<br />

table definition 92, 256<br />

changing a column 93<br />

Character Large OBjects 150<br />

check constraints 99<br />

check pending 107, 245<br />

checking syntax in interactive <strong>SQL</strong> 223<br />

CHGPF command 33<br />

CL_SCHED table 287<br />

class schedule table 287<br />

clause 47<br />

AND 74<br />

DISTINCT 72<br />

FROM 36<br />

GROUP BY<br />

example 41<br />

HAVING 42<br />

INTO<br />

example 32<br />

PREPARE statement, use<br />

with 205<br />

restriction 210<br />

NOT 74<br />

null value 45<br />

OR 74<br />

ORDER BY 43<br />

SELECT 38<br />

SET 33<br />

USING DESCRIPTOR 215<br />

VALUES 31<br />

WHENEVER NOT FOUND 60<br />

WHERE<br />

character string 31<br />

example 38, 215<br />

expression 39<br />

joining tables 76<br />

multiple search condition<br />

within 74<br />

NOT keyword 40<br />

WHERE CURRENT OF 61<br />

CLI 2<br />

© Copyright IBM Corp. 2000 333


CLOBs (Character Large OBjects)<br />

uses and definition 150<br />

CLO<strong>SQL</strong>CSR parameter<br />

effect on implicit disconnect 267<br />

coded character set conversion error 38<br />

coding techniques 31, 55, 69<br />

collating rows 41<br />

collection<br />

changing<br />

table definition 256<br />

creating 13<br />

definition 3, 6<br />

solving problem<br />

paging through retrieved<br />

data 253<br />

retrieving data a second time 256<br />

column<br />

adding 92<br />

defining heading 16, 48<br />

definition 3, 6<br />

deleting 94<br />

FOR UPDATE OF clause 58<br />

getting catalog in<strong>for</strong>mation about 97<br />

name<br />

definition 39<br />

SET clause, value 33<br />

updating view 29<br />

column definition<br />

changing 93<br />

column functions 163<br />

combining<br />

in<strong>for</strong>mation from multiple tables 23<br />

SELECT statement 80<br />

subselect with UNION<br />

example 80<br />

command<br />

RUN<strong>SQL</strong>STM<br />

errors 232<br />

command, CL<br />

Create Structured Query Language<br />

Package (CRT<strong>SQL</strong>PKG) 308<br />

CRT<strong>SQL</strong>PKG (Create Structured<br />

Query Language Package) 308<br />

Delete Structured Query Language<br />

Package (DLT<strong>SQL</strong>PKG) 311<br />

DLT<strong>SQL</strong>PKG (Delete Structured<br />

Query Language Package) 311<br />

command (CL)<br />

Change Class (CHGCLS) 237<br />

Change Job (CHGJOB) 237<br />

Change Logical File (CHGLF) 237<br />

Change Physical File (CHGPF) 237<br />

CHGCLS (Change Class) 237<br />

CHGJOB (Change Job) 237<br />

CHGLF (Change Logical File) 237<br />

CHGPF (Change Physical File) 237<br />

Create Duplicate Object<br />

(CRTDUPOBJ) 250<br />

Create <strong>SQL</strong> Package<br />

(CRT<strong>SQL</strong>PKG) 259, 311<br />

Create User Profile<br />

(CRTUSRPRF) 236<br />

CRTDUPOBJ (Create Duplicate Object)<br />

command 250<br />

CRTUSRPRF (Create User<br />

Profile) 236<br />

Delete Library (DLTLIB) 244<br />

334 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5<br />

command (CL) (continued)<br />

Delete <strong>SQL</strong> Package<br />

(DLT<strong>SQL</strong>PKG) 259, 312<br />

Display Message Description<br />

(DSPMSGD) 289<br />

DLTLIB (Delete Library) 244<br />

DSPMSGD (Display Message<br />

Description) 289<br />

Edit Check Pending Constraints<br />

(EDTCPCST) 245<br />

Edit Rebuild of Access Paths<br />

(EDTRBDAP) 245<br />

Edit Recovery <strong>for</strong> Access Paths<br />

(EDTRCYAP) 246<br />

EDTCPCST (Edit Check Pending<br />

Constraints) 245<br />

EDTRBDAP (Edit Rebuild of Access<br />

Paths) 245<br />

EDTRCYAP (Edit Recovery <strong>for</strong> Access<br />

Paths) 246<br />

Grant Object Authority<br />

(GRTOBJAUT) 235<br />

GRTOBJAUT (Grant Object<br />

Authority) 235, 237<br />

Override Database File<br />

(OVRDBF) 62, 237<br />

OVRDBF (Override Database<br />

File) 62, 237<br />

Reclaim DDM connections<br />

(RCLDDMCNV) 275<br />

Retrieve Message (RTVMSG) 289<br />

Revoke Object Authority<br />

(RVKOBJAUT) 235<br />

RTVMSG (Retrieve Message) 289<br />

Run <strong>SQL</strong> Statements<br />

(RUN<strong>SQL</strong>STM) 2<br />

RUN<strong>SQL</strong>STM (Run <strong>SQL</strong><br />

statements) 2<br />

RUN<strong>SQL</strong>STM (Run <strong>SQL</strong><br />

Statements) 231, 323<br />

RVKOBJAUT (Revoke Object<br />

Authority) 235<br />

Send Program Message<br />

(SNDPGMMSG) 289<br />

Send User Message<br />

(SNDUSRMSG) 289<br />

SNDPGMMSG (Send Program<br />

Message) 289<br />

SNDUSRMSG (Send User<br />

Message) 289<br />

Start Commitment Control<br />

(STRCMTCTL) 240<br />

Start Journal Access Path<br />

(STRJRNAP) 246<br />

STRCMTCTL (Start Commitment<br />

Control) 240<br />

STRJRNAP (Start Journal Access<br />

Path) 246<br />

STR<strong>SQL</strong> (Start <strong>SQL</strong>) 330<br />

comment<br />

<strong>for</strong> RUN<strong>SQL</strong>STM 231<br />

getting 49<br />

COMMENT ON statement<br />

using, example 49<br />

COMMIT<br />

keyword 240<br />

prepared statements 203<br />

COMMIT (continued)<br />

statement 261<br />

statement description 6<br />

commitment control<br />

activation group<br />

example 263<br />

committable updates 269<br />

description 239<br />

distributed connection<br />

restrictions 272<br />

DRDA resource 269<br />

INSERT statement 33<br />

job-level commitment definition 267,<br />

272<br />

protected resource 269<br />

rollback required 274<br />

RUN<strong>SQL</strong>STM command 232<br />

<strong>SQL</strong> statement processor 232<br />

sync point manager 269<br />

two-phase commit 269<br />

unprotected resource 269<br />

common database problem<br />

solving 253<br />

comparison operators 40<br />

comparisons involving UDTs<br />

example 177, 178<br />

compiled application program object<br />

managing object 9<br />

output source file member 11<br />

program 9<br />

user source file member 11<br />

compiling<br />

application program object<br />

output source file member 11<br />

program 11<br />

user source file member 11<br />

compiling a UDF 164<br />

completing a unit of work 67<br />

complex search condition<br />

keyword <strong>for</strong> use in 72<br />

multiple search condition 72<br />

per<strong>for</strong>ming 72<br />

WHERE clause 31<br />

concurrency<br />

data 237<br />

definition 237<br />

condition<br />

keyword <strong>for</strong> use in search 72<br />

multiple search within a WHERE<br />

clause 74<br />

per<strong>for</strong>ming complex search 72<br />

CONNECT statement 257, 261<br />

interactive <strong>SQL</strong> 230<br />

connection<br />

DDM 275<br />

determining type 269<br />

ending DDM 275<br />

protected 269<br />

unprotected 269<br />

connection management<br />

ARD programs 279<br />

commitment control restrictions 272<br />

distributed unit of work<br />

considerations 274<br />

ending connections<br />

DDMCNV effect on 275<br />

DISCONNECT statement 275


connection management (continued)<br />

RELE<strong>AS</strong>E statement 275<br />

example 263<br />

implicit connection<br />

default activation group 267<br />

nondefault activation group 268<br />

implicit disconnection<br />

default activation group 267<br />

nondefault activation group 268<br />

multiple connections to same<br />

relational database 267<br />

connection status<br />

determining 273<br />

example 278<br />

consistency token 262<br />

consistent behavior and UDTs 173<br />

constant<br />

definition 40<br />

SET clause, value 33<br />

constraint 245<br />

definition 8<br />

referential 8<br />

unique 8<br />

constraint mechanisms on large<br />

objects 149<br />

constraints<br />

check 99<br />

referential<br />

check pending 107<br />

creating tables 100<br />

delete rules 105<br />

deleting from tables 105<br />

inserting into tables 102<br />

removing 102<br />

update rules 104<br />

updating tables 103<br />

control, commitment 239<br />

control in<strong>for</strong>mation to access large object<br />

data 151<br />

control structures 12<br />

convention<br />

<strong>SQL</strong> naming 4<br />

system naming 3<br />

conversion error 37<br />

CORPDATA.DEPARTMENT<br />

(department) 281<br />

CORPDATA.EMP_ACT (employee to<br />

project activity) 283<br />

CORPDATA.EMP_ACT table 283<br />

CORPDATA.EMPLOYEE table 282<br />

CORPDATA.PROJECT (project) 286<br />

CORPDATA.PROJECT table 286<br />

correlated<br />

names 90<br />

references 90<br />

correlated subquery<br />

definition 88<br />

DELETE statement, use in 91<br />

examples<br />

HAVING clause 90<br />

UPDATE statement 91<br />

WHERE clause 88<br />

noteonusing 92<br />

correlation<br />

definition 85<br />

name 23, 79<br />

using subquery 85<br />

cost of a UDT example 167<br />

counter <strong>for</strong> UDFs example 198<br />

counting and defining UDFs<br />

example 168<br />

CREATE COLLECTION statement 13<br />

CREATE DISTINCT TYPE statement<br />

and castability 161<br />

examples of using 175<br />

to define a UDT 174<br />

Create Duplicate Object (CRTDUPOBJ)<br />

command 250<br />

CREATE FUNCTION statement 194<br />

to register a UDF 165<br />

CREATE INDEX<br />

sort sequence 53<br />

CREATE SCHEMA<br />

statement 232<br />

Create <strong>SQL</strong> Package (CRT<strong>SQL</strong>PKG)<br />

command 259, 311<br />

authority required 260<br />

Create Structured Query Language<br />

Package (CRT<strong>SQL</strong>PKG) command 308<br />

CREATE TABLE<br />

prompting 223<br />

CREATE TABLE statement 14<br />

examples of using 175<br />

Create User Profile (CRTUSRPRF)<br />

command 236<br />

CREATE VIEW statement 29<br />

creating<br />

index<br />

example 96<br />

<strong>SQL</strong> collection<br />

example 13<br />

structured query language<br />

package 308<br />

table<br />

description 14<br />

example 14<br />

view 95<br />

description 28<br />

on a table 29<br />

over multiple tables 30<br />

creating ALI<strong>AS</strong> names 48<br />

cross join 78<br />

CRTDUPOBJ (Create Duplicate Object)<br />

command 250<br />

CRT<strong>SQL</strong>PKG (Create <strong>SQL</strong> Package)<br />

command 311<br />

CRT<strong>SQL</strong>PKG (Create Structured Query<br />

Language Package) command 308<br />

CRT<strong>SQL</strong>xxx commands 3<br />

CRTUSRPRF command<br />

create user profile 236<br />

ctr() UDF C program listing 198<br />

CURDATE scalar function 46<br />

CURRENT DATE special register 45<br />

current row 60<br />

CURRENT SERVER special register 45<br />

current session<br />

printing 227<br />

removing all entries from 227<br />

CURRENT TIME special register 45<br />

CURRENT TIMESTAMP special<br />

register 45<br />

CURRENT TIMEZONE special<br />

register 45<br />

cursor<br />

distributed unit of work 278<br />

example overview 56<br />

example steps 58, 62<br />

open 59<br />

open, effect of recovery on 67<br />

retrieving SELECT statement<br />

result 214<br />

scrollable<br />

positioning within a table 55<br />

serial<br />

positioning within a table 55<br />

using 55<br />

WITH HOLD clause 67<br />

CURTIME scalar function 46<br />

D<br />

damage tolerance<br />

data<br />

246<br />

adding to the end of table<br />

paging<br />

254<br />

retrieved<br />

retrieving<br />

253<br />

in reverse order<br />

updating<br />

253<br />

as it is retrieved 254<br />

previously retrieved 256<br />

view, processing 36<br />

data definition statement (DDL)<br />

data dictionary<br />

4<br />

WITH DATA DICTIONARY clause<br />

CREATE COLLECTION<br />

statement 6<br />

CREATE SCHEMA statement 6<br />

data independence 32, 38<br />

data integrity 99<br />

atomic operation 243<br />

commitment control 239<br />

concurrency 237<br />

constraint 245<br />

damage tolerance 246<br />

data definition statements (DDL) 243<br />

function 237<br />

index recovery 246<br />

journaling 239<br />

save/restore 245<br />

data manipulation statement (DML) 4<br />

data mapping error 37<br />

data protection<br />

data types<br />

235<br />

BLOBs 150<br />

CLOBs 150<br />

DBCLOBs 150<br />

object-oriented<br />

database<br />

149<br />

design, using the catalog in 97<br />

relational 3<br />

date <strong>for</strong>mat 47<br />

specifying current value 47<br />

date/time arithmetic 47<br />

<strong>DB2</strong> Multisystem 2<br />

<strong>DB2</strong> Query Manager <strong>for</strong> <strong>AS</strong>/<strong>400</strong> 2<br />

<strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> 1<br />

distributed relational database<br />

support 257<br />

<strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> sample table 281<br />

Index 335


<strong>DB2</strong> <strong>UDB</strong> Query Manager and <strong>SQL</strong><br />

Development Kit 1<br />

distributed relational database<br />

support 257<br />

<strong>DB2</strong> <strong>UDB</strong> Symmetric Multiprocessing 2<br />

<strong>DB2</strong> Universal Database<br />

considerations <strong>for</strong> packages 260<br />

DBCLOBs (Double-Byte Character Large<br />

OBjects)<br />

uses and definition 150<br />

DBCS (double-byte character set)<br />

considerations in interactive <strong>SQL</strong> 223<br />

DBGVIEW(*SOURCE) parameter 250<br />

dbinfo, passing to UDF 194<br />

DBINFO keyword 194<br />

dbminfo argument, elements of 194<br />

deadlock detection 238<br />

debugging 249<br />

common database problem 253<br />

program 250<br />

DECLARE CURSOR statement<br />

using 36<br />

DECLARE statement 200<br />

default collection name (DFTRDBCOL)<br />

parameter 3<br />

DEFAULT keyword<br />

SET clause, value 34<br />

default value 14, 18, 32<br />

inserting in a view 95<br />

define<br />

cursor 58<br />

defining<br />

column heading 16, 48<br />

table name 48<br />

defining the UDT and UDFs<br />

example 181<br />

definitions 257<br />

access plan 11<br />

authorization ID 3<br />

authorization name 3<br />

catalog 6<br />

collection 3, 6<br />

column 3, 6<br />

column name 39<br />

concurrency 237<br />

constant 40<br />

constraint 8<br />

correlated subquery 88<br />

correlation 85<br />

CURRENT DATE special register 45<br />

current row 60<br />

CURRENT SERVER special<br />

register 45<br />

CURRENT TIME special register 45<br />

CURRENT TIMESTAMP special<br />

register 45<br />

CURRENT TIMEZONE special<br />

register 45<br />

data definition statement (DDL) 4<br />

data dictionary 6<br />

data manipulation statement<br />

(DML) 4<br />

distributed unit of work 257<br />

expression 39<br />

field 3<br />

host variable 40<br />

index 8<br />

336 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5<br />

definitions 257 (continued)<br />

join 30<br />

join operation 23<br />

journal 6<br />

journal receiver 6<br />

library 3<br />

logical file 3<br />

null value 45<br />

NULL value 40<br />

outer-level SELECT 84<br />

output source file member 11<br />

package 3, 9, 12, 259<br />

physical file 3<br />

predicate 38<br />

program 11<br />

record 3<br />

referential integrity 8<br />

remote unit of work 257<br />

row 3, 6<br />

search condition 38<br />

special register 40<br />

<strong>SQL</strong> package 3<br />

<strong>SQL</strong>CODE 289<br />

<strong>SQL</strong>STATE 289<br />

stored procedure 8<br />

subquery 84<br />

table 3, 6<br />

trigger 8<br />

user profile 3<br />

user source file member 11<br />

USER special register 45<br />

view 3, 7<br />

delete current row 61<br />

Delete Library (DLTLIB) command 244<br />

Delete <strong>SQL</strong> Package (DLT<strong>SQL</strong>PKG)<br />

command 259, 312<br />

DELETE statement<br />

correlated subquery, use in 91<br />

description 28, 34<br />

Delete Structured Query Language<br />

Package (DLT<strong>SQL</strong>PKG) command 311<br />

deleting<br />

structured query language<br />

package 311<br />

deleting a column 94<br />

deleting in<strong>for</strong>mation in a table 28<br />

department table<br />

CORPDATA.DEPARTMENT 281<br />

DESCRIBE statement<br />

use with dynamic <strong>SQL</strong> 203<br />

DESCRIBE TABLE statement 261<br />

description<br />

<strong>SQL</strong>CODEs and <strong>SQL</strong>STATEs 291<br />

designing<br />

dynamic <strong>SQL</strong> application 201<br />

DFT_<strong>SQL</strong>MATHWARN configuration<br />

parameter 192, 195<br />

DFTRDBCOL (default collection name)<br />

parameter 3<br />

diagnostic-message, passing to UDF 193<br />

DISCONNECT statement 257, 261<br />

ending connection 275<br />

Display Message Description (DSPMSGD)<br />

command 289<br />

displaying <strong>SQL</strong>CODE and <strong>SQL</strong>STATE<br />

description 289<br />

DISTINCT 71<br />

DISTINCT 71 (continued)<br />

clause 72<br />

keyword 255<br />

distinct type 161<br />

distributed relational database<br />

accessing remote databases 229<br />

application requester 257<br />

application server 257<br />

committable updates 269, 273<br />

connection management 263<br />

multiple connections 267<br />

connection restrictions 272<br />

connection type<br />

determining 269<br />

protected 269<br />

unprotected 269<br />

consideration <strong>for</strong> creating<br />

packages 260<br />

creating packages 260<br />

<strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> support 257<br />

determining connection status 273<br />

distributed RUW example<br />

program 258<br />

distributed unit of work 257, 268,<br />

276<br />

ending connections<br />

DDMCNV effect on 275<br />

DISCONNECT statement 275<br />

RELE<strong>AS</strong>E statement 275<br />

first failure data capture (FFDC) 279<br />

implicit connection<br />

default activation group 267<br />

nondefault activation group 268<br />

implicit disconnection<br />

default activation group 267<br />

nondefault activation group 268<br />

interactive <strong>SQL</strong> 229<br />

packages 259<br />

statement in 260<br />

precompiler diagnostic messages 260<br />

problem handling 279<br />

protected connection 269<br />

protected resource 269<br />

remote unit of work 257, 268<br />

rollback required state 274<br />

session attributes 230<br />

<strong>SQL</strong> packages 259<br />

sync point manager 269<br />

two-phase commit 269<br />

unprotected connection 269<br />

unprotected resource 269<br />

valid <strong>SQL</strong> statements 260<br />

Distributed Relational Database<br />

Architecture (DRDA) 1<br />

distributed unit of work 257, 268, 276<br />

connection considerations 274<br />

connection status 273<br />

connection type 269<br />

cursors 278<br />

prepared statements 278<br />

sample program 276<br />

DLT<strong>SQL</strong>PKG (Delete <strong>SQL</strong> Package)<br />

command 312<br />

DLT<strong>SQL</strong>PKG (Delete Structured Query<br />

Language Package) command 311<br />

Double-Byte Character Large<br />

OBjects 150


DRDA (Distributed Relational Database<br />

Architecture) 257<br />

DRDA level 1 268<br />

DRDA level 2 268<br />

DRDA resource 269<br />

DROP PACKAGE statement 257<br />

duplicate rows<br />

eliminating 81<br />

preventing 71<br />

DUW (distributed unit of work) 257<br />

dynamic <strong>SQL</strong><br />

address variable 199<br />

allocating storage 205<br />

application 199, 201<br />

building and running statements 199<br />

CCSID 202<br />

cursor, use in 204<br />

DESCRIBE statement 203<br />

EXECUTE statement 201<br />

fixed-list SELECT statement,<br />

using 204<br />

parameter marker 215<br />

PREPARE statement 201<br />

processing non-SELECT<br />

statements 202<br />

replacing parameter markers with<br />

host variables 216<br />

run-time overhead 199<br />

statements 4<br />

varying-list SELECT statement 203<br />

E<br />

Edit Check Pending Constraints<br />

(EDTCPCST) command 245<br />

Edit Rebuild of Access Paths<br />

(EDTRBDAP) command 245<br />

Edit Recovery <strong>for</strong> Access Paths<br />

(EDTRCYAP) command 246<br />

eliminating duplicate rows 81<br />

employee-to-project activity table 283<br />

encapsulation and UDTs 173<br />

end-of-data<br />

reached 59<br />

entering DBCS data 223<br />

ERRLVL 232<br />

error<br />

data mapping<br />

ORDER BY 37<br />

error determination<br />

in distributed relational database<br />

first failure data capture<br />

(FFDC) 279<br />

establishing<br />

position at end of table 253<br />

examples 49<br />

AND 74<br />

application <strong>for</strong>ms using CREATE<br />

TABLE 175<br />

assignments in dynamic <strong>SQL</strong> 179<br />

assignments involving different<br />

UDTs 180<br />

assignments involving UDTs 179<br />

AVG over a UDT 167<br />

BETWEEN 72<br />

catalog<br />

getting column in<strong>for</strong>mation 97<br />

examples 49 (continued)<br />

catalog (continued)<br />

getting table in<strong>for</strong>mation 97<br />

changing in<strong>for</strong>mation in a table 25<br />

changing rows in table<br />

host variables 33, 34<br />

COMMENT ON 49<br />

comparisons involving UDTs 177,<br />

178<br />

correlated subquery<br />

HAVING clause 90<br />

WHERE clause 88<br />

correlation name 23<br />

cost of a UDT 167<br />

counter <strong>for</strong> UDFs 198<br />

counting and defining UDFs 168<br />

creating<br />

index 96<br />

<strong>SQL</strong> collection 13<br />

table 14<br />

view on a table 29<br />

views over multiple tables 30<br />

ctr() UDF C program listing 198<br />

CURRENT DATE 47<br />

CURRENT TIMEZONE 47<br />

cursor 56<br />

cursor in DUW program 278<br />

defining stored procedures<br />

with CREATE PROCEDURE 118<br />

defining the UDT and UDFs 181<br />

deleting in<strong>for</strong>mation in a table 28<br />

determining connection status 278<br />

distributed RUW program 258<br />

distributed unit of work<br />

program 276<br />

dynamic CALL 127<br />

embedded CALL 124, 125<br />

EXISTS 87<br />

exploiting LOB function to populate<br />

the database 182<br />

exploiting LOB locators to manipulate<br />

UDT instances 183<br />

exploiting UDFs to query instances of<br />

UDTs 183<br />

exponentiation and defining<br />

UDFs 165<br />

extracting a document to a file (CLOB<br />

elements in a table) 156<br />

function invocations 169<br />

getting catalog in<strong>for</strong>mation about<br />

column 97<br />

table 97<br />

getting comment 49<br />

getting in<strong>for</strong>mation about<br />

column using catalog 97<br />

table using catalog 97<br />

getting in<strong>for</strong>mation from<br />

multiple tables 23<br />

single table 20<br />

IN 73<br />

inserting<br />

add row to table 32<br />

multiple rows into a table 69<br />

inserting data into a CLOB<br />

column 158<br />

invoking stored procedures 127<br />

examples 49 (continued)<br />

where a CREATE PROCEDURE<br />

exists 124<br />

where no CREATE PROCEDURE<br />

exists 125<br />

join 76<br />

LABEL ON statement 16, 48<br />

LIKE 73<br />

list function in interactive <strong>SQL</strong> 224<br />

LOBFILE.SQB COBOL program<br />

listing 157<br />

LOBFILE.SQC C program listing 157<br />

LOBLOC.SQB COBOL program<br />

listing 154<br />

LOBLOC.SQC C program listing 153<br />

money using CREATE DISTINCT<br />

TYPE 175<br />

multiple search condition (WHERE<br />

clause) 74<br />

OR 74<br />

ORDER BY<br />

sort sequence 51<br />

parameter markers in functions 169<br />

preventing duplicate rows 71<br />

QSYSPRT listing<br />

<strong>SQL</strong> statement processor 233<br />

removing in<strong>for</strong>mation<br />

from table 28, 35<br />

resume using CREATE DISTINCT<br />

TYPE 175<br />

returning completion status<br />

to calling program 136<br />

sales using CREATE TABLE 175<br />

sample table 281<br />

search 72<br />

search string and BLOBs 166<br />

SELECT records<br />

sort sequence 52<br />

SELECT statement allocating storage<br />

<strong>for</strong> <strong>SQL</strong>DA 210<br />

selecting into table<br />

host variables 36<br />

special register 47<br />

stored procedures<br />

returning completion status 136<br />

string search and defining UDFs 166<br />

string search over UDT 167<br />

subquery 84<br />

Union<br />

simple 83<br />

UNION<br />

using host variables 81<br />

UNION ALL<br />

using host variables 83<br />

unqualified function reference 170<br />

UPDATE statement 25<br />

use of UDTs in UNION 180<br />

user-defined sourced functions on<br />

UDTs 178<br />

using a locator to work with a CLOB<br />

value 152<br />

using index 96<br />

using qualified function<br />

reference 170<br />

view<br />

sort sequence 53<br />

Index 337


examples 49 (continued)<br />

WITH C<strong>AS</strong>CADED CHECK<br />

OPTION 110<br />

WITH LOCAL CHECK OPTION 110<br />

working with index 96<br />

exception join 77<br />

EXECUTE IMMEDIATE statement 201<br />

EXECUTE privileges<br />

<strong>for</strong> packages 259<br />

EXECUTE statement 201, 202<br />

EXISTS keyword, use in subquery 87<br />

exiting interactive <strong>SQL</strong> 228<br />

exploiting<br />

LOB function to populate the database<br />

example 182<br />

LOB locators to manipulate UDT<br />

instances example 183<br />

UDFs to query instances of UDTs<br />

example 183<br />

exponentiation and defining UDFs<br />

example 165<br />

expression<br />

definition 39<br />

SET clause, value 34<br />

using in the WHERE clause 39<br />

extended dynamic<br />

QSQPRCED 2<br />

extensibility and UDTs 173<br />

extracting a document to a file (CLOB<br />

elements in a table) example 156<br />

F<br />

failed session, recovering 228<br />

FETCH<br />

using host structure array<br />

multiple-row 63<br />

FETCH statement 214<br />

FFDC (first failure data capture) 279<br />

field 3<br />

file reference variables<br />

examples of using 156<br />

<strong>for</strong> manipulating LOBs 150<br />

input values 155<br />

output values 156<br />

first failure data capture (FFDC) 279<br />

fixed-list SELECT statement<br />

definition 203<br />

using 203<br />

flexibility and UDTs 173<br />

FOR UPDATE OF clause<br />

restrictions 58<br />

<strong>for</strong>mat, <strong>SQL</strong>DA 206<br />

FROM clause 36<br />

function<br />

interactive <strong>SQL</strong> 219<br />

function invocations example 169<br />

function-name, passing to UDF 193<br />

function path and UDFs 162<br />

function references, summary <strong>for</strong><br />

UDFs 171<br />

function selection algorithm and<br />

UDFs 162<br />

functions<br />

aggregating functions 163<br />

column functions 163<br />

scalar functions 163<br />

syntax <strong>for</strong> referring to 169<br />

functions (continued)<br />

table functions 163<br />

G<br />

getting<br />

catalog in<strong>for</strong>mation about<br />

column 97<br />

table 97<br />

comment 49<br />

in<strong>for</strong>mation<br />

from multiple table 23<br />

from single table 20<br />

Grant Object Authority (GRTOBJAUT)<br />

command 235<br />

GRANT PACKAGE statement 257<br />

GROUP BY<br />

clause 41<br />

keyword 255<br />

using null value with 41<br />

grouping the row you select 41<br />

H<br />

HAVING clause 42<br />

host structure array<br />

multiple-row FETCH 63<br />

host variable<br />

definition 40<br />

SET clause, value 34<br />

338 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5<br />

I<br />

ID, authorization 236<br />

IDDU (interactive data definition<br />

utility) 6<br />

ILE programs<br />

package 261<br />

ILE service programs<br />

package 261<br />

immediate sensitivity 63, 67<br />

implementing a UDF 164<br />

implicit connect 267<br />

implicit disconnect 267<br />

IN keyword<br />

description 73<br />

subquery, use in 87<br />

in tray<br />

table 287<br />

IN_TRAY table 287<br />

index<br />

add 96<br />

definition 8<br />

recovery 246<br />

using 96<br />

working with 96<br />

indicator variables<br />

stored procedures 132<br />

indicator variables and LOB locators 155<br />

infix notation and UDFs 172<br />

in<strong>for</strong>mation, inserting into<br />

table 18<br />

inner join 75<br />

INSERT statement<br />

blocked 31<br />

default value 18, 32<br />

description 31<br />

INSERT statement (continued)<br />

VALUES clause 31<br />

inserting<br />

in<strong>for</strong>mation into table 18<br />

multiple rows<br />

into tables 69<br />

note 70<br />

inserting data into a CLOB column<br />

example 158<br />

instances of object-oriented data types,<br />

storing 149<br />

Integrated Language Environment (ILE)<br />

module 12<br />

program 11<br />

service program 12<br />

integrity<br />

catalog 247<br />

data 99, 237<br />

referential 99<br />

interactive data definition utility 6<br />

interactive interface<br />

concepts 2<br />

interactive <strong>SQL</strong><br />

accessing remote databases 229<br />

change session attributes 227<br />

description 219<br />

exiting 228<br />

function 219<br />

general use 219<br />

getting started 220<br />

overview 219<br />

package 230<br />

prompting<br />

DBCS consideration 223<br />

overview 219<br />

session services 219, 226, 228<br />

statement entry 219, 221<br />

statement processing mode 223<br />

terminology 3<br />

testing your <strong>SQL</strong> statements<br />

with 219, 228<br />

Interactive <strong>SQL</strong> 2<br />

adding DBCS data 223<br />

prompting 224<br />

syntax checking 223<br />

INTO clause<br />

description 32<br />

PREPARE statements 205<br />

restriction 210<br />

invoking UDFs 168<br />

J<br />

job attribute<br />

DDMCNV 275<br />

job-level commitment definition 267, 272<br />

join<br />

cross 78<br />

definitions 30<br />

exception 77<br />

inner 75<br />

left outer 76<br />

join operation<br />

definition 23<br />

in a view 30<br />

joining<br />

data from multiple tables 75<br />

table with WHERE clause 76


joining (continued)<br />

technique 79<br />

journal 6<br />

journal receiver 6<br />

journaling 239<br />

K<br />

keyword<br />

AND 74<br />

BETWEEN 72<br />

COMMIT 240<br />

DISTINCT 255<br />

EXISTS 87<br />

GROUP BY 255<br />

IN 73, 87<br />

LIKE 73<br />

NOT 40<br />

OR 74<br />

search condition, use in 72<br />

UNION 80, 255<br />

UNION ALL, specifying 83<br />

L<br />

LABEL ON statement 16, 48<br />

in<strong>for</strong>mation in catalog 48<br />

package 262<br />

large object descriptor 150<br />

large object value 150<br />

learn how to<br />

prompt<br />

using interactive <strong>SQL</strong> 224<br />

leaving interactive <strong>SQL</strong> 228<br />

left outer join 76<br />

library<br />

definition 3<br />

LIKE keyword 73<br />

linking a UDF 164<br />

list function 226<br />

list function in interactive <strong>SQL</strong><br />

description 224<br />

LOBEVAL.SQB COBOL program<br />

listing 157<br />

LOBEVAL.SQC C program listing 157<br />

LOBLOC.SQB COBOL program<br />

listing 154<br />

LOBLOC.SQC C program listing 153<br />

LOBs (Large Objects)<br />

and <strong>DB2</strong> object extensions 149<br />

file reference variables 150<br />

examples of using 156<br />

input values 155<br />

output values 156<br />

<strong>SQL</strong>_FILE_APPEND, output value<br />

option 156<br />

<strong>SQL</strong>_FILE_CREATE, output value<br />

option 156<br />

<strong>SQL</strong>_FILE_OVERWRITE, output<br />

value option 156<br />

<strong>SQL</strong>_FILE_READ, input value<br />

option 156<br />

large object descriptor 150<br />

large object value 150<br />

locators 150, 151<br />

example of using 152<br />

indicator variables 155<br />

LOBs (Large Objects) (continued)<br />

manipulating 149<br />

programming options <strong>for</strong> values 151<br />

storing 149<br />

synergy with UDTs and UDFs<br />

examples of complex<br />

applications 181<br />

locators <strong>for</strong> manipulating LOBs 150<br />

logical file 3, 7<br />

LONG VARCHAR<br />

storage limits 150<br />

LONG VARGRAPHIC<br />

storage limits 150<br />

Loosely Coupled Parallelism 2<br />

M<br />

manipulating large objects 149<br />

mapping error<br />

data 37<br />

marker, parameter 215<br />

maximum size <strong>for</strong> large object columns,<br />

defining 151<br />

member<br />

output source file 11<br />

user source file 11<br />

mode<br />

interactive <strong>SQL</strong> 223<br />

modelling entities as independent<br />

objects 149<br />

module<br />

Integrated Language Environment<br />

(ILE)<br />

object 12<br />

money using CREATE DISTINCT TYPE<br />

example 175<br />

moving large objects using a file<br />

reference variable 150<br />

multiple<br />

row<br />

inserting into a table 69<br />

notes on inserting 70<br />

search condition within a WHERE<br />

clause 74<br />

table<br />

joining data from 75<br />

multiple-row FETCH statement<br />

using<br />

descriptor area 64<br />

host structure arrays 63<br />

row storage area 64<br />

with languages 63<br />

N<br />

naming convention<br />

*<strong>SQL</strong> 3<br />

*SYS 3<br />

<strong>SQL</strong> 4<br />

system 3<br />

negative <strong>SQL</strong>CODEs 293<br />

non-SELECT statements, processing 202<br />

NOT keyword 40, 74<br />

NOW scalar function 46<br />

null value 45<br />

INSERT statement 32<br />

inserting in a view 95<br />

null value 45 (continued)<br />

SET clause, value 33<br />

UPDATE statement 33<br />

used with GROUP BY clause 41<br />

used with ORDER BY clause 44<br />

NULL value 14<br />

definition 40<br />

numeric conversion error 38<br />

O<br />

object<br />

application program 9<br />

collection 3<br />

module 9<br />

Integrated Language Environment<br />

(ILE) 12<br />

package 9<br />

program<br />

Integrated Language Environment<br />

(ILE) 11<br />

service program 9<br />

Integrated Language Environment<br />

(ILE) 12<br />

<strong>SQL</strong> 5<br />

object-orientation and UDFs 160<br />

object-oriented extensions and UDTs 173<br />

object-relational<br />

application domain and<br />

object-orientation 149<br />

constraint mechanisms 149<br />

data types 149<br />

definition 149<br />

LOBs 149<br />

support <strong>for</strong> 150<br />

triggers 149<br />

UDTs and UDFs 149<br />

why use the <strong>DB2</strong> object<br />

extensions 149<br />

ODBC 201<br />

open cursor<br />

during a unit of work 67<br />

open database connectivity (ODBC) 201<br />

OPEN statement 215<br />

operation, atomic 243<br />

operators, comparison 40<br />

ORDER BY<br />

clause 43<br />

using null values with 44<br />

data mapping errors 37<br />

sort sequence, using 50<br />

using 51<br />

outer join 76<br />

outer-level SELECT 84<br />

output source file member<br />

definition 11<br />

overloaded function names and<br />

UDFs 162<br />

Override Database File (OVRDBF)<br />

command 62, 237<br />

overview, interactive <strong>SQL</strong> 219<br />

P<br />

package<br />

authority to create 259<br />

authority to run 259<br />

Index 339


package (continued)<br />

bind to an application 9<br />

CCSID considerations <strong>for</strong> 263<br />

consistency token 262<br />

Create <strong>SQL</strong> Package (CRT<strong>SQL</strong>PKG)<br />

command 259<br />

authority required 260<br />

creating<br />

authority required 259<br />

effect of ARD programs 279<br />

errors during 260<br />

on local system 262<br />

RDB parameter 259<br />

RDBCNNMTH parameter 262<br />

TGTRLS parameter 261<br />

type of connection 262<br />

unit of work boundary 262<br />

creating on a non-<strong>DB2</strong> <strong>UDB</strong> <strong>for</strong><br />

<strong>AS</strong>/<strong>400</strong><br />

errors during 260<br />

required precompiler options <strong>for</strong><br />

<strong>DB2</strong> Common Server 260<br />

unsupported precompiler<br />

options 260<br />

<strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> support 259<br />

definition 9, 12, 259<br />

Delete <strong>SQL</strong> Package (DLT<strong>SQL</strong>PKG)<br />

command 259<br />

deleting 259<br />

interactive <strong>SQL</strong> 230<br />

labeling 262<br />

restore 262<br />

save 262<br />

<strong>SQL</strong> statement size 261<br />

statements that do not require<br />

package 261<br />

paging<br />

retrieved data 253<br />

parameter markers<br />

in functions example 169<br />

parameter passing<br />

stored procedures 128, 132<br />

table 128<br />

parameters<br />

marker 215<br />

passing argument to UDF<br />

call-type 194<br />

dbinfo 194<br />

diagnostic-message 193<br />

function-name 193<br />

scratchpad 193<br />

specific-name 193<br />

<strong>SQL</strong>-argument 194, 195<br />

<strong>SQL</strong>-argument-ind 192<br />

<strong>SQL</strong>-argument-ind-array 195<br />

<strong>SQL</strong>-result 194, 195<br />

<strong>SQL</strong>-result-ind 192, 195<br />

<strong>SQL</strong>-state 192<br />

pending<br />

check 107<br />

per<strong>for</strong>mance<br />

UDFs 160<br />

per<strong>for</strong>mance and UDTs 173<br />

per<strong>for</strong>mance verification 251<br />

per<strong>for</strong>ming complex search condition 72<br />

physical file 3, 6<br />

positive <strong>SQL</strong>CODEs 291<br />

precompiler<br />

concepts 1<br />

diagnostic messages 260<br />

precompiler command<br />

CRT<strong>SQL</strong>xxx 50, 260<br />

precompiler parameter<br />

DBGVIEW(*SOURCE) 250<br />

predicate<br />

definition 38<br />

PREPARE statement<br />

non-SELECT statement 202<br />

restrictions 201<br />

using 215<br />

prepared statement<br />

distributed unit of work 278<br />

preventing duplicate rows 71<br />

printing current session 227<br />

problems, solving database 253<br />

processing<br />

data in a view 36<br />

non-SELECT statements 202<br />

SELECT statement with <strong>SQL</strong>DA 203<br />

program<br />

application 249<br />

debugging 250<br />

definition 11<br />

Integrated Language Environment<br />

(ILE) object 11<br />

non-ILE object 11<br />

per<strong>for</strong>mance verification 251<br />

project table 286<br />

prompt<br />

using interactive <strong>SQL</strong> 219, 224<br />

prompting<br />

CREATE TABLE 223<br />

function 219, 221<br />

overview 219<br />

subqueries 223<br />

protected connections<br />

dropping 272<br />

protected resource 269<br />

protection, data 235<br />

public authority 235<br />

Q<br />

QSQCHKS 2<br />

QSQPRCED 2<br />

package 9<br />

QSYS2<br />

catalog views 6<br />

QSYSPRT listing<br />

<strong>SQL</strong> statement processor<br />

example 233<br />

R<br />

re-use and UDFs 160<br />

read-only<br />

table 59<br />

view 95<br />

read-only connection 269<br />

receiver, journal 6<br />

Reclaim DDM connections<br />

(RCLDDMCNV) command 275<br />

record, definition 3<br />

record selection 52<br />

340 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5<br />

record selection 52 (continued)<br />

sort sequence, using 50<br />

recovering<br />

effect on open cursor 67<br />

index 246<br />

interactive <strong>SQL</strong><br />

saved or failed session 228<br />

referential constraints<br />

check pending 107<br />

creating tables 100<br />

definition 8<br />

delete rules 105<br />

deleting from tables 105<br />

inserting into tables 102<br />

removing 102<br />

update rules 104<br />

updating tables 103<br />

referential integrity 99<br />

definition 8<br />

registering<br />

UDFs 164<br />

related in<strong>for</strong>mation 331<br />

relational database 3<br />

RELE<strong>AS</strong>E statement 257, 261<br />

ending connection 275<br />

remote databases<br />

accessing from interactive <strong>SQL</strong> 229<br />

remote unit of work 257, 268<br />

connection status 273<br />

connection type 269<br />

example program 258<br />

removing all entries from current<br />

session 227<br />

restriction<br />

FOR UPDATE OF 255<br />

result table 80<br />

resume using CREATE DISTINCT TYPE<br />

example 175<br />

Retrieve Message (RTVMSG)<br />

command 289<br />

retrieving<br />

data<br />

from a table. 20<br />

in reverse order 253<br />

row<br />

using a cursor 60<br />

SELECT statement result<br />

cursor, using 214<br />

return code 38<br />

RETURNS TABLE clause 192, 194, 195<br />

reuse deleted records<br />

INSERT 33<br />

Revoke Object Authority (RVKOBJAUT)<br />

command 235<br />

REVOKE PACKAGE statement 257<br />

REXX 2<br />

rollback<br />

rollback required state 274<br />

ROLLBACK<br />

prepared statements 203<br />

ROLLBACK statement 261<br />

row<br />

definition 3, 6<br />

delete current 61<br />

inserting multiple<br />

into a table 69<br />

note 70


ow (continued)<br />

preventing duplicate 71<br />

RRN scalar function 77<br />

rules that govern operations on large<br />

objects 149<br />

run mode<br />

interactive <strong>SQL</strong> 223<br />

Run <strong>SQL</strong> Statements (RUN<strong>SQL</strong>STM)<br />

command 2<br />

run-time support<br />

concepts 1<br />

running<br />

dynamic <strong>SQL</strong> application 201<br />

RUN<strong>SQL</strong>STM (Run <strong>SQL</strong><br />

Statements) 227, 228<br />

command 2, 231<br />

command errors 232<br />

commitment control 232<br />

RUN<strong>SQL</strong>STM (Run <strong>SQL</strong> Statements)<br />

command 323<br />

RUW (remote unit of work) 257<br />

S<br />

sales using CREATE TABLE<br />

example 175<br />

sample programs<br />

distributed RUW program 258<br />

sample tables <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> 281<br />

save/restore 245<br />

packages 262<br />

saved session<br />

in a source file 227, 228<br />

recovering 228<br />

scalar functions 163<br />

schedule table<br />

class 287<br />

schema-name and UDFs 162<br />

schemas<br />

<strong>SQL</strong> statement processor 232<br />

scratchpad, passing to UDF 193<br />

scrollable cursor 55<br />

search condition<br />

definition 38<br />

per<strong>for</strong>ming complex 72<br />

subqueries 85<br />

using keyword in 72<br />

security 235<br />

authorization 250<br />

authorization ID 236<br />

commitment control 239<br />

data integrity 237<br />

concurrency 237<br />

public authority 235<br />

view 236<br />

SELECT clause 38<br />

select in<strong>for</strong>mation<br />

into host variables 36<br />

SELECT INTO statement<br />

restriction 201<br />

retrieving row 35<br />

SELECT statement<br />

definition 20<br />

example of allocating storage <strong>for</strong><br />

<strong>SQL</strong>DA 210<br />

processing and using <strong>SQL</strong>DA 203<br />

using fixed-list 203<br />

using varying-list 204<br />

selecting<br />

column 70<br />

semantic behavior of stored objects 149<br />

Send Program Message (SNDPGMMSG)<br />

command 289<br />

Send User Message (SNDUSRMSG)<br />

command 289<br />

sensitivity<br />

immediate 63, 67<br />

serial cursor 55<br />

service program<br />

Integrated Language Environment<br />

(ILE)<br />

object 12<br />

services, session 226<br />

session 228<br />

printing current 227<br />

removing all entries from<br />

current 227<br />

saving in a source file 227, 228<br />

session services<br />

in interactive <strong>SQL</strong> 219, 226, 228<br />

SET clause<br />

description 33<br />

value<br />

column name 33<br />

constant 33<br />

expression 34<br />

host variable 34<br />

null 33<br />

scalar subselect 34<br />

special register 34<br />

SET CONNECTION statement 257, 261<br />

SET CURRENT FUNCTION PATH<br />

statement 164<br />

SET TRANSACTION statement<br />

effect on implicit disconnect 267<br />

not allowed in package 260<br />

SEU (source entry utility) 228<br />

signature, two functions and the<br />

same 162<br />

SMALLINT 192, 195<br />

solving 253<br />

common database problem 253<br />

solving common problems 253<br />

SOME 86<br />

sort sequence<br />

CREATE INDEX 53<br />

used with ORDER BY 50<br />

used with record selection 50<br />

using 50<br />

views 53<br />

source entry utility (SEU) 228<br />

source file<br />

<strong>for</strong> RUN<strong>SQL</strong>STM 231<br />

member, output<br />

definition 11<br />

member, user 11<br />

saving a session in 227, 228<br />

sourced UDF 177<br />

special register<br />

CURRENT DATE 45<br />

CURRENT SERVER 45<br />

CURRENT TIME 45<br />

CURRENT TIMESTAMP 45<br />

CURRENT TIMEZONE 45<br />

definition 40<br />

special register (continued)<br />

SET clause, value 34<br />

USER 45<br />

specific-name, passing to UDF<br />

specifying<br />

193<br />

column, SELECT INTO statement 38<br />

UNION ALL 83<br />

<strong>SQL</strong> 1<br />

call level interface 2<br />

introduction 1<br />

object 5<br />

statements<br />

types 4<br />

<strong>SQL</strong>-argument, passing to UDF 194, 195<br />

<strong>SQL</strong>-argument 192<br />

<strong>SQL</strong>-argument-ind, passing to UDF<br />

<strong>SQL</strong>-argument-ind-array, passing to<br />

192<br />

UDF 195<br />

<strong>SQL</strong> collection 13<br />

<strong>SQL</strong>_FILE_READ, input value<br />

option 156<br />

<strong>SQL</strong> naming convention 4<br />

<strong>SQL</strong> package 3<br />

<strong>SQL</strong>-result, passing to UDF 194, 195<br />

<strong>SQL</strong>-result 192<br />

<strong>SQL</strong>-result-ind, passing to UDF 192, 195<br />

<strong>SQL</strong>-state, passing to UDF<br />

<strong>SQL</strong> statement processor<br />

192<br />

commitment control<br />

example<br />

232<br />

QSYSPRT listing 233<br />

schemas 232<br />

using 231<br />

<strong>SQL</strong>CODEs<br />

definition 289<br />

description 291<br />

negative 293<br />

positive 291<br />

testing application program 250<br />

<strong>SQL</strong>D 206<br />

<strong>SQL</strong>DA (<strong>SQL</strong> descriptor area)<br />

allocating storage <strong>for</strong> 210<br />

<strong>for</strong>mat 206<br />

processing SELECT statement 203<br />

programming language, use in 205<br />

SELECT statement <strong>for</strong> allocating<br />

storage <strong>for</strong> <strong>SQL</strong>DA 210<br />

<strong>SQL</strong>DABC 206<br />

<strong>SQL</strong>DAID 206<br />

<strong>SQL</strong>DATA 208<br />

<strong>SQL</strong>ERRD field of <strong>SQL</strong>CA<br />

<strong>SQL</strong>ERRD(3) field of <strong>SQL</strong>CA<br />

determining connection<br />

status 273<br />

determining number of rows<br />

fetched 63<br />

<strong>SQL</strong>ERRD(4) field of <strong>SQL</strong>CA 273<br />

determining connection type 269<br />

determining length of each row<br />

retrieved 63<br />

<strong>SQL</strong>ERRD(5) field of <strong>SQL</strong>CA<br />

determining end-of-file 63<br />

<strong>SQL</strong>IND 208<br />

<strong>SQL</strong>LEN 207<br />

<strong>SQL</strong>N 206<br />

<strong>SQL</strong>NAME 209<br />

<strong>SQL</strong>RES 208<br />

Index 341


<strong>SQL</strong>STATEs<br />

code definition 289<br />

definition 289<br />

description 291<br />

testing application program 250<br />

<strong>SQL</strong>TYPE 206<br />

sqludf.h include file <strong>for</strong> UDFs 194<br />

<strong>SQL</strong>VAR 206<br />

Start Commitment Control<br />

(STRCMTCTL) command 240<br />

Start Journal Access Path (STRJRNAP)<br />

command 246<br />

Start <strong>SQL</strong> (STR<strong>SQL</strong>) command 330<br />

starting interactive <strong>SQL</strong> 220<br />

statement entry 219, 221<br />

statement processing mode<br />

interactive <strong>SQL</strong> 223<br />

statements 45<br />

ALI<strong>AS</strong> statement<br />

example 48<br />

basic, using 31<br />

COMMENT ON statement 49<br />

COMMIT 6<br />

CONNECT 257<br />

CREATE COLLECTION 13<br />

CREATE INDEX<br />

sort sequence 53<br />

CREATE PROCEDURE<br />

external procedure 117<br />

<strong>SQL</strong> procedure 117<br />

CREATE SCHEMA 232<br />

CREATE TABLE 14<br />

CREATE VIEW 29<br />

data definition (DDL) 4<br />

data manipulation (DML) 4<br />

date value 47<br />

DECLARE CURSOR 36<br />

DELETE<br />

example 34<br />

WHERE clause 28<br />

DISCONNECT 257<br />

DROP PACKAGE 257<br />

dynamic 4<br />

EXECUTE 201, 202<br />

FETCH 214<br />

multiple-row 62<br />

GRANT PACKAGE 257<br />

INSERT<br />

using 31<br />

LABEL ON statement<br />

example 48<br />

examples 16<br />

multiple-row FETCH 64<br />

OPEN 215<br />

package not required 261<br />

packages 260<br />

PREPARE<br />

cursor 215<br />

non-SELECT statement 202<br />

using 201<br />

processing non select 202<br />

RELE<strong>AS</strong>E 257<br />

REVOKE PACKAGE 257<br />

ROLLBACK 6<br />

select 20<br />

SELECT INTO<br />

example 35<br />

statements 45 (continued)<br />

SELECT INTO (continued)<br />

processing data (view) 36<br />

restriction 201<br />

specifying column 38<br />

SET CONNECTION 257<br />

<strong>SQL</strong> packages 260<br />

testing<br />

in application program 249<br />

using interactive <strong>SQL</strong> 219, 228<br />

time value 47<br />

timestamp value 47<br />

UPDATE<br />

changing data value 25<br />

example 33<br />

stopping interactive <strong>SQL</strong> 228<br />

storage, allocating <strong>for</strong> <strong>SQL</strong>DA 210<br />

stored procedures 117, 145<br />

definition 8<br />

parameter passing 128<br />

indicator variables 132<br />

table 128<br />

storing large objects 149<br />

string search and defining UDFs<br />

example 166<br />

string search on BLOBs 166<br />

string search over UDT example 167<br />

strong typing and UDTs 176<br />

STR<strong>SQL</strong> (Start <strong>SQL</strong>) command 220, 330<br />

Structured Query Language 1<br />

structured query language package<br />

creating 308<br />

deleting 311<br />

subquery 88<br />

basic comparison 86<br />

correlated 85, 88<br />

correlated names and references 90<br />

definition 84<br />

examples 84<br />

EXISTS keyword 87<br />

IN keyword 87<br />

notes on using<br />

with UPDATE and DELETE 88<br />

prompting 223<br />

quantified comparison 86<br />

search condition 85<br />

subselect<br />

combining with the UNION keyword,<br />

example 80<br />

SET clause, value 34<br />

Symmetric Multiprocessing 2<br />

sync point manager 269<br />

syntax check<br />

QSQCHKS 2<br />

syntax check mode<br />

interactive <strong>SQL</strong> 223<br />

syntax <strong>for</strong> referring to functions 169<br />

system naming convention 3<br />

system table name 17<br />

T<br />

table<br />

adding data to the end 254<br />

changing definition 92, 256<br />

changing in<strong>for</strong>mation in 25<br />

CL_SCHED (class schedule) 287<br />

342 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5<br />

table (continued)<br />

CORPDATA.DEPARTMENT<br />

(department) 281<br />

CORPDATA.EMP_ACT (employee to<br />

project activity) 283<br />

CORPDATA.EMPLOYEE 282<br />

CORPDATA.PROJECT (project) 286<br />

creating<br />

CREATE TABLE statement 14<br />

view 29<br />

<strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> sample 281<br />

defining name 48<br />

definition 3, 6<br />

deleting in<strong>for</strong>mation in 28<br />

establishing position at the end 253<br />

getting catalog in<strong>for</strong>mation<br />

about column 97<br />

getting in<strong>for</strong>mation<br />

from multiple 23<br />

from one 20<br />

IN_TRAY 287<br />

inserting<br />

in<strong>for</strong>mation into 18<br />

multiple rows into 69<br />

joining 75<br />

the WHERE clause 76<br />

multiple<br />

creating view over 30<br />

sample 281<br />

used in examples<br />

CORPDATA.DEPARTMENT<br />

(department) 281<br />

CORPDATA.EMP_ACT (employee<br />

to project activity) 283<br />

CORPDATA.EMPLOYEE 282<br />

CORPDATA.PROJECT<br />

(project) 286<br />

using 14<br />

table functions 163<br />

contents of call-type argument 194<br />

table name<br />

system 17<br />

technique<br />

coding 31, 55, 69<br />

solving database problem 253<br />

terminology<br />

interactive <strong>SQL</strong> 3<br />

relational database 3<br />

relationship table<br />

*<strong>SQL</strong> 3<br />

*SYS 3<br />

testing<br />

authorization 249, 250<br />

debugging your program 250<br />

input data 249<br />

per<strong>for</strong>mance verification 251<br />

<strong>SQL</strong> statements using interactive<br />

<strong>SQL</strong> 219, 228<br />

statements in application<br />

program 249<br />

view 249<br />

time <strong>for</strong>mat 47<br />

specifying current value 47<br />

timestamp <strong>for</strong>mat 47<br />

specifying current value 47<br />

tolerance, damage 246


trigger<br />

definition 8<br />

event 8<br />

trigger support 111<br />

triggers<br />

and <strong>DB2</strong> object extensions 149<br />

truncation error 37<br />

two-phase commit 269<br />

typing<br />

interactive <strong>SQL</strong> 221<br />

U<br />

UDFs (User-defined functions)<br />

and <strong>DB2</strong> object extensions 149<br />

casting 172<br />

concepts 162<br />

definition 160<br />

function path 162<br />

function selection algorithm 162<br />

general considerations 172<br />

implementing UDFs 160<br />

infix notation 172<br />

invoking<br />

examples of invocations 168<br />

parameter markers in<br />

functions 169<br />

qualified function reference 170<br />

unqualified function<br />

reference 170<br />

LOB types 172<br />

overloaded function names 162<br />

process of implementation 164<br />

referring to functions 169<br />

registering UDFs 165<br />

examples of registering 165<br />

schema-name and UDFs 162<br />

sourced 177<br />

summary of function references 171<br />

synergy with UDTs and LOBs<br />

examples of complex<br />

applications 181<br />

type of functions 163<br />

unqualified reference 162<br />

why use UDFs 160<br />

writing your own UDF 189<br />

UDFs and LOB types 172<br />

UDTs (User-defined types)<br />

and <strong>DB2</strong> object extensions 149<br />

defining a UDT 174<br />

defining tables 175<br />

manipulating<br />

examples of 176<br />

resolving unqualified UDTs 174<br />

strong typing 176<br />

synergy with UDFs and LOBs<br />

examples of complex<br />

applications 181<br />

why use UDTs 173<br />

UNION ALL, specifying 83<br />

UNION keyword<br />

restriction 255<br />

using to combine subselects 80<br />

unique constraint<br />

definition 8<br />

unit of work<br />

distributed 257<br />

unit of work (continued)<br />

effect on open cursor 67<br />

package creation 262<br />

remote 257<br />

rollback required 274<br />

unit of work boundary<br />

package creation 262<br />

unprotected resource 269<br />

unqualified function reference<br />

example 170<br />

unqualified reference 162<br />

UPDATE statement<br />

correlated subquery, using in 91<br />

description 33<br />

WHERE clause 25<br />

updating data<br />

as it is retrieved, restrictions 254<br />

committable updates 269<br />

previously retrieved 256<br />

use of UDTs in UNION example 180<br />

user auxiliary storage pool (<strong>AS</strong>P) 247<br />

user-defined sourced functions on UDTs<br />

example 178<br />

user profile<br />

authorization ID 3<br />

authorization name 3<br />

user source file member<br />

definition 11<br />

USER special register 45<br />

using<br />

blocked insert statement 70<br />

cursor<br />

example 56<br />

retrieve row 60<br />

date value 47<br />

index 96<br />

null value 45<br />

ORDER BY 51<br />

parameter markers 215<br />

record selection 52<br />

sort sequence 50<br />

time value 47<br />

timestamp value 47<br />

Using<br />

views 95<br />

USING<br />

clause 212<br />

DESCRIPTOR clause 215<br />

using a locator to work with a CLOB<br />

value example 152<br />

using interactive <strong>SQL</strong> 219<br />

after first time 226<br />

list selection function 224<br />

prompting 221<br />

statement entry 221<br />

using qualified function reference<br />

example 170<br />

V<br />

validate mode<br />

interactive <strong>SQL</strong> 223<br />

value<br />

default 14, 18<br />

inserting<br />

into table or view 31<br />

VALUES clause 31<br />

varying-list SELECT statement<br />

definition 204<br />

varying-list SELECT statement (continued)<br />

using 204<br />

verification<br />

per<strong>for</strong>mance 251<br />

view<br />

creating 95<br />

CREATE VIEW statement 28<br />

on a table 29<br />

over multiple tables 30<br />

definition 3, 7<br />

limiting access 28<br />

processing data in 36<br />

read-only 95<br />

security 236<br />

sort sequence 53<br />

testing 249<br />

using 95<br />

WITH C<strong>AS</strong>CADED CHECK 108<br />

WITH CHECK 108<br />

WITH LOCAL CHECK 109<br />

W<br />

WHENEVER NOT FOUND clause 60<br />

WHERE clause<br />

character string 31<br />

constant 39<br />

description 38<br />

example 215<br />

expression in, using 39<br />

joining tables 76<br />

multiple search condition within<br />

a 74<br />

NOT keyword 40<br />

WHERE CURRENT OF clause 61<br />

WITH C<strong>AS</strong>CADED CHECK<br />

OPTION 108<br />

WITH CHECK OPTION 108<br />

WITH DATA DICTIONARY clause<br />

CREATE COLLECTION statement 6<br />

CREATE SCHEMA statement 6<br />

creating data dictionary 6<br />

WITH LOCAL CHECK OPTION 109<br />

working with<br />

index 96<br />

X<br />

X/Open call level interface 2<br />

Index 343


344 <strong>DB2</strong> <strong>UDB</strong> <strong>for</strong> <strong>AS</strong>/<strong>400</strong> <strong>SQL</strong> <strong>Programming</strong> <strong>Concepts</strong> V4R5


����<br />

Printed in U.S.A.

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!

哆哆女性网饲料贸易公司起名免费免费网起名周易公司起名免费取名设计菜谱网站新生儿生辰八字免费起名卿本佳人出租房起名烟花易冷周杰伦下载上海seo关键词优化软件属水的字女孩起名建筑未解之谜网站建设 威海飞夺泸定桥电影姓阮起名电商 网站建设手机小游戏seo收录是什么姓包男孩起名大全面试网站建设的问题周易生辰八字生辰八字免费起名周易全书目录胡姓起名胡姓小孩取名大全周易秘义韦氏起名女孩名字大全崔怎么起名男孩周易取名称大全生辰八字星际种田记霍元甲歌曲马革裹尸的意思给男孩起名字木字旁淀粉肠小王子日销售额涨超10倍罗斯否认插足凯特王妃婚姻不负春光新的一天从800个哈欠开始有个姐真把千机伞做出来了国产伟哥去年销售近13亿充个话费竟沦为间接洗钱工具重庆警方辟谣“男子杀人焚尸”男子给前妻转账 现任妻子起诉要回春分繁花正当时呼北高速交通事故已致14人死亡杨洋拄拐现身医院月嫂回应掌掴婴儿是在赶虫子男孩疑遭霸凌 家长讨说法被踢出群因自嘲式简历走红的教授更新简介网友建议重庆地铁不准乘客携带菜筐清明节放假3天调休1天郑州一火锅店爆改成麻辣烫店19岁小伙救下5人后溺亡 多方发声两大学生合买彩票中奖一人不认账张家界的山上“长”满了韩国人?单亲妈妈陷入热恋 14岁儿子报警#春分立蛋大挑战#青海通报栏杆断裂小学生跌落住进ICU代拍被何赛飞拿着魔杖追着打315晚会后胖东来又人满为患了当地回应沈阳致3死车祸车主疑毒驾武汉大学樱花即将进入盛花期张立群任西安交通大学校长为江西彩礼“减负”的“试婚人”网友洛杉矶偶遇贾玲倪萍分享减重40斤方法男孩8年未见母亲被告知被遗忘小米汽车超级工厂正式揭幕周杰伦一审败诉网易特朗普谈“凯特王妃P图照”考生莫言也上北大硕士复试名单了妈妈回应孩子在校撞护栏坠楼恒大被罚41.75亿到底怎么缴男子持台球杆殴打2名女店员被抓校方回应护栏损坏小学生课间坠楼外国人感慨凌晨的中国很安全火箭最近9战8胜1负王树国3次鞠躬告别西交大师生房客欠租失踪 房东直发愁萧美琴窜访捷克 外交部回应山西省委原副书记商黎光被逮捕阿根廷将发行1万与2万面值的纸币英国王室又一合照被质疑P图男子被猫抓伤后确诊“猫抓病”

哆哆女性网 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化