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