DB2 UDB For AS400 SQL Programming1

Download as pdf or txt
Download as pdf or txt
You are on page 1of 358

AS/400e

DB2 UDB for AS/400 SQL Programming Concepts


V ersion 4

AS/400e

DB2 UDB for AS/400 SQL Programming Concepts


V ersion 4

Copyright International Business Machines Corporation 2000. All rights reserved. US Government Users Restricted Rights Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.

Contents
About DB2 UDB for AS/400 SQL Programming Concepts . . . . . . . vii
Who should read this book . . . . . . . . . vii Assumptions relating to examples of SQL statements. . . . . . . . . . . . . . vii How to interpret syntax diagrams in this guide viii Whats new in the V4R5 version of the SQL programming concepts information . . . . . . ix Example: Creating a view combining data from more than one table . . . . . . . . . . 30

Chapter 3. Basic Concepts and Techniques . . . . . . . . . . . . . 31


Using basic SQL statements and clauses . . . . . Inserting rows using the INSERT statement. . . Changing data in a table using the UPDATE statement . . . . . . . . . . . . . . Removing rows from a table using the DELETE statement . . . . . . . . . . . . . . Querying data using the SELECT INTO statement . . . . . . . . . . . . . . Data retrieval errors . . . . . . . . . . The SELECT clause . . . . . . . . . . . Specifying a search condition using the WHERE clause . . . . . . . . . . . . . . . The GROUP BY clause . . . . . . . . . HAVING clause . . . . . . . . . . . . ORDER BY clause . . . . . . . . . . . Null Values to indicate absence of column values in a row . . . . . . . . . . . . . . . . Special registers in SQL statements . . . . . . Date, Time, and Timestamp data types . . . . . Specifying current date and time values . . . . Date/Time arithmetic . . . . . . . . . . Creating and using ALIAS names . . . . . . . Creating descriptive labels using the LABEL ON statement . . . . . . . . . . . . . . . Describing an SQL object using COMMENT ON . . Getting comments after running a COMMENT ON statement . . . . . . . . . . . . Sort sequences in SQL . . . . . . . . . . . Sort sequence used with ORDER BY and record selection . . . . . . . . . . . . . . ORDER BY . . . . . . . . . . . . . Record selection . . . . . . . . . . . . Sort sequence and views . . . . . . . . . Sort Sequence and the CREATE INDEX Statement . . . . . . . . . . . . . . Sort sequence and constraints . . . . . . . 31 31 33 34 35 37 38 38 41 42 43 45 45 47 47 47 48 48 49 49 50 50 51 52 53 53 54

Chapter 1. Introduction to DB2 UDB for AS/400 Structured Query Language . . . 1


SQL concepts . . . . . . . . . . . . . SQL relational database and system terminology Types of SQL statements . . . . . . . . SQL objects . . . . . . . . . . . . . . Collections . . . . . . . . . . . . . Tables, Rows, and Columns . . . . . . . Aliases . . . . . . . . . . . . . . Views. . . . . . . . . . . . . . . Indexes . . . . . . . . . . . . . . Constraints . . . . . . . . . . . . . Triggers . . . . . . . . . . . . . . Stored Procedures . . . . . . . . . . User-defined functions . . . . . . . . . User-defined type. . . . . . . . . . . SQL Packages . . . . . . . . . . . . Application program objects . . . . . . . . User source file member . . . . . . . . Output source file member . . . . . . . Program . . . . . . . . . . . . . SQL Package . . . . . . . . . . . . Module . . . . . . . . . . . . . . Service program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 3 4 5 6 6 7 7 8 8 8 9 9 9 9 9 11 11 11 12 12 12

Chapter 2. Getting Started with SQL . . 13


Starting interactive SQL . . . . . . . . . Creating an SQL collection . . . . . . . . Example: Creating the SQL Collection (SAMPLECOLL) . . . . . . . . . . . Creating and using a table . . . . . . . . Example: Creating a table (INVENTORY_LIST) Creating the Supplier Table (SUPPLIERS) . . Using the LABEL ON statement . . . . . . Inserting information into a table . . . . . . Example: Inserting information into a table (INVENTORY_LIST) . . . . . . . . . Getting information from a single table . . . . Getting information from more than one table . . Changing information in a table . . . . . . Example: Changing information in a table . . Deleting information from a table . . . . . . Example: Deleting information from a table (INVENTORY_LIST) . . . . . . . . . Creating and using a view . . . . . . . . Example: Creating a view on a single table . .
Copyright IBM Corp. 2000

. 13 . 13 . 14 . 14 14 . 16 . 16 . 18 . . . . . . 18 20 23 25 25 28

Chapter 4. Using a Cursor . . . . . . 55


Types of cursors . . . . . . . . . . . Serial cursor . . . . . . . . . . . Scrollable cursor . . . . . . . . . . Example of using a cursor . . . . . . . Step 1: Define the cursor . . . . . . . Step 2: Open the cursor . . . . . . . Step 3: Specify what to do when end-of-data reached . . . . . . . . . . . . . Step 4: Retrieve a row using a cursor . . . Step 5a: Update the current row . . . . Step 5b: Delete the current row . . . . . Step 6: Close the cursor . . . . . . . . . . . . . is . . . . . . . . . . . . . . . . 55 55 55 56 58 59 59 60 61 61 62

. 28 . 28 . 29

iii

Using the multiple-row FETCH statement . . . . Multiple-row FETCH using a host structure array Multiple-row FETCH using a row storage area Unit of work and open cursors . . . . . . . .

62 63 64 67

WITH CHECK OPTION on a View . . WITH CASCADED CHECK OPTION WITH LOCAL CHECK OPTION . . DB2 UDB for AS/400 trigger support . Trigger sample . . . . . . . .

. . . . 108 . . . . 108 . . . . 109 . . . . 111 . . . . 112

Chapter 5. Advanced Coding Techniques . . . . . . . . . . . . . 69


Advanced insert techniques . . . . . . . . . Inserting rows into a table using a Select-Statement . . . . . . . . . . . . Inserting multiple rows in a table with the blocked INSERT statement . . . . . . . . Advanced update techniques . . . . . . . . Preventing duplicate rows . . . . . . . . . Performing complex search conditions . . . . . Keywords for use in search conditions . . . . Joining data from more than one table . . . . . Inner Join . . . . . . . . . . . . . . Left Outer Join . . . . . . . . . . . . Exception Join . . . . . . . . . . . . Cross Join . . . . . . . . . . . . . . Multiple join types in one statement . . . . . Notes on joins . . . . . . . . . . . . Specifying itermediate join tables using table expressions . . . . . . . . . . . . . . Using the UNION keyword to combine subselects Specifying UNION ALL . . . . . . . . . Subqueries in SELECT statements . . . . . . . Correlation . . . . . . . . . . . . . Subqueries and search conditions . . . . . . How subqueries are used. . . . . . . . . Using subqueries with UPDATE and DELETE . . Notes on using subqueries . . . . . . . . Correlated subqueries . . . . . . . . . . Using correlated subqueries in an UPDATE statement . . . . . . . . . . . . . . Using correlated subqueries in a DELETE statement . . . . . . . . . . . . . . Notes on using correlated subqueries . . . . . Changing a table definition . . . . . . . . . Adding a column . . . . . . . . . . . Changing a column. . . . . . . . . . . Allowable conversions. . . . . . . . . . Deleting a column . . . . . . . . . . . Order of operations for ALTER TABLE statement Creating and using views. . . . . . . . . . Adding indexes . . . . . . . . . . . . . Catalogs in database design . . . . . . . . . Getting catalog information about a table . . . Getting catalog information about a column . . 69 69 70 70 71 72 72 75 75 76 77 78 78 79 79 80 83 84 85 85 86 88 88 88 91 91 92 92 92 93 93 94 94 95 96 97 97 97

Chapter 7. Stored Procedures . . . . 117


Creating a procedure . . . . . . . . . . Defining an external procedure . . . . . . Defining an SQL procedure . . . . . . . . Invoking a stored procedure . . . . . . . Using CALL Statement where procedure definition exists . . . . . . . . . . Using Embedded CALL Statement where no procedure definition exists . . . . . . . Using Embedded CALL statement with an SQLDA . . . . . . . . . . . . . Using Dynamic CALL Statement where no CREATE PROCEDURE exists . . . . . . Parameter passing conventions for stored procedures . . . . . . . . . . . . . Indicator variables and stored procedures . . . Returning a completion status to the calling program . . . . . . . . . . . . . . Examples of CALL statements . . . . . . . Example 1: ILE C and PL/I procedures called from ILE C applications . . . . . . . . Considerations for stored procedures that are written in Java . . . . . . . . . . . . Coding a Java stored procedure that uses the JAVA parameter . . . . . . . . . . Coding a Java stored procedure using the DB2GENERAL parameter style . . . . . . Restrictions on Java stored procedures . . . . . . . 117 117 118 124

. 124 . 125 . 125 . 127 . 128 . 132 . 135 . 136 . 137 . 145 . 145 . 146 . 147

| |

Chapter 8. Using the Object-Relational Capabilities . . . . . . . . . . . . 149


Why use the DB2 object extensions? . . . . . DB2 approach to supporting objects . . . . . Using Large Objects (LOBs) . . . . . . . Understanding large object data types (BLOB, CLOB, DBCLOB) . . . . . . . . . . Understanding large object locators . . . . Example: Using a locator to work with a CLOB value . . . . . . . . . . . . . . Indicator variables and LOB locators . . . LOB file reference variables . . . . . . Example: Extracting a document to a file . . Example: Inserting data into a CLOB column Display layout of LOB columns . . . . . Journal entry layout of LOB columns . . . User-defined functions (UDF) . . . . . . . Why use UDFs? . . . . . . . . . . UDF concepts . . . . . . . . . . . Implementing UDFs . . . . . . . . . Registering UDFs . . . . . . . . . . Examples: Registering UDFs . . . . . . Using UDFs . . . . . . . . . . . . User-defined distinct types (UDT) . . . . . Why use UDTs? . . . . . . . . . . . 149 . 150 . 150 . 151 . 151 . . . . . . . . . . . . . . . 152 155 155 156 158 158 159 160 160 162 164 165 165 168 173 173

Chapter 6. Data Integrity . . . . . . . 99


Adding and using check constraints . . . . . . 99 Referential integrity . . . . . . . . . . . 99 Adding or dropping referential constraints . . 100 Removing referential constraints . . . . . . 102 Inserting into tables with referential constraints 102 Updating tables with referential constraints . . 103 Deleting from tables with referential constraints 105 Check pending . . . . . . . . . . . . 107

iv

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Defining a UDT . . . . . . . . . . Resolving unqualified UDTs . . . . . . Examples: Using CREATE DISTINCT TYPE . Defining tables with UDTs . . . . . . . Manipulating UDTs . . . . . . . . . Examples of manipulating UDTs . . . . . Synergy between UDTs, UDFs, and LOBs . . . Combining UDTs, UDFs, and LOBs . . . . Examples of complex applications . . . . Using DataLinks . . . . . . . . . . . NO LINK CONTROL . . . . . . . . FILE LINK CONTROL (with File System Permissions). . . . . . . . . . . . FILE LINK CONTROL (with Database Permissions). . . . . . . . . . . . Commands used for working with DataLinks

. . . . . . . . . . .

174 174 175 175 176 176 181 181 181 184 185

Using the list selection function . . . . Session services description . . . . . Exiting interactive SQL . . . . . . . Using an existing SQL session . . . . . Recovering an SQL session . . . . . . Accessing remote databases with interactive SQL . . . . . . . . . . . . .

. . . . . .

. . . . .

224 226 228 228 228

. 229

Chapter 13. Using the SQL Statement Processor . . . . . . . . . . . . . 231


Execution of statements after errors occur . . Commitment control in the SQL statement processor . . . . . . . . . . . . . Schemas in the SQL Statement Processor . . Source member listing for the SQL statement processor . . . . . . . . . . . . . . . . . . 232 . 232 . 232 . 233

. 185 . 185 186

Chapter 9. Writing User-Defined Functions (UDFs). . . . . . . . . . 189


UDF runtime environment . . . . Length of time that the UDF runs Threads considerations . . . . Parallel processing. . . . . . Writing function code . . . . . Writing UDFs as SQL functions . Writing UDFs as external functions Examples of UDF code . . . . . Example: Square of a number UDF Example: Counter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189 189 190 190 190 190 191 196 196 198

Chapter 14. DB2 UDB for AS/400 Data Protection . . . . . . . . . . . . . 235


Security for SQL objects . . . . . Authorization ID . . . . . . Views . . . . . . . . . . Auditing . . . . . . . . . Data integrity . . . . . . . . Concurrency. . . . . . . . Journaling . . . . . . . . Commitment control . . . . . Atomic operations . . . . . . Constraints . . . . . . . . Save/Restore . . . . . . . Damage tolerance . . . . . . Index recovery . . . . . . . Catalog integrity . . . . . . User auxiliary storage pool (ASP) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235 236 236 236 237 237 239 239 243 245 245 246 246 247 247

Chapter 10. Dynamic SQL Applications . . . . . . . . . . . . 199


Designing and running a dynamic SQL application Processing non-SELECT statements . . . . . . CCSID of dynamic SQL statements . . . . . Using the PREPARE and EXECUTE statements Processing SELECT statements and using an SQLDA . . . . . . . . . . . . . . . Fixed-list SELECT statements . . . . . . . Varying-list Select-statements . . . . . . . SQL Descriptor Area (SQLDA) . . . . . . SQLDA format . . . . . . . . . . . . Example: Select-statement for allocating storage for SQLDA . . . . . . . . . . . . . Using a cursor . . . . . . . . . . . . Parameter markers . . . . . . . . . . 201 202 202 202 203 203 204 205 206 210 214 215

Chapter 15. Testing SQL Statements in Application Programs. . . . . . . 249


Establishing a test environment . . . Designing a test data structure . . Testing your SQL application programs. Program debug phase . . . . . Performance verification phase . . . . . . . . . . . . . . . . . . . . . . 249 249 250 250 251

Chapter 16. Solving Common Database Problems . . . . . . . . . 253


Paging through retrieved data . . . . . Retrieving in reverse order . . . . . . Establishing position at the end of a table . Adding data to the end of a table . . . Updating data as it is retrieved from a table Restrictions . . . . . . . . . . Updating data previously retrieved . . . Changing the table definition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253 253 253 254 254 255 256 256

| | | | | |

Chapter 11. Use of dynamic SQL through client interfaces . . . . . . 217


Accessing data Accessing data Accessing data (ODBC) . . with with with . . Java . . . . . . . . . 217 Domino . . . . . . . . 217 Open Database Connectivity . . . . . . . . . . . 217

Chapter 12. Using Interactive SQL . . 219


Basic functions of interactive SQL Starting interactive SQL . . . Using statement entry function Prompting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219 220 221 221

Chapter 17. Distributed Relational Database Function . . . . . . . . . 257


DB2 UDB for AS/400 distributed relational database support . . . . . . . . . . . . 257

Contents

DB2 UDB for AS/400 distributed relational database example program . . . . . . . . . SQL package support. . . . . . . . . . . Valid SQL statements in an SQL package . . . Considerations for creating an SQL package . . CCSID considerations for SQL. . . . . . . . Connection management and activation groups Connections and conversations . . . . . . Source code for PGM1: . . . . . . . . . Source code for PGM2: . . . . . . . . . Source code for PGM3: . . . . . . . . . Multiple connections to the same relational database . . . . . . . . . . . . . . Implicit connection management for the default activation group . . . . . . . . . . . Implicit connection management for nondefault activation groups . . . . . . . . . . . Distributed support . . . . . . . . . . . Determining connection type . . . . . . . Connect and commitment control restrictions Determining connection status. . . . . . . Distributed unit of work connection considerations . . . . . . . . . . . . Ending connections . . . . . . . . . . Distributed unit of work. . . . . . . . . . Managing distributed unit of work connections Cursors and prepared statements . . . . . . Application requester driver programs . . . . . Problem handling . . . . . . . . . . . .

258 259 260 260 263 263 263 264 265 265 267 267 268 268 269 272 273 274 275 276 276 278 279 279

Department Table (CORPDATA.DEPARTMENT) DEPARTMENT . . . . . . . . . . . Employee Table (CORPDATA.EMPLOYEE) . . Employee to Project Activity Table (CORPDATA.EMP_ACT) . . . . . . . . EMP_ACT . . . . . . . . . . . . Project Table (CORPDATA.PROJECT) . . . . PROJECT. . . . . . . . . . . . . Class Schedule Table (CL_SCHED) . . . . . In Tray Table (IN_TRAY) . . . . . . . .

281 . 282 . 282 . . . . . . 283 284 286 286 287 287

Appendix B. SQLCODEs and SQLSTATEs . . . . . . . . . . . . 289


SQLCODE and SQLSTATE Descriptions Positive SQLCODEs . . . . . . Negative SQLCODEs . . . . . . . . . . . . . . . . 291 . 291 . 293

Appendix C. DB2 UDB for AS/400 CL Command Descriptions . . . . . . . 307


CRTSQLPKG (Create Structured Query Language Package) Command . . . . . . . . . . DLTSQLPKG (Delete Structured Query Language Package) Command . . . . . . . . . . RUNSQLSTM (Run Structured Query Language Statement) Command . . . . . . . . . STRSQL (Start Structured Query Language) Command . . . . . . . . . . . . . . 307 . 311 . 312 . 323

Bibliography . . . . . . . . . . . . 331 Appendix A. DB2 UDB for AS/400 Sample Tables . . . . . . . . . . . 281 Index . . . . . . . . . . . . . . . 333

vi

DB2 UDB for AS/400 SQL Programming Concepts V4R5

About DB2 UDB for AS/400 SQL Programming Concepts


This book explains basic SQL programming concepts that show programmers and database administrators: v How to use the DB2 SQL for AS/400 licensed program v How to access data in a database v How to prepare, run, and test an application program that contains SQL statements. For more information on DB2 UDB for AS/400 SQL guidelines and examples for implementation in an application programming environment, see the following books in the Database and Files Systems category of the AS/400e Information Center: v SQL Reference v DB2 UDB for AS/400 SQL Programming for Host Languages v DB2 UDB for AS/400 Database Performance and Query Optimization v SQL Call Level Interface (ODBC) In addition, information on advanced database functions can be found in: v DATABASE 2/400 Advanced Database Functions, GG24-4249.

Who should read this book


This guide should be used by application programmers and database administrators who are familiar with and can program with COBOL for AS/400, ILE COBOL for AS/400, AS/400 PL/I, ILE C for AS/400, ILE C++, VisualAge C++ for AS/400, REXX, RPG III (part of RPG for AS/400), or ILE RPG for AS/400 language and who can understand basic database applications.

Assumptions relating to examples of SQL statements


The examples of SQL statements shown in this guide are based on the sample tables in Appendix A, DB2 UDB for AS/400 Sample Tables, and assume the following: v They are shown in the interactive SQL environment or they are written in ILE C or in COBOL. EXEC SQL and END-EXEC are used to delimit an SQL statement in a COBOL program. A description of how to use SQL statements in a COBOL program is provided in Coding SQL Statements in COBOL Applications. A description of how to use SQL statements in an ILE C program is provided in Coding SQL Statements in C Applications. v Each SQL example is shown on several lines, with each clause of the statement on a separate line. v SQL keywords are highlighted. v Table names provided in Appendix A, DB2 UDB for AS/400 Sample Tables, use the collection CORPDATA. Table names that are not found in Appendix A, DB2 UDB for AS/400 Sample Tables, should use collections you create. v Calculated columns are enclosed in parentheses, (), and brackets, []. v The SQL naming convention is used.
Copyright IBM Corp. 2000

vii

v The APOST and APOSTSQL precompiler options are assumed although they are not the default options in COBOL. Character string literals within SQL and host language statements are delimited by apostrophes (). v A sort sequence of *HEX is used, unless otherwise noted. v The complete syntax of the SQL statement is usually not shown in any one example. For the complete description and syntax of any of the statements described in this guide, see the SQL Reference Whenever the examples vary from these assumptions, it is stated. Because this guide is for the application programmer, most of the examples are shown as if they were written in an application program. However, many examples can be slightly changed and run interactively by using interactive SQL. The syntax of an SQL statement, when using interactive SQL, differs slightly from the format of the same statement when it is embedded in a program.

How to interpret syntax diagrams in this guide


Throughout this book, syntax is described using the structure defined as follows: v Read the syntax diagrams from left to right, from top to bottom, following the path of the line. The symbol indicates the beginning of a statement. The symbol indicates that the statement syntax is continued on the next line. The symbol indicates that a statement is continued from the previous line. The symbol indicates the end of a statement. Diagrams of syntactical units other than complete statements start with the symbol and end with the symbol. v Required items appear on the horizontal line (the main path).
required_item

v Optional items appear below the main path.


required_item optional_item

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

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

viii

DB2 UDB for AS/400 SQL Programming Concepts V4R5

required_item

required_choice1 required_choice2

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

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

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

required_item

repeatable_item

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

A repeat arrow above a stack indicates that you can repeat the items in the stack. v Keywords appear in uppercase (for example, FROM). They must be spelled exactly as shown. Variables appear in all lowercase letters (for example, column-name). They represent user-supplied names or values. v If punctuation marks, parentheses, arithmetic operators, or other such symbols are shown, you must enter them as part of the syntax.

Whats new in the V4R5 version of the SQL programming concepts information
The two major changes to this information for this release were: v Providing information on the big integer (BIGINT) data type v Providing information on using Java stored procedures.

About DB2 UDB for AS/400 SQL Programming Concepts

ix

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Chapter 1. Introduction to DB2 UDB for AS/400 Structured Query Language


These topics describe the AS/400* system implementation of the Structured Query Language (SQL) using DB2 UDB for AS/400 and the DB2 UDB Query Manager and SQL Development Kit Version 4 licensed program. SQL manages information based on the relational model of data. SQL statements can be embedded in high-level languages, dynamically prepared and run, or run interactively. SQL consists of statements and clauses that describe what you want to do with the data in a database and under what conditions you want to do it. This topic describes the following: v SQL concepts v SQL objects on page 5 v Application program objects on page 9 SQL can access data in a remote relational database, using the IBM Distributed Relational Database Architecture* (DRDA*). This function is described in Chapter 17. Distributed Relational Database Function, of this guide. Further information about DRDA is contained in the Distributed Database Programming book.

SQL concepts
DB2 UDB for AS/400 SQL consists of the following main parts: v SQL run-time support SQL run-time parses SQL statements and runs any SQL statements. This support is that part of the Operating System/400* (OS/400) licensed program which allows applications that contain SQL statements to be run on systems where the DB2 UDB Query Manager and SQL Development Kit licensed program is not installed. v SQL precompilers SQL precompilers support precompiling embedded SQL statements in host languages. The following languages are supported: ILE C for AS/400* ILE C++ for AS/400 VisualAge C++ for AS/400 ILE COBOL for AS/400* COBOL for AS/400* AS/400 PL/I* RPG III (part of RPG for AS/400*)

ILE RPG for AS/400* The SQL host language precompilers prepare an application program containing SQL statements. The host language compilers then compile the precompiled host source programs. For more information on precompiling, see the topic Preparing and Running a Program with SQL Statements in the SQL Programming with Host
Copyright IBM Corp. 2000

Languages information. The precompiler support is part of the DB2 UDB Query Manager and SQL Development Kit licensed program. SQL interactive interface SQL interactive interface allows you to create and run SQL statements. For more information on interactive SQL, see Chapter 12. Using Interactive SQL. Interactive SQL is part of the DB2 UDB Query Manager and SQL Development Kit licensed program. Run SQL Statements CL command RUNSQLSTM allows you to run a series of SQL statements, which are stored in a source file. The RUNSQLSTM command is part of the DB2 UDB Query Manager and SQL Development Kit licensed program. See Chapter 13. Using the SQL Statement Processor for more information on the Run SQL Statements command. DB2 Query Manager for AS/400 DB2 Query Manager for AS/400 provides a prompt-driven interactive interface that allows you to create data, add data, maintain data, and run reports on the databases. Query Manager is part of the DB2 UDB Query Manager and SQL Development Kit licensed program. For more information, refer to the Query Manager Use book. SQL REXX Interface The SQL REXX interface allows you to run SQL statements in a REXX procedure. This interface is part of the DB2 UDB Query Manager and SQL Development Kit licensed program. For more information on using SQL statements in REXX procedures, see the topic Coding SQL Statements in REXX Applications in the SQL Programming with Host Languages information. SQL Call Level Interface DB2 UDB for AS/400 supports the SQL Call Level Interface. This allows users of any of the ILE languages to access SQL functions directly through procedure calls to a service program provided by the system. Using the SQL Call Level Interface, one can perform all the SQL functions without the need for a precompile. This is a standard set of procedure calls to prepare SQL statements, execute SQL statements, fetch rows of data, and even do advanced functions such as accessing the catalogs and binding program variables to output columns. For a complete description of all the available functions, and their syntax, see the SQL Call Level Interface (ODBC) book.

v QSQPRCED API This Application Program Interface (API) provides an extended dynamic SQL capability. SQL statements can be prepared into an SQL package and then executed using this API. Statements prepared into a package by this API persist until the package or statement is explicitly dropped. QSQPRCED is part of the OS/400 licensed program. For more information on the QSQPRCED API, see the OS/400 API book. v QSQCHKS API This API syntax checks SQL statements. QSQCHKS is part of the OS/400 licensed program. For more information on the QSQCHKS API, see the OS/400 API book. v DB2 Multisystem This feature of the operating system allows your data to be distributed across multiple AS/400 systems. For more information on DB2 Multisystem, see the DB2 Multisystem book. v DB2 UDB Symmetric Multiprocessing

DB2 UDB for AS/400 SQL Programming Concepts V4R5

This feature of the operating system provides the query optimizer with additional methods for retrieving data that include parallel processing. Symmetric multiprocessing (SMP) is a form of parallelism achieved on a single system where multiple processors (CPU and I/O processors) that share memory and disk resource work simultaneously towards achieving a single end result. This parallel processing means that the database manager can have more than one (or all) of the system processors working on a single query simultaneously. See the topic Controlling Parallel Processing in the Database Performance and Query Optimization information for details on how to control parallel processing.

SQL relational database and system terminology


In the relational model of data, all data is perceived as existing in tables. DB2 UDB for AS/400 objects are created and maintained as AS/400 system objects. The following table shows the relationship between AS/400 system terms and SQL relational database terms. For more information on database, see the Database Programming book.
Table 1. Relationship of System Terms to SQL Terms System Terms SQL Terms Library. Groups related objects and allows Collection. Consists of a library, a journal, a you to find the objects by name. journal receiver, an SQL catalog, and optionally a data dictionary. A collection groups related objects and allows you to find the objects by name. Physical file. A set of records. Table. A set of columns and rows. Record. A set of fields. Row. The horizontal part of a table containing a serial set of columns. Field. One or more characters of related Column. The vertical part of a table of one information of one data type. data type. Logical file. A subset of fields and records View. A subset of columns and rows of one of one or more physical files. or more tables. SQL Package. An object type that is used to Package. An object type that is used to run run SQL statements. SQL statements. User Profile Authorization name or Authorization ID.

SQL and system naming conventions


There are two naming conventions that can be used in DB2 UDB for AS/400 programming: system (*SYS) and SQL (*SQL). The naming convention used affects the method for qualifying file and table names and the terms used on the interactive SQL displays. The naming convention used is selected by a parameter on the SQL commands or, for REXX, selected through the SET OPTION statement. System naming (*SYS): In the system naming convention, files are qualified by library name in the form:
library/file

If the table name is not explicitly qualified and a default collection name is specified for the default relational database collection (DFTRDBCOL) parameter of

Chapter 1. Introduction to DB2 UDB for AS/400 Structured Query Language

the CRTSQLxxx 1 or the CRTSQLPKG commands, the default collection name is used. If the table name is not explicitly qualified and the default collection name is not specified, the qualification rules are: v The following CREATE statements resolve to unqualified objects as follows: CREATE TABLE The table is created in the current library (*CURLIB). CREATE VIEW The view is created in the first library referenced in the subselect. CREATE INDEX The index is created into the collection or library that contains the table on which the index is being built. CREATE ALIAS The alias is created into the collection or library that contains the table for which you defined the alias. If the table is not qualified or is not found, the alias is created in the current library (*CURLIB). v All other SQL statements cause SQL to search the library list (*LIBL) for the unqualified table. The default relational database collection (DFTRDBCOL) parameter applies only to static SQL statements. SQL naming (*SQL): In the SQL naming convention, tables are qualified by the collection name in the form:
collection.table

If the table name is not explicitly qualified and the default collection name is specified in the default relational database collection (DFTRDBCOL) parameter of the CRTSQLxxx command, the default collection name is used. If the table name is not explicitly qualified and the default collection name is not specified, the rules are: v For static SQL, the default qualifier is the user profile of the program owner. v For dynamic SQL or interactive SQL, the default qualifier is the user profile of the job running the statement.

Types of SQL statements


There are four basic types of SQL statements: data definition language (DDL) statements, data manipulation language (DML) statements, dynamic SQL statements, and miscellaneous statements. SQL statements can operate on objects that are created by SQL as well as AS/400 externally described physical files and AS/400 single-format logical files, whether or not they reside in an SQL collection. They do not refer to the IDDU dictionary definition for program-described files. Program-described files appear as a table with only a single column.

1. The xxx in this command refers to the host language indicators: CI for the ILE C for AS/400 language, CPPI for the ILE C++ for AS/400 language, CBL for the COBOL for AS/400 language, CBLI for the ILE COBOL for AS/400 language, PLI for the AS/400 PL/I language, RPG for the RPG for AS/400 language, and RPGI for the ILE RPG for AS/400 language. The CVTSQLCPP command is considered part of this group of commands even though it does not start with CRT.

DB2 UDB for AS/400 SQL Programming Concepts V4R5

SQL DDL Statements ALTER TABLE COMMENT ON CREATE ALIAS CREATE COLLECTION CREATE DISTINCT TYPE CREATE FUNCTION CREATE INDEX CREATE PROCEDURE CREATE SCHEMA CREATE TABLE CREATE VIEW DROP ALIAS DROP COLLECTION DROP DISTINCT TYPE DROP FUNCTION DROP INDEX DROP PACKAGE DROP PROCEDURE DROP SCHEMA DROP TABLE DROP VIEW GRANT DISTINCT TYPE GRANT FUNCTION GRANT PACKAGE GRANT PROCEDURE GRANT TABLE LABEL ON RENAME REVOKE DISTINCT TYPE REVOKE FUNCTION REVOKE PACKAGE REVOKE PROCEDURE REVOKE TABLE Dynamic SQL Statements DESCRIBE EXECUTE EXECUTE IMMEDIATE PREPARE

SQL DML Statements CLOSE COMMIT DECLARE CURSOR DELETE FETCH INSERT LOCK TABLE OPEN ROLLBACK SELECT INTO SET variable UPDATE VALUES INTO

Miscellaneous Statements BEGIN DECLARE SECTION CALL CONNECT DECLARE PROCEDURE DECLARE STATEMENT DECLARE VARIABLE DESCRIBE TABLE DISCONNECT END DECLARE SECTION FREE LOCATOR INCLUDE RELEASE SET CONNECTION SET OPTION SET PATH SET RESULT SETS SET TRANSACTION WHENEVER

SQL objects
SQL objects used on the AS/400 system are collections, tables, aliases, views, SQL packages, indexes, and catalogs. SQL creates and maintains these objects as AS/400 database objects. A brief description of these objects follows.
Chapter 1. Introduction to DB2 UDB for AS/400 Structured Query Language

Collections
A collection provides a logical grouping of SQL objects. A collection consists of a library, a journal, a journal receiver, a catalog, and optionally, a data dictionary. Tables, views, and system objects (such as programs) can be created, moved, or restored into any AS/400 library. All AS/400 files can be created or moved into an SQL collection if the SQL collection does not contain a data dictionary. If the SQL collection contains a data dictionary then: v AS/400 source physical files or nonsource physical files with one member can be created, moved, or restored into an SQL collection. v AS/400 logical files cannot be placed in an SQL collection because they cannot be described in the data dictionary. You can create and own many collections.

Data Dictionary
A collection contains a data dictionary if it was created prior to Version 3 Release 1 or if the WITH DATA DICTIONARY clause was specified on the CREATE COLLECTION or the CREATE SCHEMA statements. A data dictionary is a set of tables containing object definitions. If SQL created the dictionary, then it is automatically maintained by the system. You can work with data dictionaries by using the interactive data definition utility (IDDU), which is part of the OS/400 program. For more information on IDDU, see the IDDU Use book.

Journals and Journal Receivers


A journal and journal receiver are used to record changes to tables and views in the database. The journal and journal receiver are then used in processing SQL COMMIT and ROLLBACK statements. The journal and journal receiver can also be used as an audit trail or for forward or backward recovery. For more information on journaling, see the Backup and Recovery book.

Catalogs
An SQL catalog consists of a set of tables and views which describe tables, views, indexes, packages, procedures, files, and constraints. This information is contained in a set of cross-reference tables in libraries QSYS and QSYS2. Library QSYS2 also contains a set of catalog views built over the QSYS catalog tables which describe information about all the tables, views, indexes, packages, procedures, files, and constraints on the system. In each SQL collection there is a set of views built over the catalog tables which contains information about the tables, views, indexes, packages, files, and constraints in the collection. A catalog is automatically created when you create a collection. You cannot drop or explicitly change the catalog. For more information about SQL catalogs, see the SQL Reference book.

Tables, Rows, and Columns


A table is a two-dimensional arrangement of data consisting of rows and columns. The row is the horizontal part containing one or more columns. The column is the vertical part containing one or more rows of data of one data type. All data for a

DB2 UDB for AS/400 SQL Programming Concepts V4R5

column must be of the same type. A table in SQL is a keyed or nonkeyed physical file. See the section on data types in the SQL Reference book for a description of data types. Data in a table can be distributed across AS/400 systems. For more information about distributed tables, see the DB2 Multisystem book. The following is a sample SQL table:
Columns

PROJNO Rows MA2100 MA2110 MA2112 MA2113 ...

PROJNAME MFG AUTOMATION MFG PROGRAMMING ROBOT DESIGN PROD CONTROL PROG ...

DEPTNO D11 E21 E01 D11 ...

DEPTMGR 000060 000100 000050 000060 ...

PRSTAFF 12 3 3 3 ...
RV2W573-0

Aliases
An alias is an alternate name for a table or view. You can use an alias to refer to a table or view in those cases where an existing table or view can be referred to. For more information on aliases, see the SQL Reference book.

Views
A view appears like a table to an application program; however, a view contains no data. It is created over one or more tables. A view can contain all the columns of given tables or some subset of them, and can contain all the rows of given tables or some subset of them. The columns can be arranged differently in a view than they are in the tables from which they are taken. A view in SQL is a special form of a nonkeyed logical file. The following figure shows a view created from the preceding example of an SQL table. Notice that the view is created only over the PROJNO and PROJNAME columns of the table and for rows MA2110 and MA2100.
Columns

PROJNO Rows MA2100 MA2110

PROJNAME MFG AUTOMATION MFG PROGRAMMING


RV2W574-0

Chapter 1. Introduction to DB2 UDB for AS/400 Structured Query Language

Indexes
An SQL index is a subset of the data in the columns of a table that are logically arranged in either ascending or descending order. Each index contains a separate arrangement. These arrangements are used for ordering (ORDER BY clause), grouping (GROUP BY clause), and joining. An SQL index is a keyed logical file. The index is used by the system for faster data retrieval. Creating an index is optional. You can create any number of indexes. You can create or drop an index at any time. The index is automatically maintained by the system. However, because the indexes are maintained by the system, a large number of indexes can adversely affect the performance of applications that change the table.

Constraints
Constraints are rules enforced by the database manager. DB2 UDB for AS/400 supports the following constraints: v Unique constraints A unique constraint is the rule that the values of the key are valid only if they are unique. Unique constraints can be created using the CREATE TABLE and ALTER TABLE statements. 2 Unique constraints are enforced during the execution of INSERT and UPDATE statements. A PRIMARY KEY constraint is a form of UNIQUE constraint. The difference is that a PRIMARY KEY cannot contain any nullable columns. v Referential constraints A referential constraint is the rule that the values of the foreign key are valid only if: They appear as values of a parent key, or Some component of the foreign key is null. Referential constraints are enforced during the execution of INSERT, UPDATE, and DELETE statements. v Check constraints A check constraint is a rule that limits the values allowed in a column or group of columns. Check constraints can be added using the CREATE TABLE and ALTER TABLE statements. Check constraints are enforced during the execution of INSERT and UPDATE statements. To satisfy the constraint, each row of data inserted or updated in the table must make the specified condition either TRUE or unknown (due to a null value). For more information on constraints, see Chapter 6. Data Integrity.

Triggers
A trigger is a set of actions that are executed automatically whenever a specified event occurs to a specified base table. An event can be an insert, update, or delete operation. The trigger can be run either before or after the event. For more information on triggers, see Chapter 6. Data Integrity in this book or see the Database Programming book.

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

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Stored Procedures
A stored procedure is a program that can be called using the SQL CALL statement. DB2 UDB for AS/400 supports external stored procedures and SQL procedures. External stored procedures can be any AS/400 program or REXX procedure. They cannot be System/36 programs or procedures, or service programs. An SQL procedure is defined entirely in SQL and can contain SQL statements including SQL control statements. For more information on stored procedures, see Chapter 7. Stored Procedures.

User-defined functions
A user-defined function is a program that can be invoked like any built-in function. DB2 UDB for AS/400 supports external functions, SQL functions, and sourced functions. External functions can be any AS/400 ILE program or service program. An SQL function is defined entirely in SQL and can contain SQL statements, including SQL control statements. A sourced function is built over any built-in or any existing user-defined function. For more information on user-defined functions, see Chapter 9. Writing User-Defined Functions (UDFs) on page 189.

User-defined type
A user-defined type is a distinct data type that users can define independently of those supplied by the database management system. Distinct data types map on a one-to-one basis to existing database types. For more information on user-defined types, see User-defined distinct types (UDT) on page 173.

SQL Packages
An SQL package is an object that contains the control structure produced when the SQL statements in an application program are bound to a remote relational database management system (DBMS). The DBMS uses the control structure to process SQL statements encountered while running the application program. SQL packages are created when a relational database name (RDB parameter) is specified on a Create SQL (CRTSQLxxx) command and a program object is created. Packages can also be created using the CRTSQLPKG command. For more information about packages and distributed relational database function, see Chapter 17. Distributed Relational Database Function SQL packages can also be created using the QSQPRCED API. For more information on QSQPRCED, see the OS/400 API book.

Application program objects


The process of creating a DB2 UDB for AS/400 application program may result in the creation of several objects. This section briefly describes the process of creating a DB2 UDB for AS/400 application. DB2 UDB for AS/400 supports both non-ILE and ILE precompilers. Application programs may be either distributed or nondistributed. Additional information on creating DB2 UDB for AS/400 application programs is in the topic Preparing and Running a Program with SQL Statements in the SQL Programming with Host Languages information.
Chapter 1. Introduction to DB2 UDB for AS/400 Structured Query Language

With DB2 UDB for AS/400 you may need to manage the following objects: v The original source v Optionally, the module object for ILE programs v The program or service program v The SQL package for distributed programs With a nondistributed non-ILE DB2 UDB for AS/400 program, you must manage only the original source and the resulting program. The following shows the objects involved and steps that happen during the precompile and compile processes for a nondistributed non-ILE DB2 UDB for AS/400 program:
User Source File Member

Precompile

Temporary Source File Member Processed SQL Statements

Compile

Program

Access Plan

RV2W565-1

With a nondistributed ILE DB2 UDB for AS/400 program, you may need to manage the original source, the modules, and the resulting program or service program. The following shows the objects involved and steps that happen during the precompile and compile processes for a nondistributed ILE DB2 UDB for AS/400 program when OBJTYPE(*PGM) is specified on the precompile command:

User Source Precompile File Member

Temporary Source File Member Processed SQL Statements

Compile

Module

Bind

Program

Processed SQL Statements

Access Plan

RV2W569-0

With a distributed non-ILE DB2 UDB for AS/400 program, you must manage the original source, the resulting program, and the resulting package. The following shows the objects and steps that occur during the precompile and compile processes for a distributed non-ILE DB2 UDB for AS/400 program:
Create Compile Program SQL Package Access Plan SQL Package

User Source File Member

Precompile

Temporary Source File Member Processed SQL Statements

Access Plan
RV2W566-2

With a distributed ILE DB2 UDB for AS/400 program, you must manage the original source, module objects, the resulting program or service program, and the resulting packages. An SQL package can be created for each distributed module in a distributed ILE program or service program. The following shows the objects and

10

DB2 UDB for AS/400 SQL Programming Concepts V4R5

steps that occur during the precompile and compile processes for a distributed ILE DB2 UDB for AS/400 program:
Create SQL Package

User Source File Member

Precompile

Temporary Source File Member Processed SQL Statements

Compile

Module

Bind

Program

SQL Package

Processed SQL Statements

Access Plan

Access Plan

RV2W570-1

Note: The access plans associated with the DB2 UDB for AS/400 distributed program object are not created until the program is run locally.

User source file member


A source file member contains the programmers application language and SQL statements. You can create and maintain the source file member by using the source entry utility (SEU), a part of the AS/400 Application Development Tools licensed program.

Output source file member


The SQL precompile creates an output source file member. By default, the precompile process (CRTSQLxxx commands) creates a temporary source file called QSQLTEMP (QSQLTEMP1 for CRTSQLRPGI) in library QTEMP. If the precompile process uses the QTEMP library, the system automatically deletes the file when the job completes. You can specify the output source file as a permanent file name on the precompile commands. A member with the same name as the program name is added to the output source file. This member contains the following items: v Calls to the SQL run-time support, which have replaced embedded SQL statements v Parsed and syntax-checked SQL statements By default, the precompiler calls the host language compiler. For more information on precompilers, see the topic Preparing and Running a Program with SQL Statements in the SQL Programming with Host Languages information.

Program
A program is the object which you can run that is created as a result of the compile process for non-ILE compiles or as a result of the bind process for ILE compiles. An access plan is a set of internal structures and information that tells SQL how to run an embedded SQL statement most effectively. It is created only when the program has successfully created. Access plans are not created during program creation for SQL statements if the statements: v Refer to a table or view that cannot be found v Refer to a table or view to which you are not authorized The access plans for such statements are created when the program is run. If, at that time, the table or view still cannot be found or you are still not authorized, a
Chapter 1. Introduction to DB2 UDB for AS/400 Structured Query Language

11

negative SQLCODE is returned. Access plans are stored and maintained in the program object for nondistributed SQL programs and in the SQL package for distributed SQL programs.

SQL Package
An SQL package contains the access plans for a distributed SQL program. An SQL package is an object that is created when: v A distributed SQL program is successfully created using the RDB parameter on CRTSQLxxx commands. v When the Create SQL Package (CRTSQLPKG) command is run. When a distributed SQL program is created, the name of the SQL package and an internal consistency token are saved in the program. These are used at run time to find the SQL package and to verify that the SQL package is correct for this program. Because the name of the SQL package is critical for running distributed SQL programs, an SQL package cannot be: v Moved v Renamed v Duplicated v Restored to a different library

Module
A module is an Integrated Language Environment (ILE) object that is created by compiling source code using the CRTxxxMOD command (or any of the CRTBNDxxx commands where xxx is C, CBL, CPP, or RPG). You can run a module only if you use the Create Program (CRTPGM) command to bind it into a program. You usually bind several modules together, but you can bind a module by itself. Modules contain information about the SQL statements; however, the SQL access plans are not created until the modules are bound into either a program or service program.

Service program
A service program is an Integrated Language Environment (ILE) object that provides a means of packaging externally supported callable routines (functions or procedures) into a separate object. Bound programs and other service programs can access these routines by resolving their imports to the exports provided by a service program. The connections to these services are made when the calling programs are created. This improves call performance to these routines without including the code in the calling program.

12

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Chapter 2. Getting Started with SQL


This chapter describes how to create and work with SQL collections, tables, and views using SQL statements. The syntax for each of the SQL statements used in this chapter is described in detail in the SQL Reference book. A description of how to use SQL statements and clauses in more complex situations is provided in Chapter 3. Basic Concepts and Techniques and Chapter 5. Advanced Coding Techniques. In this chapter, the examples use the interactive SQL interface to show the execution of SQL statements. Each SQL interface provides methods for using SQL statements to define tables, views, and other objects, methods for updating the objects, and methods for reading data from the objects. Some tasks described here can also be done using Operations Navigator. In those cases, the information about the task notes that it can be done using Operations Navigator. See the following topics for details: v Starting interactive SQL v Creating an SQL collection v v v v v Creating and using a table on page 14 Using the LABEL ON statement on page 16 Inserting information into a table on page 18 Getting information from a single table on page 20 Getting information from more than one table on page 23

v Changing information in a table on page 25 v Deleting information from a table on page 28 v Creating and using a view on page 28

Starting interactive SQL


To start using interactive SQL for the following examples, type:
STRSQL NAMING(*SQL)

and press Enter. When the Enter SQL Statements display appears, you are ready to start typing SQL Statements. For more information on interactive SQL and the STRSQL command, see Chapter 12. Using Interactive SQL. If you are reusing an existing interactive SQL session, make sure that you set the naming mode to SQL naming. You can specify this on the F13 (Services) panel, option 1 (Change session attributes).

Creating an SQL collection


An SQL collection is the basic object in which tables, views, indexes, and packages are placed. One way to create a collection (called a library) is by using Operations Navigator. Or you can use the SQL CREATE COLLECTION statement.

Copyright IBM Corp. 2000

13

For an example of creating a collection using interactive SQL, see Example: Creating the SQL Collection (SAMPLECOLL).

Example: Creating the SQL Collection (SAMPLECOLL)


You can create a sample collection, named SAMPLECOLL, by typing the following SQL statement on the Enter SQL Statements display and pressing Enter:
Enter SQL Statements Type SQL statement, press Enter. Current connection is to relational database SYSTEM1 ===> CREATE COLLECTION SAMPLECOLL_________________________________________ _____________________________________________________________________ _____________________________________________________________________ _____________________________________________________________________ Bottom F3=Exit F4=Prompt F6=Insert line F9=Retrieve F10=Copy line F12=Cancel F13=Services F24=More keys

Note: Running this statement causes several objects to be created and takes several seconds. After you have successfully created a collection, you can create tables, views, and indexes in it. Tables, views, and indexes can also be created in libraries instead of collections.

Creating and using a table


You can create a table by using the SQL CREATE TABLE statement or by using Operations Navigator. The CREATE TABLE statement allows you to create a table, define the physical attributes of the columns in the table, and define constraints to restrict the values that are allowed in the table. For an example of creating a table using interactive SQL, see Example: Creating a table (INVENTORY_LIST). When creating a table, you need to understand the concepts of null value and default value. A null value indicates the absence of a column value for a row. It is not the same as a value of zero or all blanks. It means unknown. It is not equal to any value, not even to other null values. If a column does not allow the null value, a value must be assigned to the column, either a default value or a user supplied value. A default value is assigned to a column when a row is added to a table and no value is specified for that column. If a specific default value is not defined for a column, the system default value will be used. For more information on the default values used by INSERT, see Inserting rows using the INSERT statement on page 31

Example: Creating a table (INVENTORY_LIST)


We are going to create a table to maintain information about the current inventory of a business. It will have information about the items kept in the inventory, their cost, quantity currently on hand, the last order date, and the number last ordered. The item number will be a required value. It cannot be null. The item name,

14

DB2 UDB for AS/400 SQL Programming Concepts V4R5

quantity on hand, and order quantity will have user supplied default values. The last order date and quantity ordered will allow the null value. On the Enter SQL Statements display, type CREATE TABLE and press F4 (Prompt). The following display is shown (with the input areas not yet filled in):
Specify CREATE TABLE Statement Type information, press Enter. Table . . . . . . . . . Collection . . . . . . Nulls: INVENTORY_LIST______ SAMPLECOLL__ Name Name, F4 for list

1=NULL, 2=NOT NULL, 3=NOT NULL WITH DEFAULT FOR Column ____________ ____________ ____________ ____________ ____________ ____________ ____________ Type CHAR___________ VARCHAR________ DECIMAL________ SMALLINT_______ DATE___________ SMALLINT_______ _______________ N N Length 6____ 20___ 8____ _____ _____ _____ _____ Scale Nulls __ 2 __ 3 2_ 3 __ 1 __ 1 __ 1 __ 3 Bottom Y=Yes, N=No Y=Yes, N=No F10=Copy line F24=More keys

Column ITEM_NUMBER_______ ITEM_NAME_________ UNIT_COST_________ QUANTITY_ON_HAND__ LAST_ORDER_DATE___ ORDER_QUANTITY____ __________________

Table CONSTRAINT . . . . . . . . . . . . . Distributed Table . . . . . . . . . . . . F3=Exit F4=Prompt F11=Display more attributes F5=Refresh F12=Cancel

F6=Insert line F14=Delete line

Type the table name and collection name of the table you are creating, INVENTORY_LIST in SAMPLECOLL, for the Table and Collection prompts. Each column you want to define for the table is represented by an entry in the list on the lower part of the display. For each column, type the name of the column, the data type of the column, its length and scale, and the null attribute. Press F11 to see more attributes that can be specified for the columns. This is where a default value may be specified.
Specify CREATE TABLE Statement Type information, press Enter. Table . . . . . . . . . Collection . . . . . . Data: INVENTORY_LIST______ SAMPLECOLL__ Name Name, F4 for list

1=BIT, 2=SBCS, 3=MIXED, 4=CCSID Data _ _ _ _ _ _ _ Allocate _____ _____ _____ _____ _____ _____ _____

Column ITEM NUMBER_______ ITEM NAME_________ UNIT_COST_________ QUANTITY_ON_HAND__ LAST_ORDER_DATE___ ORDER_QUANTITY____ __________________

CCSID CONSTRAINT Default _____ N __________________ _____ N '***UNKNOWN***'___ _____ N __________________ _____ N NULL______________ _____ N __________________ _____ N 20________________ _____ _ __________________ Bottom Table CONSTRAINT . . . . . . . . . . . . . N Y=Yes, N=No Distributed Table . . . . . . . . . . . . N Y=Yes, N=No F5=Refresh F12=Cancel F6=Insert line F14=Delete line F10=Copy line F24=More keys

F3=Exit F4=Prompt F11=Display more attributes

Note: Another way of entering column definitions is to press F4 (Prompt) with your cursor on one of the column entries in the list. This will bring up a display that shows all of the attributes for defining a single column.
Chapter 2. Getting Started with SQL

15

When all the values have been entered, press Enter to create the table. The Enter SQL Statements display will be shown again with a message indicating that the table has been created. You can directly key in this CREATE TABLE statement on the Enter SQL Statements display as follows:
CREATE TABLE SAMPLECOLL.INVENTORY_LIST (ITEM_NUMBER CHAR(6) NOT NULL, ITEM_NAME VARCHAR(20) NOT NULL WITH DEFAULT '***UNKNOWN***', UNIT_COST DECIMAL(8,2) NOT NULL WITH DEFAULT, QUANTITY_ON_HAND SMALLINT DEFAULT NULL, LAST_ORDER_DATE DATE, ORDER_QUANTITY SMALLINT DEFAULT 20)

Creating the Supplier Table (SUPPLIERS)


Later in our examples, we will need a second table as well. This table will contain information about suppliers of our inventory items, which items they supply, and the cost of the item from that supplier. To create it, either type it in directly on the Enter SQL Statements display or press F4 (Prompt) to use the interactive SQL displays to create the definition.
CREATE TABLE SAMPLECOLL.SUPPLIERS (SUPPLIER_NUMBER CHAR(4) NOT NULL, ITEM_NUMBER CHAR(6) NOT NULL, SUPPLIER_COST DECIMAL(8,2))

Using the LABEL ON statement


Normally, the column name is used as the column heading when showing the output of a SELECT statement in interactive SQL. By using the LABEL ON statement, you can create a more descriptive label for the column name. Since we are going to be running our examples in interactive SQL, we will use the LABEL ON statement to change the column headings. Even though the column names are descriptive, it will be easier to read if the column headings show each part of the name on a single line. It will also allow us to see more columns of our data on a single display. To change the labels for our columns, type LABEL ON COLUMN on the Enter SQL Statements display and press F4 (Prompt). The following display will appear:

16

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Specify LABEL ON Statement Type choices, press Enter. Label on . . . . 2 1=Table or view 2=Column 3=Package 4=Alias Name, F4 for list Name, F4 for list 1=Column heading 2=Text

Table or view Collection . . Option . . . . .

INVENTORY_LIST______ SAMPLECOLL__ 1

F3=Exit F4=Prompt F5=Refresh F21=Display statement

F12=Cancel

F20=Display full names

Type in the name of the table and collection containing the columns for which you want to add labels and press Enter. The following display will be shown, prompting you for each of the columns in the table.
Specify LABEL ON Statement Type information, press Enter. Column ITEM_NUMBER ITEM_NAME UNIT_COST QUANTITY_ON_HAND LAST_ORDER_DATE ORDER_QUANTITY Column Heading ....+....1....+....2....+....3....+....4....+....5.... 'ITEM NUMBER'___________________________ 'ITEM NAME'_____________________________ 'UNIT COST'_____________________________ 'QUANTITY ON HAND'_________ 'LAST ORDER DATE'_________ 'NUMBER ORDERED'__________________________

F3=Exit F14=Delete line

Bottom F5=Refresh F6=Insert line F10=Copy line F12=Cancel F19=Display system column names F24=More keys

Type the column headings for each of the columns. Column headings are defined in 20 character sections. Each section will be displayed on a different line when showing the output of a SELECT statement. The ruler across the top of the column heading entry area can be used to easily space the headings correctly. When the headings are typed, press Enter. The following message indicates that the LABEL ON statement was successful.
LABEL ON for INVEN00001 in SAMPLECOLL completed.

The table name in the message is the system table name for this table, not the name that was actually specified in the statement. DB2 UDB for AS/400 maintains
Chapter 2. Getting Started with SQL

17

two names for tables with names longer than ten characters. For more information on system table names, see the CREATE TABLE statement in the SQL Reference book. The LABEL ON statement can also be keyed in directly on the Enter SQL statements display as follows:
LABEL ON SAMPLECOLL/INVENTORY_LIST (ITEM_NUMBER IS 'ITEM ITEM_NAME IS 'ITEM UNIT_COST IS 'UNIT QUANTITY_ON_HAND IS 'QUANTITY LAST_ORDER_DATE IS 'LAST ORDER_QUANTITY IS 'NUMBER NUMBER', NAME', COST', ON ORDER ORDERED')

HAND', DATE',

Inserting information into a table


After you create a table, you can insert, or add, information (data) into it by using Operations Navigator. Or you can use the SQL INSERT statement. For an example of inserting data into a table using interactive SQL, see Example: Inserting information into a table (INVENTORY_LIST).

Example: Inserting information into a table (INVENTORY_LIST)


To work with interactive SQL, on the Enter SQL Statements display, type INSERT and press F4 (Prompt). The Specify INSERT Statement display will be shown.
Specify INSERT Statement Type choices, press Enter. INTO table . . . . . . . Collection . . . . . . Select columns to insert INTO . . . . . . . . . Insertion method . . . . Type choices, press Enter. WITH isolation level . . 1 1=Current level, 2=NC (NONE) 3=UR (CHG), 4=CS, 5=RS (ALL) 6=RR INVENTORY_LIST______ SAMPLECOLL__ Y 1 Name, F4 for list Name, F4 for list Y=Yes, N=No 1=Input VALUES 2=Subselect

F3=Exit F4=Prompt F5=Refresh F21=Display statement

F12=Cancel

F20=Display full names

Type the table name and collection name in the input fields as shown. Change the Select columns to insert INTO prompt to Yes. Press Enter to see the display where the columns you want to insert values into can be selected.

18

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Specify INSERT Statement Type sequence numbers (1-999) to make selections, press Enter. Seq 1__ 2__ 3__ 4__ ___ ___ Column ITEM_NUMBER ITEM_NAME UNIT_COST QUANTITY_ON_HAND LAST_ORDER_DATE ORDER_QUANTITY Type CHARACTER VARCHAR DECIMAL SMALLINT DATE SMALLINT Length 6 20 8 4 4 Bottom Scale 2

F3=Exit F5=Refresh F20=Display entire name

F12=Cancel F19=Display system column names F21=Display statement

In this example, we only want to insert into four of the columns. We will let the other columns have their default value inserted. The sequence numbers on this display indicate the order that the columns and values will be listed in the INSERT statement. Press Enter to show the display where values for the selected columns can be typed.
Specify INSERT Statement Type values to insert, press Enter. Column ITEM_NUMBER ITEM_NAME UNIT_COST QUANTITY_ON_HAND Value '153047'_____________________________________________ 'Pencils, red'_______________________________________ 10.00________________________________________________ 25___________________________________________________

F3=Exit F12=Cancel

Bottom F5=Refresh F6=Insert line F10=Copy line F11=Display type F14=Delete line F15=Split line F24=More keys

Note: To see the data type and length for each of the columns in the insert list, press F11 (Display type). This will show a different view of the insert values display, providing information about the column definition. Type the values to be inserted for all of the columns and press Enter. A row containing these values will be added to the table. The values for the columns that were not specified will have a default value inserted. For LAST_ORDER_DATE it will be the null value since no default was provided and the column allows the null value. For ORDER_QUANTITY it will be 20, the value specified as the default value on the CREATE TABLE statement. You can type the INSERT statement on the Enter SQL Statements display as:
INSERT INTO SAMPLECOLL.INVENTORY_LIST (ITEM_NUMBER, ITEM_NAME, UNIT_COST, QUANTITY_ON_HAND)

Chapter 2. Getting Started with SQL

19

VALUES('153047', 'Pencils, red', 10.00, 25)

To add the next row to the table, press F9 (Retrieve) on the Enter SQL Statements display. This will copy the previous INSERT statement to the typing area. You can either type over the values from the previous INSERT statement or press F4 (Prompt) to use the Interactive SQL displays to enter data. Continue using the INSERT statement to add the following rows to the table. Values not shown in the chart below should not be inserted so that the default will be used. In the INSERT statement column list, specify only the column names for which you want to insert a value. For example, to insert the third row, you would specify only ITEM_NUMBER and UNIT_COST for the column names and only the two values for these columns in the VALUES list.
ITEM_NUMBER 153047 229740 544931 303476 559343 291124 775298 073956 Paper clips Envelopes, legal Envelopes, standard Chairs, secretary Pens, black 225.00 20.00 6 25 ITEM_NAME Pencils, red Lined tablets UNIT_COST 10.00 1.50 5.00 2.00 3.00 100 500 QUANTITY_ON_HAND 25 120

Add the following rows to the SAMPLECOLL.SUPPLIERS table.


SUPPLIER_NUMBER 1234 1234 1234 9988 9988 2424 2424 5546 3366 3366 ITEM_NUMBER 153047 229740 303476 153047 559343 153047 303476 775298 303476 073956 SUPPLIER_COST 10.00 1.00 3.00 8.00 3.00 9.00 2.50 225.00 1.50 17.00

The sample collection now contains two tables with several rows of data in each.

Getting information from a single table


Now that we have inserted all the information into our tables, we need to be able to look at it again. In SQL, this is done with the SELECT statement. The SELECT statement is the most complex of all SQL statements. This statement is composed of three main clauses: 1. The SELECT clause, which specifies those columns containing the desired data.

20

DB2 UDB for AS/400 SQL Programming Concepts V4R5

2. The FROM clause, which specifies the table or tables containing the columns with the desired data. 3. The WHERE clause, which supplies conditions that determine which rows of data are retrieved. In addition to the three main clauses, there are several other clauses described in Using basic SQL statements and clauses on page 31, and in the SQL Reference book, which affect the final form of returned data. To see the values we inserted into the INVENTORY_LIST table, type SELECT and press F4 (prompt). The following display will be shown:
Specify SELECT Statement Type SELECT statement information. FROM tables . . . . . SELECT columns . . . . WHERE conditions . . . GROUP BY columns . . . HAVING conditions . . ORDER BY columns . . . FOR UPDATE OF columns . . . . . . . . . . . . . . . . . . . . . Press F4 for a list.

SAMPLECOLL.INVENTORY_LIST____________________ *____________________________________________ _____________________________________________ _____________________________________________ _____________________________________________ _____________________________________________ _____________________________________________ Bottom N N N Y=Yes, N=No Y=Yes, N=No Y=Yes, N=No

Type choices, press Enter. DISTINCT rows in result table . . . . . . . . . UNION with another SELECT . . . . . . . . . . . Specify additional options . . . . . . . . . . .

F3=Exit F10=Copy line

F4=Prompt F5=Refresh F6=Insert line F9=Specify subquery F12=Cancel F14=Delete line F15=Split line F24=More keys

Type the table name in the FROM tables field on the display. To select all columns from the table, type * for the SELECT columns field on the display. Press Enter and the statement will run to select all of the data for all of the columns in the table. The following output will be shown:
Data width . . . . . . : Position to line . . . . . Shift to column . . . . . . ....+....1....+....2....+....3....+....4....+....5....+....6....+....7. ITEM ITEM UNIT QUANTITY LAST NUMBER NUMBER NAME COST ON ORDER ORDERED HAND DATE 153047 Pencils, red 10.00 25 20 229740 Lined tablets 1.50 120 20 544931 ***UNKNOWN*** 5.00 - 20 303476 Paper clips 2.00 100 20 559343 Envelopes, legal 3.00 500 20 291124 Envelopes, standard .00 - 20 775298 Chairs, secretary 225.00 6 20 073956 Pens, black 20.00 25 20 ******** End of data ******** F3=Exit F12=Cancel F19=Left F20=Right F21=Split Display Data 71

The column headings that were defined using the LABEL ON statement are shown. The ITEM_NAME for the third entry has the default value that was specified in the CREATE TABLE statement. The QUANTITY_ON_HAND column has a null value for the rows where no value was inserted. The LAST_ORDER_DATE column contains all null values since that column is not in
Chapter 2. Getting Started with SQL

21

any of the INSERT statements and the column was not defined to have a default value. Similarly, the ORDER_QUANTITY column contains the default value for all rows. This statement could be entered on the Enter SQL Statements display as:
SELECT * FROM SAMPLECOLL.INVENTORY_LIST

To limit the number of columns returned by the SELECT statement, the columns you want to see must be specified. To restrict the number of output rows returned, the WHERE clause is used. To see only the items that cost more than 10 dollars, and only have the values for the columns ITEM_NUMBER, UNIT_COST, and ITEM_NAME returned, type SELECT and press F4 (Prompt). The Specify SELECT Statement display will be shown.
Specify SELECT Statement Type SELECT statement information. FROM tables . . . . . SELECT columns . . . . WHERE conditions . . . GROUP BY columns . . . HAVING conditions . . ORDER BY columns . . . FOR UPDATE OF columns . . . . . . . . . . . . . . . . . . . . . Press F4 for a list.

SAMPLECOLL.INVENTORY_LIST____________________ ITEM_NUMBER, UNIT_COST, ITEM_NAME____________ UNIT_COST > 10.00____________________________ _____________________________________________ _____________________________________________ _____________________________________________ _____________________________________________ Bottom N N N Y=Yes, N=No Y=Yes, N=No Y=Yes, N=No

Type choices, press Enter. DISTINCT rows in result table . . . . . . . . . UNION with another SELECT . . . . . . . . . . . Specify additional options . . . . . . . . . . .

F3=Exit F10=Copy line

F4=Prompt F5=Refresh F6=Insert line F9=Specify subquery F12=Cancel F14=Delete line F15=Split line F24=More keys

Although only one line is initially shown for each prompt on the Specify SELECT Statement display, F6 (Insert line) can be used to add more lines to any of the input areas in the top part of the display. This could be used if more columns were to be entered in the SELECT columns list, or a longer, more complex WHERE condition were needed. Fill in the display as shown above. When Enter is pressed, the SELECT statement is run. The following output will be seen:
Data width . . . . . . : Position to line . . . . . Shift to column . . . . . . ....+....1....+....2....+....3....+....4. ITEM UNIT ITEM NUMBER COST NAME 775298 225.00 Chairs, secretary 073956 20.00 Pens, black ******** End of data ******** F3=Exit F12=Cancel F19=Left F20=Right F21=Split Display Data 41

The only rows returned are those whose data values compare with the condition specified in the WHERE clause. Furthermore, the only data values returned are from the columns you explicitly specified in the SELECT clause. Data values of columns other than those explicitly identified are not returned.

22

DB2 UDB for AS/400 SQL Programming Concepts V4R5

This statement could have been entered on the Enter SQL Statements display as:
SELECT ITEM_NUMBER, UNIT_COST, ITEM_NAME FROM SAMPLECOLL.INVENTORY_LIST WHERE UNIT_COST > 10.00

Getting information from more than one table


SQL allows you to get information from columns contained in more than one table. This operation is called a join operation. (For a more detailed description of the join operation, see Joining data from more than one table on page 75). In SQL, a join operation is specified by placing the names of those tables you want to join together into the same FROM clause of a SELECT statement. Suppose you want to see a list of all the suppliers and the item numbers and item names for their supplied items. The item name is not in the SUPPLIERS table. It is in the INVENTORY_LIST table. Using the common column, ITEM_NUMBER, we can see all three of the columns as if they were from a single table. Whenever the same column name exists in two or more tables being joined, the column name must be qualified by the table name to specify which column is really being referenced. In this SELECT statement, the column name ITEM_NUMBER is defined in both tables so the column name needs to be qualified by the table name. If the columns had different names, there would be no confusion so qualification would not be needed. To perform this join, the following SELECT statement can be used. Enter it by typing it directly on the Enter SQL Statements display or by prompting. If using prompting, both table names need to be typed on the FROM tables input line.
SELECT SUPPLIER_NUMBER, SAMPLECOLL.INVENTORY_LIST.ITEM_NUMBER, ITEM_NAME FROM SAMPLECOLL.SUPPLIERS, SAMPLECOLL.INVENTORY_LIST WHERE SAMPLECOLL.SUPPLIERS.ITEM_NUMBER = SAMPLECOLL.INVENTORY_LIST.ITEM_NUMBER

Another way to enter the same statement is to use a correlation name. A correlation name provides another name for a table name to use in a statement. A correlation name must be used when the table names are the same. It can be specified following each table name in the FROM list. The previous statement could be rewritten as:
SELECT SUPPLIER_NUMBER, Y.ITEM_NUMBER, ITEM_NAME FROM SAMPLECOLL.SUPPLIERS X, SAMPLECOLL.INVENTORY_LIST Y WHERE X.ITEM_NUMBER = Y.ITEM_NUMBER

In this example, SAMPLECOLL.SUPPLIERS is given a correlation name of X and SAMPLECOLL.INVENTORY_LIST is given a correlation name of Y. The names X and Y are then used to qualify the ITEM_NUMBER column name. For more information on correlation names, see the SQL Reference book. Running this example returns the following output:

Chapter 2. Getting Started with SQL

23

Data width . . . . . . : Position to line . . . . . Shift to column . . . . . . ....+....1....+....2....+....3....+....4....+ SUPPLIER_NUMBER ITEM ITEM NUMBER NAME 1234 153047 Pencils, red 9988 153047 Pencils, red 2424 153047 Pencils, red 1234 229740 Lined tablets 1234 303476 Paper clips 2424 303476 Paper clips 3366 303476 Paper clips 9988 559343 Envelopes, legal 5546 775298 Chairs, secretary 3366 073956 Pens, black ******** End of data ******** F3=Exit F12=Cancel F19=Left F20=Right F21=Split

Display Data

45

The data values in the result table represent a composite of the data values contained in the two tables INVENTORY_LIST and SUPPLIERS. This result table contains the supplier number from the SUPPLIER table and the item number and item name from the INVENTORY_LIST table. Any item numbers that do not appear in the SUPPLIER table are not shown in this result table. The results are not guaranteed to be in any order unless the ORDER BY clause is specified for the SELECT statement. Since we did not change any column headings for the SUPPLIER table, the SUPPLIER_NUMBER column name is used as the column heading. The following is an example of using ORDER BY to guarantee the order of the rows. The statement will first order the result table by the SUPPLIER_NUMBER column. Rows with the same value for SUPPLIER_NUMBER will be ordered by their ITEM_NUMBER.
SELECT SUPPLIER_NUMBER, Y.ITEM_NUMBER, ITEM_NAME FROM SAMPLECOLL.SUPPLIERS X, SAMPLECOLL.INVENTORY_LIST Y WHERE X.ITEM_NUMBER = Y.ITEM_NUMBER ORDER BY SUPPLIER_NUMBER, Y.ITEM_NUMBER

Running the previous statement would produce the following output.

24

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Data width . . . . . . : Position to line . . . . . Shift to column . . . . . . ....+....1....+....2....+....3....+....4....+ SUPPLIER_NUMBER ITEM ITEM NUMBER NAME 1234 153047 Pencils, red 1234 229740 Lined tablets 1234 303476 Paper clips 2424 153047 Pencils, red 2424 303476 Paper clips 3366 073956 Pens, black 3366 303476 Paper clips 5546 775298 Chairs, secretary 9988 153047 Pencils, red 9988 559343 Envelopes, legal ******** End of data ******** F3=Exit F12=Cancel F19=Left F20=Right F21=Split

Display Data

45

Changing information in a table


You can use the SQL UPDATE statement to change the data values in some or all of the columns of a table. You may also use Operations Navigator to accomplish this task. For an example of changing information in a table using interactive SQL, see Example: Changing information in a table. If you want to limit the number of rows being changed during a single statement execution, use the WHERE clause with the UPDATE statement. For more information see, Changing data in a table using the UPDATE statement on page 33. If you do not specify the WHERE clause, all of the rows in the specified table are changed. However, if you use the WHERE clause, the system changes only the rows satisfying the conditions that you specify. For more information, see Specifying a search condition using the WHERE clause on page 38.

Example: Changing information in a table


Suppose we want to use interactive SQL and are placing an order for more paper clips today. To update the LAST_ORDER_DATE and ORDER_QUANTITY for item number 303476, type UPDATE and press F4 (Prompt). The Specify UPDATE Statement display will be shown.

Chapter 2. Getting Started with SQL

25

Specify UPDATE Statement Type choices, press Enter. Table . . . . . . . . Collection . . . . . Correlation . . . . . INVENTORY_LIST______ SAMPLECOLL__ ____________________ Name, F4 for list Name, F4 for list Name

F3=Exit F4=Prompt F5=Refresh F21=Display statement

F12=Cancel

F20=Display full names

After typing the table name and collection name, press Enter. The display will be shown again with the list of columns in the table.
Specify UPDATE Statement Type choices, press Enter. Table . . . . . . . . Collection . . . . . Correlation . . . . . INVENTORY_LIST______ SAMPLECOLL__ ____________________ Name, F4 for list Name, F4 for list Name

Type information, press Enter. Column ITEM_NUMBER ITEM_NAME UNIT_COST QUANTITY_ON_HAND LAST_ORDER_DATE ORDER_QUANTITY F3=Exit F4=Prompt F11=Display type Value _____________________________________________________ _____________________________________________________ _____________________________________________________ _____________________________________________________ CURRENT DATE_________________________________________ 50___________________________________________________ F5=Refresh F12=Cancel F6=Insert line F14=Delete line F10=Copy line F24=More keys Bottom

Specifying CURRENT DATE for a value will change the date in all the selected rows to be todays date. After typing the values to be updated for the table, press Enter to see the display on which the WHERE condition can be specified. If a WHERE condition is not specified, all the rows in the table will be updated using the values from the previous display.

26

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Specify UPDATE Statement Type WHERE conditions, press Enter. Press F4 for a list. ITEM_NUMBER = '303476'________________________________________________ ______________________________________________________________________

Type choices, press Enter. WITH isolation level . . . 1

Bottom 1=Current level, 2=NC (NONE) 3=UR (CHG), 4=CS, 5=RS (ALL) 6=RR

F3=Exit F10=Copy line

F4=Prompt F5=Refresh F6=Insert line F9=Specify subquery F12=Cancel F14=Delete line F15=Split line F24=More keys

After typing the condition, press Enter to perform the update on the table. A message will indicate that the function is complete. This statement could have been typed on the Enter SQL Statements display as:
UPDATE SAMPLECOLL.INVENTORY_LIST SET LAST_ORDER_DATE = CURRENT DATE, ORDER_QUANTITY = 50 WHERE ITEM_NUMBER = '303476'

Running a SELECT statement to get all the rows from the table (SELECT * FROM SAMPLECOLL.INVENTORY_LIST), returns the following result:
Data width . . . . . . : 71 Position to line . . . . . Shift to column . . . . . . ....+....1....+....2....+....3....+....4....+....5....+....6....+....7. ITEM ITEM UNIT QUANTITY LAST NUMBER NUMBER NAME COST ON ORDER ORDERED HAND DATE 153047 Pencils, red 10.00 25 20 229740 Lined tablets 1.50 120 20 544931 ***UNKNOWN*** 5.00 - 20 303476 Paper clips 2.00 100 05/30/94 50 559343 Envelopes, legal 3.00 500 20 291124 Envelopes, standard .00 - 20 775298 Chairs, secretary 225.00 6 20 073956 Pens, black 20.00 25 20 ******** End of data ******** Bottom F3=Exit F12=Cancel F19=Left F20=Right F21=Split Display Data

Only the entry for Paper clips was changed. The LAST_ORDER_DATE was changed to be the current date. This date is always the date the update is run. The NUMBER_ORDERED shows its updated value.

Chapter 2. Getting Started with SQL

27

Deleting information from a table


You can delete data from a table by using Operations Navigator. Or, using the SQL DELETE statement, you can delete entire rows from a table when they no longer contain needed information. You can use the WHERE clause with the DELETE statement to identify rows to be deleted during a single statement execution. For more information, see Removing rows from a table using the DELETE statement on page 34. For an example of deleting information in a table using interactive SQL, see Example: Deleting information from a table (INVENTORY_LIST).

Example: Deleting information from a table (INVENTORY_LIST)


If we want to remove all the rows in our table that have the null value for the QUANTITY_ON_HAND column, you could enter the following statement on the Enter SQL Statements display:
DELETE FROM SAMPLECOLL.INVENTORY_LIST WHERE QUANTITY_ON_HAND IS NULL

To check a column for the null value, the IS NULL comparison is used. Running another SELECT statement after the delete has completed will return the following result table:
Data width . . . . . . : Position to line . . . . . Shift to column . . . . . . ....+....1....+....2....+....3....+....4....+....5....+....6....+....7. ITEM ITEM UNIT QUANTITY LAST NUMBER NUMBER NAME COST ON ORDER ORDERED HAND DATE 153047 Pencils, red 10.00 25 20 229740 Lined tablets 1.50 120 20 303476 Paper clips 2.00 100 05/30/94 50 559343 Envelopes, legal 3.00 500 20 775298 Chairs, secretary 225.00 6 20 073956 Pens, black 20.00 25 20 ******** End of data ******** F3=Exit F12=Cancel F19=Left F20=Right F21=Split Display Data 71

Bottom

The rows with a null value for QUANTITY_ON_HAND were deleted.

Creating and using a view


You may find that no single table contains all the information you need. You may also want to give users access to only part of the data in a table. Views provide a way to subset the table so that you deal with only the data you need. A view reduces complexity and, at the same time, restricts access. You can create a view using Operations Navigator. Or you can use the SQL CREATE VIEW statement. Using the CREATE VIEW statement, defining a view on a table is like creating a new table containing just the columns and rows you want. When your application uses a view, it cannot access rows or columns of the table that are not included in the view. However, rows that do not match the selection

28

DB2 UDB for AS/400 SQL Programming Concepts V4R5

criteria may still be inserted through a view if the SQL WITH CHECK OPTION is not used. See Chapter 6. Data Integrity for more information on using WITH CHECK OPTION. For examples of creating a view using interactive SQL, see the following: v Example: Creating a view on a single table v Example: Creating a view combining data from more than one table on page 30 In order to create a view you must have the proper authority to the tables or physical files on which the view is based. See the CREATE VIEW statement in the SQL Reference for a list of authorities needed. If you do not specify column names in the view definition, the column names will be the same as those for the table on which the view is based. You can make changes to a table through a view even if the view has a different number of columns or rows than the table. For INSERT, columns in the table that are not in the view must have a default value. You can use the view as though it were a table, even though the view is totally dependent on one or more tables for data. The view has no data of its own and therefore requires no storage for the data. Because a view is derived from a table that exists in storage, when you update the view data, you are really updating data in the table. Therefore, views are automatically kept up-to-date as the tables they depend on are updated. See Creating and using views on page 95 for additional information.

Example: Creating a view on a single table


The following example shows how to create a view on a single table. The view is built on the INVENTORY_LIST table. The table has six columns, but the view uses only three of the columns: ITEM_NUMBER, LAST_ORDER_DATE, and QUANTITY_ON_HAND. The order of the columns in the SELECT clause is the order in which they will appear in the view. The view will contain only the rows for items that were ordered in the last two weeks. The CREATE VIEW statement looks like this:
CREATE VIEW SAMPLECOLL.RECENT_ORDERS AS SELECT ITEM_NUMBER, LAST_ORDER_DATE, QUANTITY_ON_HAND FROM SAMPLECOLL.INVENTORY_LIST WHERE LAST_ORDER_DATE > CURRENT DATE - 14 DAYS

In the example above, the columns in the view have the same name as the columns in the table because no column list follows the view name. The collection that the view is created into does not need to be the same collection as the table it is built over. Any collection or library could be used. The following display is the result of running the SQL statement:
SELECT * FROM SAMPLECOLL.RECENT_ORDERS

Chapter 2. Getting Started with SQL

29

Display Data Position to line . . . . . ....+....1....+....2....+. ITEM LAST QUANTITY NUMBER ORDER ON DATE HAND 303476 05/30/94 100 ******** End of data ******** F3=Exit F12=Cancel F19=Left

Data width . . . . . . : Shift to column . . . . . .

26

F20=Right

F21=Split

Bottom

The only row selected by the view is the row that we updated to have the current date. All other dates in our table still have the null value so they are not returned.

Example: Creating a view combining data from more than one table
You can create a view that combines data from two or more tables by naming more than one table in the FROM clause. In the following example, the INVENTORY_LIST table contains a column of item numbers called ITEM_NUMBER, and a column with the cost of the item, UNIT_COST. These are joined with the ITEM_NUMBER column and the SUPPLIER_COST column of the SUPPLIERS table. A WHERE clause is used to limit the number of rows returned. The view will only contain those item numbers for suppliers that can supply an item at lower cost than the current unit cost. The CREATE VIEW statement looks like this:
CREATE VIEW SAMPLECOLL.LOWER_COST AS SELECT SUPPLIER_NUMBER, A.ITEM_NUMBER, UNIT_COST, SUPPLIER_COST FROM SAMPLECOLL.INVENTORY_LIST A, SAMPLECOLL.SUPPLIERS B WHERE A.ITEM_NUMBER = B.ITEM_NUMBER AND UNIT_COST > SUPPLIER_COST

The following table is the result of running the SQL statement:


SELECT * FROM SAMPLECOLL.LOWER_COST
Data width . . . . . . : Position to line . . . . . Shift to column . . . . . . ....+....1....+....2....+....3....+....4....+....5. SUPPLIER_NUMBER ITEM UNIT SUPPLIER_COST NUMBER COST 9988 153047 10.00 8.00 2424 153047 10.00 9.00 1234 229740 1.50 1.00 3366 303476 2.00 1.50 3366 073956 20.00 17.00 ******** End of data ******** F3=Exit F12=Cancel F19=Left F20=Right F21=Split Display Data 51

Bottom

The rows that can be seen through this view are only those rows that have a supplier cost that is less than the unit cost.

30

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Chapter 3. Basic Concepts and Techniques


This chapter explains some of the concepts used in SQL statements. It discusses many of the common statements and clauses in SQL. The examples in this chapter refer to the tables shown in Appendix A. DB2 UDB for AS/400 Sample Tables.

Using basic SQL statements and clauses


This section shows the basic SQL statements and clauses that retrieve, update, delete, and insert data into tables and views. The SQL statements used are SELECT, UPDATE, DELETE, and INSERT. FETCH statements can be used in an application program to access data as well. This statement is covered in Chapter 4. Examples using these SQL statements are supplied to help you develop SQL applications. Detailed syntax and parameter descriptions for SQL statements are given in the SQL Reference book. You can write SQL statements on one line or on many lines. The rules for the continuation of lines are the same as those of the host language (the language the program is written in). Notes: 1. The SQL statements described in this section can be run on SQL tables and views, and database physical and logical files. The tables, views, and files can be either in an SQL collection or in a library. 2. Character strings specified in an SQL statement (such as those used with WHERE or VALUES clauses) are case sensitive; that is, uppercase characters must be entered in uppercase and lowercase characters must be entered in lowercase.
WHERE ADMRDEPT='a00' WHERE ADMRDEPT='A00' (does not return a result) (returns a valid department number)

Comparisons may not be case sensitive if a shared-weight sort sequence is being used where uppercase and lowercase characters are treated as the same character.

Inserting rows using the INSERT statement


You can use the INSERT statement to add new rows to a table or view in one of the following ways: v Specifying values in the INSERT statement for columns of the single row to be added. v Specifying the blocked form of the INSERT statement to add multiple rows. Inserting multiple rows in a table with the blocked INSERT statement on page 70 explains how to use the blocked form of the INSERT statement to add multiple rows to a table. v Including a select-statement in the INSERT statement to tell SQL what data for the new row is contained in another table or view. Inserting rows into a table using a Select-Statement on page 69 explains how to use the select-statement within an INSERT statement to add zero, one, or many rows to a table.

Copyright IBM Corp. 2000

31

Note: Because views are built on tables and actually contain no data, working with views can be confusing. See Creating and using views on page 95 for more information on inserting data by using a view. For every row you insert, you must supply a value for each column defined with the NOT NULL attribute if that column does not have a default value. The INSERT statement for adding a row to a table or view may look like this:
INSERT INTO table-name (column1, column2, ... ) VALUES (value-for-column1, value-for-column2, ... )

The INTO clause names the columns for which you specify values. The VALUES clause specifies a value for each column named in the INTO clause. You must provide a value in the VALUES clause for each column named in an INSERT statements column list. The column name list can be omitted if all columns in the table have a value provided in the VALUES clause. If a column has a default value, the keyword DEFAULT may be used as a value on the VALUES clause. It is a good idea to name all columns into which you are inserting values because: v Your INSERT statement is more descriptive. v You can verify that you are giving the values in the proper order based on the column names. v You have better data independence. The order in which the columns are defined in the table does not affect your INSERT statement. If the column is defined to allow null values or to have a default, you do not need to name it in the column name list or specify a value for it. The default value is used. If the column is defined to have a default value, the default value is placed in the column. If DEFAULT was specified for the column definition without an explicit default value, SQL places the default value for that data type in the column. If the column does not have a default value defined for it, but is defined to allow the null value (NOT NULL was not specified in the column definition), SQL places the null value in the column. v For numeric columns, the default value is 0. v For fixed length character or graphic columns, the default is blanks. v For varying length character or graphic columns or LOB columns, the default is a zero length string. v For date, time, and timestamp columns, the default value is the current date, time, or timestamp. When inserting a block of records, the default date/time value is extracted from the system when the block is written. This means that the column will be assigned the same default value for each row in the block. v For DataLink columns, the default value corresponds to DLVALUE(,URL,). v For distinct-type columns, the default value is the default value of the corresponding source type. When your program attempts to insert a row that duplicates another row already in the table, an error might occur. Multiple null values may or may not be considered duplicate values, depending on the option used when the index was created. v If the table has a primary key, unique key, or unique index, the row is not inserted. Instead, SQL returns an SQLCODE of 803.

32

DB2 UDB for AS/400 SQL Programming Concepts V4R5

v If the table does not have a primary key, unique key, or unique index, the row can be inserted without error. If SQL finds an error while running the INSERT statement, it stops inserting data. If you specify COMMIT(*ALL), COMMIT(*CS), COMMIT(*CHG), or COMMIT(*RR), no rows are inserted. Rows already inserted by this statement, in the case of INSERT with a select-statement or blocked insert, are deleted. If you specify COMMIT(*NONE), any rows already inserted are not deleted. A table created by SQL is created with the Reuse Deleted Records parameter of *YES. This allows the database manager to reuse any rows in the table that were marked as deleted. The CHGPF command can be used to change the attribute to *NO. This causes INSERT to always add rows to the end of the table. The order in which rows are inserted does not guarantee the order in which they will be retrieved. If the row is inserted without error, the SQLERRD(3) field of the SQLCA has a value of 1. Note: For blocked INSERT or for INSERT with select-statement, more than one row can be inserted. The number of rows inserted is reflected in SQLERRD(3).

Changing data in a table using the UPDATE statement


To change the data in a table, use the UPDATE statement. With the UPDATE statement, you can change the value of one or more columns in each row that satisfies the search condition of the WHERE clause. The result of the UPDATE statement is one or more changed column values in zero or more rows of a table (depending on how many rows satisfy the search condition specified in the WHERE clause). The UPDATE statement looks like this:
UPDATE table-name SET column-1 = value-1, column-2 = value-2, ... WHERE search-condition ...

For example, suppose an employee was relocated. To update several items of the employees data in the CORPDATA.EMPLOYEE table to reflect the move, you can specify:
UPDATE CORPDATA.EMPLOYEE SET JOB = :PGM-CODE, PHONENO = :PGM-PHONE WHERE EMPNO = :PGM-SERIAL

Use the SET clause to specify a new value for each column you want to update. The SET clause names the columns you want updated and provides the values you want them changed to. The value you specify can be: A column name. Replace the columns current value with the contents of another column in the same row. A constant. Replace the columns current value with the value provided in the SET clause. A null value. Replace the columns current value with the null value, using the keyword NULL. The column must be defined as capable of containing a null value when the table was created, or an error occurs.
Chapter 3. Basic Concepts and Techniques

33

A host variable. Replace the columns current value with the contents of a host variable. A special register. Replace the columns current value with a special register value; for example, USER. An expression. Replace the columns current value with the value that results from an expression. The expression can contain any of the values in this list. A scalar subselect. Replace the columns current value with the value that the subquery returns. The DEFAULT keyword. Replace the columns current value with the default value of the column. The column must have a default value defined for it or allow the NULL value, or an error occurs. The following is an example of a statement that uses many different values:
UPDATE WORKTABLE SET COL1 = 'ASC', COL2 = NULL, COL3 = :FIELD3, COL4 = CURRENT TIME, COL5 = AMT - 6.00, COL6 = COL7 WHERE EMPNO = :PGM-SERIAL

To identify the rows to be updated, use the WHERE clause: v To update a single row, use a WHERE clause that selects only one row. v To update several rows, use a WHERE clause that selects only the rows you want to update. You can omit the WHERE clause. If you do, SQL updates each row in the table or view with the values you supply. If the database manager finds an error while running your UPDATE statement, it stops updating and returns a negative SQLCODE. If you specify COMMIT(*ALL), COMMIT(*CS), COMMIT(*CHG), or COMMIT(*RR), no rows in the table are changed (rows already changed by this statement, if any, are restored to their previous values). If COMMIT(*NONE) is specified, any rows already changed are not restored to previous values. If the database manager cannot find any rows that satisfy the search condition, an SQLCODE of +100 is returned. Note: UPDATE with a WHERE clause may have updated more than one row. The number of rows updated is reflected in SQLERRD(3).

Removing rows from a table using the DELETE statement


To remove rows from a table, use the DELETE statement. When you DELETE a row, you remove the entire row. DELETE does not remove specific columns from the row. The result of the DELETE statement is the removal of zero or more rows of a table (depending on how many rows satisfy the search condition specified in the WHERE clause). If you omit the WHERE clause from a DELETE statement, SQL removes all the rows of the table. The DELETE statement looks like this:
DELETE FROM table-name WHERE search-condition ...

34

DB2 UDB for AS/400 SQL Programming Concepts V4R5

For example, suppose department D11 was moved to another place. You want to delete each row in the CORPDATA.EMPLOYEE table with a WORKDEPT value of D11 as follows:
DELETE FROM CORPDATA.EMPLOYEE WHERE WORKDEPT = 'D11'

The WHERE clause tells SQL which rows you want to delete from the table. SQL deletes all the rows that satisfy the search condition from the base table. You can omit the WHERE clause, but it is best to include one, because a DELETE statement without a WHERE clause deletes all the rows from the table or view. To delete a table definition as well as the table contents, issue the DROP statement (described in the SQL Reference book). If SQL finds an error while running your DELETE statement, it stops deleting data and returns a negative SQLCODE. If you specify COMMIT(*ALL), COMMIT(*CS), COMMIT(*CHG), or COMMIT(*RR), no rows in the table are deleted (rows already deleted by this statement, if any, are restored to their previous values). If COMMIT(*NONE) is specified, any rows already deleted are not restored to their previous values. If SQL cannot find any rows that satisfy the search condition, an SQLCODE of +100 is returned. Note: DELETE with WHERE clause may have deleted more than one row. The number of rows deleted is reflected in SQLERRD(3).

Querying data using the SELECT INTO statement


You can use a variety of statements and clauses to query your data. One way to do this is to use the SELECT INTO statement in a program to retrieve a specific row (for example, the row for an employee). Furthermore, in this example, a variety of clauses are used to gather data in a specific way. You can use the Specifying a search condition using the WHERE clause on page 38, The GROUP BY clause on page 41, HAVING clause on page 42, and ORDER BY clause on page 43 to tailor your query to gather data in a specific manner. The format and syntax shown here are very basic. SELECT INTO statements can be more varied than the examples presented in this chapter. A SELECT INTO statement can include the following: 1. The name of each column you want 2. The name of each host variable used to contain retrieved data 3. The name of the table or view that contains the data 4. A search condition to uniquely identify the row that contains the information you want 5. The name of each column used to group your data 6. A search condition that uniquely identifies a group that contains the information you want 7. The order of the results so a specific row among duplicates can be returned. A SELECT INTO statement looks like this:
SELECT column names INTO host variables FROM table or view name

Chapter 3. Basic Concepts and Techniques

35

WHERE search condition GROUP BY column names HAVING search condition ORDER BY column-name

The SELECT, INTO, and FROM clauses must be specified. The other clauses are optional. The INTO clause names the host variables (variables in your program used to contain retrieved column values). The value of the first column specified in the SELECT clause is put into the first host variable named in the INTO clause; the second value is put into the second host variable, and so on. The result table for a SELECT INTO should contain just one row. For example, each row in the CORPDATA.EMPLOYEE table has a unique EMPNO (employee number) column. The result of a SELECT INTO statement for this table if the WHERE clause contains an equal comparison on the EMPNO column, would be exactly one row (or no rows). Finding more than one row is an error, but one row is still returned. You can control which row will be returned in this error condition by specifying the ORDER BY clause. If you use the ORDER BY clause, the first row in the result table is returned. If you want more than one row to be the result of a select-statement, use a DECLARE CURSOR statement to select the rows, followed by a FETCH statement to move the column values into host variables one or many rows at a time. Using cursors is described in Chapter 4. Using a Cursor on page 55. The FROM clause names the table (or view) that contains the data you are interested in. For example, assume that each department listed in the CORPDATA.DEPARTMENT table has a unique department number. You want to retrieve the department name and manager number from the CORPDATA.DEPARTMENT table for department C01. To do this, your program can set PGM-DEPT to the value C01 and issue:
SELECT DEPTNAME, MGRNO INTO :PGM-DEPTNAME, :PGM-MGRNO FROM CORPDATA.DEPARTMENT WHERE DEPTNO = :PGM-DEPT

When the statement is run, the result is one row:


PGM-DEPTNAME INFORMATION CENTER PGMMGRNO 000030

These values are assigned to the host variables PGM-DEPTNAME and PGM-MGRNO. If SQL is unable to find a row that satisfies the search condition, an SQLCODE of +100 is returned. If SQL finds errors while running your select-statement, a negative SQLCODE is returned. If SQL finds more host variables than results, +326 is returned.

36

DB2 UDB for AS/400 SQL Programming Concepts V4R5

You can retrieve data from a view in exactly the same way you retrieve data from a table. However, there are several restrictions when you attempt to update, insert, or delete data in a view. These restrictions are described in Creating and using views on page 95.

Data retrieval errors


If SQL finds that a retrieved character or graphic column is too long to be placed in a host variable, SQL does the following: v Truncates the data while assigning the value to the host variable. v Sets SQLWARN0 and SQLWARN1 in the SQLCA to the value 'W'. v Sets the indicator variable, if provided, to the length of the value before truncation. If SQL finds a data mapping error while running a statement, one of two things occurs: v If the error occurs on an expression in the SELECT list and an indicator variable is provided for the expression in error: SQL returns a 2 for the indicator variable corresponding to the expression in error. SQL returns all valid data for that row. SQL returns a positive SQLCODE. v If an indicator variable is not provided, SQL returns the corresponding negative SQLCODE in the SQLCA. Data mapping errors include: v +138 - Argument of the substringing function is not valid. v +180 - Syntax for a string representation of a date, time, or timestamp is not valid. v +181 - String representation of a date, time, or timestamp is not a valid value. v +183 - Invalid result from a date/time expression. The resulting date or timestamp is not within the valid range of dates or timestamps. v +191 - MIXED data is not properly formed. v +304 - Numeric conversion error (for example, overflow, underflow, or division by zero). v +331 - Characters cannot be converted. v +420 - Character in the CAST argument is not valid. v +802 - Data conversion or data mapping error. For data mapping errors, the SQLCA reports only the last error detected. The indicator variable corresponding to each result column having an error is set to 2. If the full-select contains DISTINCT in the select list and a column in the select list contains numeric data that is not valid, the data is considered equal to a null value if the query is completed as a sort. If an existing index is used, the data is not considered equal to a null. The impact of data mapping errors on the ORDER BY clause depends on the situation: v If the data mapping error occurs while data is being assigned to a host variable in a SELECT INTO or FETCH statement, and that same expression is used in the
Chapter 3. Basic Concepts and Techniques

37

ORDER BY clause, the result record is ordered based on the value of the expression. It is not ordered as if it were a null (higher than all other values). This is because the expression was evaluated before the assignment to the host variable is attempted. v If the data mapping error occurs while an expression in the select-list is being evaluated and the same expression is used in the ORDER BY clause, the result column is normally ordered as if it were a null value (higher than all other values). If the ORDER BY clause is implemented by using a sort, the result column is ordered as if it were a null value. If the ORDER BY clause is implemented by using an existing index, in the following cases, the result column is ordered based on the actual value of the expression in the index: The expression is a date column with a date format of *MDY, *DMY, *YMD, or *JUL, and a date conversion error occurs because the date is not within the valid range for dates. The expression is a character column and a character could not be converted. The expression is a decimal column and a numeric value that is not valid is detected.

The SELECT clause


With the SELECT clause (the first part of a select-statement), you specify the name of each column you want to retrieve. For example:
SELECT EMPNO, LASTNAME, WORKDEPT . . .

You can specify that only one column be retrieved, or as many as 8000 columns. The value of each column you name is retrieved in the order specified in the SELECT clause. If you want to retrieve all columns (in the same order as they appear in the row), use an asterisk (*) instead of naming the columns:
SELECT * . . .

When using the select-statement in an application program, list the column names to give your program more data independence. There are two reasons for this: 1. When you look at the source code statement, you can easily see the one-to-one correspondence between the column names in the SELECT clause and the host variables named in the INTO clause. 2. If a column is added to a table or view you access and you use SELECT * ..., and you create the program again from source, the INTO clause does not have a matching host variable named for the new column. The extra column causes you to get a warning (not an error) in the SQLCA (SQLWARN4 will contain a W).

Specifying a search condition using the WHERE clause


The WHERE clause specifies a search condition that identifies the row or rows you want to retrieve, update, or delete. The number of rows you process with an SQL statement then depends on the number of rows that satisfy the WHERE clause

38

DB2 UDB for AS/400 SQL Programming Concepts V4R5

search condition. A search condition consists of one or more predicates. A predicate specifies a test that you want SQL to apply to a specified row or rows of a table. In the following example, WORKDEPT = 'C01' is a predicate, WORKDEPT and 'C01' are expressions, and the equal sign (=) is a comparison operator. Note that character values are enclosed in apostrophes ('); numeric values are not. This applies to all constant values wherever they are coded within an SQL statement. For example, to specify that you are interested in the rows where the department number is C01, you would say:
... WHERE WORKDEPT = 'C01'

In this case, the search condition consists of one predicate: WORKDEPT = 'C01'. If the search condition contains character or UCS-2 graphic column predicates, the sort sequence that is in effect when the query is run is applied to those predicates. See Sort sequences in SQL on page 50 for more information on sort sequence and selection.

Expressions in the WHERE Clause


An expression in a WHERE clause names or specifies something you want to compare to something else. Each expression, when evaluated by SQL, is a character string, date/time/timestamp, or a numeric value. The expressions you specify can be: v A column name names a column. For example:
... WHERE EMPNO = '000200'

EMPNO names a column that is defined as a 6-byte character value. Equality comparisons (that is, X = Y or X <> Y) can be performed on character data. Other types of comparisons can also be evaluated for character data. However, you cannot compare character strings to numbers. You also cannot perform arithmetic operations on character data (even though EMPNO is a character string that appears to be a number). You can add and subtract date/time values. v An expression identifies two values that are added (+), subtracted (), multiplied (*), divided (/), have exponentiation (**), or concatenated (CONCAT or ||) to result in a value. The operands of an expression can be: A constant (that is, a literal value) A column A host variable A value returned from a function A special register Another expression For example:
... WHERE INTEGER(PRENDATE - PRSTDATE) > 100

When the order of evaluation is not specified by parentheses, the expression is evaluated in the following order: 1. Prefix operators 2. Exponentiation
Chapter 3. Basic Concepts and Techniques

39

3. Multiplication, division, and concatenation 4. Addition and subtraction Operators on the same precedence level are applied from left to right. v A constant specifies a literal value for the expression. For example:
... WHERE 40000 < SALARY

SALARY names a column that is defined as an 9-digit packed decimal value (DECIMAL(9,2)). It is compared to the numeric constant 40000. v A host variable identifies a variable in an application program. For example:
... WHERE EMPNO = :EMP

v A special register identifies a special value generated by the database manager. For example:
... WHERE LASTNAME = USER

v The NULL value specifies the condition of having an unknown value.


... WHERE DUE_DATE IS NULL

A search condition need not be limited to two column names or constants separated by arithmetic or comparison operators. You can develop a complex search condition that specifies several predicates separated by AND and OR. No matter how complex the search condition, it supplies a TRUE or FALSE value when evaluated against a row. There is also an unknown truth value, which is effectively false. That is, if the value of a row is null, this null value is not returned as a result of a search because it is not less than, equal to, or greater than the value specified in the search condition. More complex search conditions and predicates are described in Performing complex search conditions on page 72. To fully understand the WHERE clause, you need to know how SQL evaluates search conditions and predicates, and compares the values of expressions. This topic is discussed in the SQL Reference book.

Comparison operators
SQL supports the following comparison operators:
= <> or = or != < > <= or > or !> > = or < or !< Equal to Not equal to Less than Greater than Less than or equal to (or not greater than) Greater than or equal to (or not less than)

NOT Keyword
You can precede a predicate with the NOT keyword to specify that you want the opposite of the predicates value (that is, TRUE if the predicate is FALSE, or vice versa). NOT applies only to the predicate it precedes, not to all predicates in the WHERE clause. For example, to indicate that you are interested in all employees except those working in department C01, you could say:
... WHERE NOT WORKDEPT = 'C01'

which is equivalent to:


... WHERE WORKDEPT <> 'C01'

40

DB2 UDB for AS/400 SQL Programming Concepts V4R5

The GROUP BY clause


Without a GROUP BY clause, the application of SQL column functions returns one row. When GROUP BY is used, the function is applied to each group, thereby returning as many rows as there are groups. The GROUP BY clause allows you to find the characteristics of groups of rows rather than individual rows. When you specify a GROUP BY clause, SQL divides the selected rows into groups such that the rows of each group have matching values in one or more columns or expressions. Next, SQL processes each group to produce a single-row result for the group. You can specify one or more columns or expressions in the GROUP BY clause to group the rows. The items you specify in the SELECT statement are properties of each group of rows, not properties of individual rows in a table or view. For example, the CORPDATA.EMPLOYEE table has several sets of rows, and each set consists of rows describing members of a specific department. To find the average salary of people in each department, you could issue:

The SQL statement:

Results in: fetch WORK-DEPT AVG-SALARY 1 2 ... A00 B01 ... 42833 41250 ...

RV2W551-1

The result is several rows, one for each department. Notes: 1. Grouping the rows does not mean ordering them. Grouping puts each selected row in a group, which SQL then processes to derive characteristics of the group. Ordering the rows puts all the rows in the results table in ascending or descending collating sequence. ( ORDER BY clause on page 43 describes how to do this.) 2. If there are null values in the column you specify in the GROUP BY clause, a single-row result is produced for the data in the rows with null values. 3. If the grouping occurs over character or UCS-2 graphic columns, the sort sequence in effect when the query is run is applied to the grouping. See Sort sequences in SQL on page 50 for more information on sort sequence and selection. When you use GROUP BY, you list the columns or expressions you want SQL to use to group the rows. For example, suppose you want a list of the number of people working on each major project described in the CORPDATA.PROJECT table. You could issue:

Chapter 3. Basic Concepts and Techniques

41

The SQL statement:

Results in: fetch SUM-PR 1 2 3 ... 6 5 10 ... MAJ-PROJ AD3100 AD3110 MA2100 ...

RV2W552-3

The result is a list of the companys current major projects and the number of people working on each project. You can also specify that you want the rows grouped by more than one column or expression. For example, you could issue a select-statement to find the average salary for men and women in each department, using the CORPDATA.EMPLOYEE table. To do this, you could issue:

The SQL statement:

Results in: fetch DEPT 1 2 3 4 ... A00 A00 B01 C01 ... SEX F M M F ... AVG-WAGES 52750 37875 41250 30156 ...

RV2W553-1

Because you did not include a WHERE clause in this example, SQL examines and process all rows in the CORPDATA.EMPLOYEE table. The rows are grouped first by department number and next (within each department) by sex before SQL derives the average SALARY value for each group.

HAVING clause
You can use the HAVING clause to specify a search condition for the groups selected based on a GROUP BY clause. The HAVING clause says that you want only those groups that satisfy the condition in that clause. Therefore, the search condition you specify in the HAVING clause must test properties of each group rather than properties of individual rows in the group. The HAVING clause follows the GROUP BY clause and can contain the same kind of search condition you can specify in a WHERE clause. In addition, you can specify column functions in a HAVING clause. For example, suppose you wanted to retrieve the average salary of women in each department. To do this, you would use the AVG column function and group the resulting rows by WORKDEPT and specify a WHERE clause of SEX = 'F'.

42

DB2 UDB for AS/400 SQL Programming Concepts V4R5

To specify that you want this data only when all the female employees in the selected department have an education level equal to or greater than 16 (a college graduate), use the HAVING clause. The HAVING clause tests a property of the group. In this case, the test is on MIN(EDLEVEL), which is a group property:

The SQL statement:

Results in: fetch DEPT 1 2 3 A00 C01 D11 AVG-WAGES 52750 30156 24476 MIN-EDUC 18 16 17

RV2W554-3

You can use multiple predicates in a HAVING clause by connecting them with AND and OR, and you can use NOT for any predicate of a search condition. Note: If you intend to update a column or delete a row, you cannot include a GROUP BY or HAVING clause in the SELECT statement within a DECLARE CURSOR statement. (The DECLARE CURSOR statement is described in Chapter 4. Using a Cursor on page 55.) Predicates with arguments that are not column functions can be coded in either WHERE or HAVING clauses. It is usually more efficient to code the selection criteria in the WHERE clause. It is processed during the initial phase of the query processing. The HAVING selection is performed in post processing of the result table. If the search condition contains predicates involving character or UCS-2 graphic columns, the sort sequence in effect when the query is run is applied to those predicates. See Sort sequences in SQL on page 50 for more information on sort sequence and selection.

ORDER BY clause
You can specify that you want selected rows retrieved in a particular order, sorted by ascending or descending collating sequence of a columns value, with the ORDER BY clause. You can use an ORDER BY clause as you would a GROUP BY clause: specify the columns or expressions you want SQL to use when retrieving the rows in a collated sequence. For example, to retrieve the names and department numbers of female employees listed in the alphanumeric order of their department numbers, you could use this select-statement:

Chapter 3. Basic Concepts and Techniques

43

The SQL statement:

Results in: fetch PGM-NAME3 1 2 3 4 5 6 7 8 9 10 11 12 13 HAAS KWAN QUINTANA NICHOLLS PIANKA SCOUTTEN LUTZ PULASKI JOHNSON PEREZ HENDERSON SCHNEIDER SETRIGHT DEPT A00 C01 C01 C01 D11 D11 D11 D21 D21 D21 E11 E11 E11
RV2W555-3

Notes: 1. All columns named in the ORDER BY clause must also be named in the SELECT list. 2. Null values are ordered as the highest value. To order by a column function, or something other than a column name, you can specify an AS clause in the select-list. To order by an expression, you can either specify the exact same expression in the ORDER BY clause, or you can specify an AS clause in the select-list. The AS clause names the result column. This name can be specified in the ORDER BY clause. To order by a name specified in the AS clause: v The name must be unique in the select-list. v The name must not be qualified. For example, to retrieve the full name of employees listed in alphabetic order, you could use this select-statement:
SELECT LASTNAME CONCAT FIRSTNAME AS FULLNAME ... ORDER BY FULLNAME

This select-statement could optionally be written as:


SELECT LASTNAME CONCAT FIRSTNAME ORDER BY LASTNAME CONCAT FIRSTNAME

Instead of naming the columns to order the results, you can use a number. For example, ORDER BY 3 specifies that you want the results ordered by the third column of the results table, as specified by the select-statement. Use a number to order the rows of the results table when the sequencing value is not a named column. You can also specify whether you want SQL to collate the rows in ascending (ASC) or descending (DESC) sequence. An ascending collating sequence is the default. In the above select-statement, SQL first returns the row with the lowest department

44

DB2 UDB for AS/400 SQL Programming Concepts V4R5

number (alphabetically and numerically), followed by rows with higher department numbers. To order the rows in descending collating sequence based on the department number, specify:
... ORDER BY WORKDEPT DESC

As with GROUP BY, you can specify a secondary ordering sequence (or several levels of ordering sequences) as well as a primary one. In the example above, you might want the rows ordered first by department number, and within each department, ordered by employee name. To do this, specify:
... ORDER BY WORKDEPT, LASTNAME

If character columns or UCS-2 graphic columns are used in the ORDER BY clause, ordering for these columns is based on the sort sequence in effect when the query is run. See Sort sequences in SQL on page 50 for more information on sort sequence and its affect on ordering.

Null Values to indicate absence of column values in a row


A null value indicates the absence of a column value in a row. A null value is not the same as zero or all blanks. A null value is the same as unknown. Null values can be used as a condition in the WHERE and HAVING clauses, and as a mathematical argument. For example, a WHERE clause can specify a column that, for some rows, contains a null value. Normally, a comparison predicate using a column that contains null values does not select a row that has a null value for the column. This is because a null value is neither less than, equal to, nor greater than the value specified in the condition. To select the values for all rows that contain a null value for the manager number, you could specify:
SELECT DEPTNO, DEPTNAME, ADMRDEPT FROM CORPDATA.DEPARTMENT WHERE MGRNO IS NULL

The result would be:


DEPTNO DEPTNAME D01 DEVELOPMENT CENTER ADMRDEPT A00

To get the rows that do not have a null value for the manager number, you could change the WHERE clause like this:
WHERE MGRNO IS NOT NULL

For more information on the use of null values, see the SQL Reference book.

Special registers in SQL statements


You can specify certain special registers in SQL statements. For locally run SQL statements, the special registers and their contents are shown in the following table:
Special Registers CURRENT DATE CURRENT_DATE Contents The current date.

Chapter 3. Basic Concepts and Techniques

45

Special Registers CURRENT TIME CURRENT_TIME CURRENT TIMESTAMP CURRENT_TIMESTAMP CURRENT TIMEZONE CURRENT_TIMEZONE

Contents The current time. The current date and time in timestamp format. A duration of time that links local time to Universal Coordinated Time (UTC) using the formula: local time - CURRENT TIMEZONE = UTC It is taken from the system value QUTCOFFSET.

CURRENT SERVER CURRENT_SERVER USER CURRENT PATH CURRENT_PATH CURRENT FUNCTION PATH

The name of the relational database as contained in the relational database directory table in the relational database directory. The run-time authorization identifier (user profile) of the job. The SQL path used to resolve unqualified data type names, procedure names, and function names.

If a single statement contains more than one reference to any of CURRENT DATE, CURRENT TIME, or CURRENT TIMESTAMP special registers, or the CURDATE, CURTIME, or NOW scalar functions, all values are based on a single clock reading. For remotely run SQL statements, the special registers and their contents are shown in the following table:
Special Registers CURRENT DATE CURRENT_DATE CURRENT TIME CURRENT_TIME CURRENT TIMESTAMP CURRENT_TIMESTAMP CURRENT TIMEZONE CURRENT_TIMEZONE CURRENT SERVER CURRENT_SERVER USER CURRENT PATH CURRENT_PATH CURRENT FUNCTION PATH Contents The current date and time at the remote system, not the local system.

A duration of time that links the remote system time to UTC. The name of the relational database as contained in the relational database directory table in the relational database directory. The run-time authorization identifier of the server job on the remote system. The current path value at the remote system.

When a query over a distributed table references a special register, the contents of the special register on the system that requests the query are used. For more information on distributed tables, see DB2 Multisystembook.

46

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Date, Time, and Timestamp data types


Date, time, and timestamp are data types represented in an internal form not seen by the SQL user. Date, time, and timestamp can be represented by character string values and assigned to character string variables. The database manager recognizes the following as date, time, and timestamp values: v A value returned by the DATE, TIME, or TIMESTAMP scalar functions. v A value returned by the CURRENT DATE, CURRENT TIME, or CURRENT TIMESTAMP special registers. v A character string when it is an operand of an arithmetic expression or a comparison and the other operand is a date, time, or timestamp. For example, in the predicate:
... WHERE HIREDATE < '1950-01-01'

if HIREDATE is a date column, the character string 1950-01-01 is interpreted as a date. v A character string variable or constant used to set a date, time, or timestamp column in either the SET clause of an UPDATE statement, or the VALUES clause of an INSERT statement. For more information on character string formats of date, time, and timestamp values, see Chapter 2 of the SQL Reference book .

Specifying current date and time values


You can specify a current date, time, or timestamp in an expression by specifying one of three special registers: CURRENT DATE, CURRENT TIME, or CURRENT TIMESTAMP. The value of each is based on a time-of-day clock reading obtained during the running of the statement. Multiple references to CURRENT DATE, CURRENT TIME, or CURRENT TIMESTAMP within the same SQL statement use the same value. The following statement returns the age (in years) of each employee in the EMPLOYEE table when the statement is run:
SELECT YEAR(CURRENT DATE - BIRTHDATE) FROM CORPDATA.EMPLOYEE

The CURRENT TIMEZONE special register allows a local time to be converted to Universal Coordinated Time (UTC). For example, if you have a table named DATETIME, containing a time column type with a name of STARTT, and you want to convert STARTT to UTC, you can use the following statement:
SELECT STARTT - CURRENT TIMEZONE FROM DATETIME

Date/Time arithmetic
Addition and subtraction are the only arithmetic operators applicable to date, time, and timestamp values. You can increment and decrement a date, time, or timestamp by a duration; or subtract a date from a date, a time from a time, or a timestamp from a timestamp. For a detailed description of date and time arithmetic, see Chapter 2 of the SQL Reference book.

Chapter 3. Basic Concepts and Techniques

47

Creating and using ALIAS names


When you refer to an existing table or view to an AS/400 physical file that consists of multiple members, you can avoid using file overrides by creating an alias. You can use the SQL CREATE ALIAS statement to do this. Or you can use Operations Navigator. You can create an alias for v A table or view v A member of a table A table alias defines a name for the file, including the specific member name. You can use this alias name in an SQL statement in the same way that you would use a table name. Unlike overrides, alias names are objects that exist until they are dropped. For example, if there is a multiple member file MYLIB.MYFILE with members MBR1 and MBR2, an alias can be created for the second member so that SQL can easily refer to it.
CREATE ALIAS MYLIB.MYMBR2_ALIAS FOR MYLIB.MYFILE (MBR2)

When alias MYLIB.MYMBR2_ALIAS is specified on the following insert statement, the values are inserted into member MBR2 in MYLIB.MYFILE.
INSERT INTO MYLIB.MYMBR2_ALIAS VALUES('ABC', 6)

Alias names can also be specified on DDL statements. Assume that alias MYLIB.MYALIAS exists and is an alias for table MYLIB.MYTABLE. The following DROP statement will drop table MYLIB.MYTABLE.
DROP TABLE MYLIB.MYALIAS

If you really want to drop the alias name instead, specify the ALIAS keyword on the drop statement:
DROP ALIAS MYLIB.MYALIAS

Creating descriptive labels using the LABEL ON statement


Sometimes the table name, column name, view name, alias name, or SQL package name does not clearly define data that is shown on an interactive display of the table. By using the LABEL ON statement, you can create a more descriptive label for the table name, column name, view name, alias name, or SQL package name. These labels can be seen in the SQL catalog in the LABEL column. The LABEL ON statement looks like this:
LABEL ON TABLE CORPDATA.DEPARTMENT IS 'Department Structure Table' LABEL ON COLUMN CORPDATA.DEPARTMENT.ADMRDEPT IS 'Reports to Dept.'

After these statements are run, the table named DEPARTMENT displays the text description as Department Structure Table and the column named ADMRDEPT displays the heading Reports to Dept. The label for tables, views, SQL packages, and

48

DB2 UDB for AS/400 SQL Programming Concepts V4R5

column text cannot be more than 50 characters and the label for column headings cannot be more than 60 characters (blanks included). The following are examples of LABEL ON statements: This LABEL ON statement provides column heading 1 and column heading 2.
*...+....1....+....2....+....3....+....4....+....5....+....6..* LABEL ON COLUMN CORPDATA.EMPLOYEE.EMPNO IS 'Employee Number'

This LABEL ON statement provides 3 levels of column headings for the SALARY column.
*...+....1....+....2....+....3....+....4....+....5....+....6..* LABEL ON COLUMN CORPDATA.EMPLOYEE.SALARY IS 'Yearly Salary (in dollars)'

This LABEL ON statement removes the column heading for SALARY.


*...+....1....+....2....+....3....+....4....+....5....+....6..* LABEL ON COLUMN CORPDATA.EMPLOYEE.SALARY IS ''

An example of a DBCS column heading with two levels specified.


*...+....1....+....2....+....3....+....4....+....5....+....6..* LABEL ON COLUMN CORPDATA.EMPLOYEE.SALARY IS '<AABBCCDD> <EEFFGG>'

This LABEL ON statement provides column text for the EDLEVEL column.
*...+....1....+....2....+....3....+....4....+....5....+....6..* LABEL ON COLUMN CORPDATA.EMPLOYEE.EDLEVEL TEXT IS 'Number of years of formal education'

For more information about the LABEL ON statement, see the SQL Reference book.

Describing an SQL object using COMMENT ON


After you create an SQL object such as a table, view, index, package, procedure, parameter, user-defined type, or function, you can supply information about it for future referral, such as the purpose of the object, who uses it, and anything unusual or special about it. You can also include similar information about each column of a table or view. Your comment must not be more than 2000 bytes. A comment is especially useful if your names do not clearly indicate the contents of the columns or objects. In that case, use a comment to describe the specific contents of the column or objects. An example of using COMMENT ON follows:
COMMENT ON TABLE CORPDATA.EMPLOYEE IS 'Employee table. Each row in this table represents one employee of the company.'

Getting comments after running a COMMENT ON statement


After running a COMMENT ON statement for a table, your comments are stored in the REMARKS column of SYSTABLES. Comments for the other objects are
Chapter 3. Basic Concepts and Techniques

49

stored in the REMARKS column of the appropriate catalog table. (If the indicated row had already contained a comment, the old comment is replaced by the new one.) The following example gets the comments added by the COMMENT ON statement in the previous example:
SELECT REMARKS FROM CORPDATA.SYSTABLES WHERE NAME = 'EMPLOYEE'

Sort sequences in SQL


A sort sequence defines how characters in a character set relate to each other when they are compared or ordered. For more information on sort sequences, see Chapter 1 in SQL Reference book. The sort sequence is used for all character and UCS-2 graphic comparisons performed in SQL statements. There are sort sequence tables for both single byte and double byte character data. Each single byte sort sequence table has an associated double byte sort sequence table, and vice versa. Conversion between the two tables is performed when necessary to implement a query. In addition, the CREATE INDEX statement has the sort sequence (in effect at the time the statement was run) applied to the character columns referred to in the index.

Sort sequence used with ORDER BY and record selection


To see how to use a sort sequence, run the examples in this section against the STAFF table shown in Table 2. Notice that the values in the JOB column are in mixed case. You can see the values 'Mgr', 'MGR', and 'mgr'.
Table 2. The STAFF Table ID 10 20 30 40 50 60 70 80 90 100 NAME Sanders Pernal Merenghi OBrien Hanes Quigley Rothman James Koonitz Plotz DEPT 20 20 38 38 15 38 15 20 42 42 JOB Mgr Sales MGR Sales Mgr SALES Sales Clerk sales mgr YEARS 7 8 5 6 10 0 7 0 6 6 SALARY 18357.50 18171.25 17506.75 18006.00 20659.80 16808.30 16502.83 13504.60 18001.75 18352.80 COMM 0 612.45 0 846.55 0 650.25 1152.00 128.20 1386.70 0

In the following examples, the results are shown for each statement using: v *HEX sort sequence v Shared-weight sort sequence using the language identifier ENU v Unique-weight sort sequence using the language identifier ENU Note: ENU is chosen as a language identifier by specifying either SRTSEQ(*LANGIDUNQ), or SRTSEQ(*LANGIDSHR) and LANGID(ENU), on the CRTSQLxxx, STRSQL, or RUNSQLSTM commands, or by using the SET OPTION statement.

50

DB2 UDB for AS/400 SQL Programming Concepts V4R5

ORDER BY
The following SQL statement causes the result table to be sorted using the values in the JOB column:
SELECT * FROM STAFF ORDER BY JOB

Table 3 shows the result table using a *HEX sort sequence. The rows are sorted based on the EBCDIC value in the JOB column. In this case, all lowercase letters sort before the uppercase letters.
Table 3. SELECT * FROM STAFF ORDER BY JOB Using the *HEX Sort Sequence. ID 100 90 80 10 50 30 20 40 70 60 NAME Plotz Koonitz James Sanders Hanes Merenghi Pernal OBrien Rothman Quigley DEPT 42 42 20 20 15 38 20 38 15 38 JOB mgr sales Clerk Mgr Mgr MGR Sales Sales Sales SALES YEARS 6 6 0 7 10 5 8 6 7 0 SALARY 18352.80 18001.75 13504.60 18357.50 20659.80 17506.75 18171.25 18006.00 16502.83 16808.30 COMM 0 1386.70 128.20 0 0 0 612.45 846.55 1152.00 650.25

Table 4 shows how sorting is done for a unique-weight sort sequence. After the sort sequence is applied to the values in the JOB column, the rows are sorted. Notice that after the sort, lowercase letters are before the same uppercase letters, and the values 'mgr', 'Mgr', and 'MGR' are adjacent to each other.
Table 4. SELECT * FROM STAFF ORDER BY JOB Using the Unique-Weight Sort Sequence for the ENU Language Identifier. ID 80 100 10 50 30 90 20 40 70 60 NAME James Plotz Sanders Hanes Merenghi Koonitz Pernal OBrien Rothman Quigley DEPT 20 42 20 15 38 42 20 38 15 38 JOB Clerk mgr Mgr Mgr MGR sales Sales Sales Sales SALES YEARS 0 6 7 10 5 6 8 6 7 0 SALARY 13504.60 18352.80 18357.50 20659.80 17506.75 18001.75 18171.25 18006.00 16502.83 16808.30 COMM 128.20 0 0 0 0 1386.70 612.45 846.55 1152.00 650.25

Table 5 on page 52 shows how sorting is done for a shared-weight sort sequence. After the sort sequence is applied to the values in the JOB column, the rows are sorted. For the sort comparison, each lowercase letter is treated the same as the corresponding uppercase letter. In Table 5 on page 52, notice that all the values 'MGR', 'mgr' and 'Mgr' are mixed together.

Chapter 3. Basic Concepts and Techniques

51

Table 5. SELECT * FROM STAFF ORDER BY JOB Using the Shared-Weight Sort Sequence for the ENU Language Identifier. ID 80 10 30 50 100 20 40 60 70 90 NAME James Sanders Merenghi Hanes Plotz Pernal OBrien Quigley Rothman Koonitz DEPT 20 20 38 15 42 20 38 38 15 42 JOB Clerk Mgr MGR Mgr mgr Sales Sales SALES Sales sales YEARS 0 7 5 10 6 8 6 0 7 6 SALARY 13504.60 18357.50 17506.75 20659.80 18352.80 18171.25 18006.00 16808.30 16502.83 18001.75 COMM 128.20 0 0 0 0 612.45 846.55 650.25 1152.00 1386.70

Record selection
The following SQL statement selects records with the value 'MGR' in the JOB column:
SELECT * FROM STAFF WHERE JOB='MGR'

Table 6 shows how record selection is done with a *HEX sort sequence. In Table 6, the rows that match the record selection criteria for the column 'JOB' are selected exactly as specified in the select statement. Only the uppercase 'MGR' is selected.
Table 6. SELECT * FROM STAFF WHERE JOB=MGR Using the *HEX Sort Sequence. ID 30 NAME Merenghi DEPT 38 JOB MGR YEARS 5 SALARY 17506.75 COMM 0

Table 7 shows how record selection is done with a unique-weight sort sequence. In Table 7, the lowercase and uppercase letters are treated as unique. The lowercase 'mgr' is not treated the same as uppercase 'MGR'. Therefore, the lower case 'mgr' is not selected.
Table 7. SELECT * FROM STAFF WHERE JOB = MGR Using Unique-Weight Sort Sequence for the ENU Language Identifier. ID 30 NAME Merenghi DEPT 38 JOB MGR YEARS 5 SALARY 17506.75 COMM 0

Table 8 shows how record selection is done with a shared-weight sort sequence. In Table 8, the rows that match the record selection criteria for the column 'JOB' are selected by treating uppercase letters the same as lowercase letters. Notice that in Table 8 all the values 'mgr', 'Mgr' and 'MGR' are selected.
Table 8. SELECT * FROM STAFF WHERE JOB = MGR Using the Shared-Weight Sort Sequence for the ENU Language Identifier. ID 10 30 50 NAME Sanders Merenghi Hanes DEPT 20 38 15 JOB Mgr MGR Mgr YEARS 7 5 10 SALARY 18357.50 17506.75 20659.80 COMM 0 0 0

52

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Table 8. SELECT * FROM STAFF WHERE JOB = MGR Using the Shared-Weight Sort Sequence for the ENU Language Identifier. (continued) ID 100 NAME Plotz DEPT 42 JOB mgr YEARS 6 SALARY 18352.80 COMM 0

Sort sequence and views


Views are created with the sort sequence that was in effect when the CREATE VIEW statement was run. When the view is referred to in a FROM clause, that sort sequence is used for any character comparisons in the subselect of the CREATE VIEW. At that time, an intermediate result table is produced from the view subselect. The sort sequence in effect when the query is being run is then applied to all the character and UCS-2 graphic comparisons (including those comparisons involving implicit conversions to character or UCS-2 graphic) specified in the query. The following SQL statements and tables show how views and sort sequences work. View V1, used in the following examples, was created with a shared-weight sort sequence of SRTSEQ(*LANGIDSHR) and LANGID(ENU). The CREATE VIEW statement would be as follows:
CREATE VIEW V1 AS SELECT * FROM STAFF WHERE JOB = 'MGR' AND ID < 100

Table 9 shows the result table from the view.


Table 9. SELECT * FROM V1 ID 10 30 50 NAME Sanders Merenghi Hanes DEPT 20 38 15 JOB Mgr MGR Mgr YEARS 7 5 10 SALARY 18357.50 17506.75 20659.80 COMM 0 0 0

Any queries run against view V1 are run against the result table shown in Table 9. The query shown below is run with a sort sequence of SRTSEQ(*LANGIDUNQ) and LANGID(ENU).
Table 10. SELECT * FROM V1 WHERE JOB = MGR Using the Unique-Weight Sort Sequence for Language Identifier ENU ID 30 NAME Merenghi DEPT 38 JOB MGR YEARS 5 SALARY 17506.75 COMM 0

Sort Sequence and the CREATE INDEX Statement


Indexes are created using the sort sequence that was in effect when the CREATE INDEX statement was run. An entry is added to the index every time an insert is made into the table over which the index is defined. Index entries contain the weighted value for character key and UCS-2 graphic key columns. The system gets the weighted value by converting the key value based on the sort sequence of the index. When selection is made using that sort sequence and that index, the character or UCS-2 graphic keys do not need to be converted prior to comparison. This improves the performance of the query.
Chapter 3. Basic Concepts and Techniques

53

Sort sequence and constraints


Unique constraints are implemented with indexes. If the table on which a unique constraint is added was defined with a sort sequence, the index will be created with that same sort sequence. If defining a referential constraint, the sort sequence between the parent and dependent table must match. For more information on sort sequence and constraints, see the Database Programming book. The sort sequence used at the time a check constraint is defined is the same sort sequence the system uses to validate adherence to the constraint at the time of an INSERT or UPDATE.

54

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Chapter 4. Using a Cursor


When SQL runs a select statement, the resulting rows comprise the result table. A cursor provides a way to access a result table. It is used within an SQL program to maintain a position in the result table. SQL uses a cursor to work with the rows in the result table and to make them available to your program. Your program can have several cursors, although each must have a unique name. Statements related to using a cursor include the following: v A DECLARE CURSOR statement to define and name the cursor and specify the rows to be retrieved with the embedded select statement. v OPEN and CLOSE statements to open and close the cursor for use within the program. The cursor must be opened before any rows can be retrieved. v A FETCH statement to retrieve rows from the cursors result table or to position the cursor on another row. v An UPDATE ... WHERE CURRENT OF statement to update the current row of a cursor. v A DELETE ... WHERE CURRENT OF statement to delete the current row of a cursor.

Types of cursors
SQL supports serial and scrollable cursors. The type of cursor determines the positioning methods which can be used with the cursor.

Serial cursor
A serial cursor is one defined without the SCROLL keyword. For a serial cursor, each row of the result table can be fetched only once per OPEN of the cursor. When the cursor is opened, it is positioned before the first row in the result table. When a FETCH is issued, the cursor is moved to the next row in the result table. That row is then the current row. If host variables are specified (with the INTO clause on the FETCH statement), SQL moves the current rows contents into your programs host variables. This sequence is repeated each time a FETCH statement is issued until the end-of-data (SQLCODE = 100) is reached. When you reach the end-of-data, close the cursor. You cannot access any rows in the result table after you reach the end-of-data. To use the cursor again, you must first close the cursor and then re-issue the OPEN statement. You can never back up.

Scrollable cursor
For a scrollable cursor, the rows of the result table can be fetched many times. The cursor is moved through the result table based on the position option specified on the FETCH statement. When the cursor is opened, it is positioned before the first row in the result table. When a FETCH is issued, the cursor is positioned to the row in the result table that is specified by the position option. That row is then the current row. If host variables are specified (with the INTO clause on the FETCH
Copyright IBM Corp. 2000

55

statement), SQL moves the current rows contents into your programs host variables. Host variables cannot be specified for the BEFORE and AFTER position options. This sequence is repeated each time a FETCH statement is issued. The cursor does not need to be closed when an end-of-data or beginning-of-data condition occurs. The position options enable the program to continue fetching rows from the table. The following scroll options are used to position the cursor when issuing a FETCH statement. These positions are relative to the current cursor location in the result table.
NEXT PRIOR FIRST LAST BEFORE AFTER CURRENT RELATIVE n Positions the cursor on the next row. This is the default if no position is specified. Positions the cursor on the previous row. Positions the cursor on the first row. Positions the cursor on the last row. Positions the cursor before the first row. Positions the cursor after the last row. Does not change the cursor position. Evaluates a host variable or integer n in relationship to the cursors current position. For example, if n is -1, the cursor is positioned on the previous row of the result table. If n is +3, the cursor is positioned three rows after the current row.

Example of using a cursor


Suppose your program examines data about people in department D11. The following examples show the SQL statements you would include in a program to define and use a serial and a scrollable cursor. These cursors can be used to obtain information about the department from the CORPDATA.EMPLOYEE table. For the serial cursor example, the program processes all of the rows from the table, updating the job for all members of department D11 and deleting the records of employees from the other departments.
Table 11. A Serial Cursor Example Serial Cursor SQL Statement EXEC SQL DECLARE THISEMP CURSOR FOR SELECT EMPNO, LASTNAME, WORKDEPT, JOB FROM CORPDATA.EMPLOYEE FOR UPDATE OF JOB END-EXEC. EXEC SQL OPEN THISEMP END-EXEC. EXEC SQL WHENEVER NOT FOUND GO TO CLOSE-THISEMP END-EXEC. Described in Section Step 1: Define the cursor on page 58.

Step 2: Open the cursor on page 59.

Step 3: Specify what to do when end-of-data is reached on page 59.

56

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Table 11. A Serial Cursor Example (continued) Serial Cursor SQL Statement EXEC SQL FETCH THISEMP INTO :EMP-NUM, :NAME2, :DEPT, :JOB-CODE END-EXEC. ... for all employees in department D11, update the JOB value: EXEC SQL UPDATE CORPDATA.EMPLOYEE SET JOB = :NEW-CODE WHERE CURRENT OF THISEMP END-EXEC. ... then print the row. ... for other employees, delete the row: EXEC SQL DELETE FROM CORPDATA.EMPLOYEE WHERE CURRENT OF THISEMP END-EXEC. Branch back to fetch and process the next row. CLOSE-THISEMP. EXEC SQL CLOSE THISEMP END-EXEC. Step 6: Close the cursor on page 62. Step 5b: Delete the current row on page 61. Described in Section Step 4: Retrieve a row using a cursor on page 60.

Step 5a: Update the current row on page 61.

For the scrollable cursor example, the program uses the RELATIVE position option to obtain a representative sample of salaries from department D11.
Table 12. Scrollable Cursor Example Scrollable Cursor SQL Statement Described in Section

Step 1: Define the cursor on page 58. EXEC SQL DECLARE THISEMP DYNAMIC SCROLL CURSOR FOR SELECT EMPNO, LASTNAME, SALARY FROM CORPDATA.EMPLOYEE WHERE WORKDEPT = D11 END-EXEC. EXEC SQL OPEN THISEMP END-EXEC. EXEC SQL WHENEVER NOT FOUND GO TO CLOSE-THISEMP END-EXEC. Step 2: Open the cursor on page 59.

Step 3: Specify what to do when end-of-data is reached on page 59.

Chapter 4. Using a Cursor

57

Table 12. Scrollable Cursor Example (continued) Scrollable Cursor SQL Statement ...initialize program summation salary variable EXEC SQL FETCH RELATIVE 3 FROM THISEMP INTO :EMP-NUM, :NAME2, :JOB-CODE END-EXEC. ...add the current salary to program summation salary ...branch back to fetch and process the next row. ...calculate the average salary CLOSE-THISEMP. EXEC SQL CLOSE THISEMP END-EXEC. Step 6: Close the cursor on page 62. Described in Section Step 4: Retrieve a row using a cursor on page 60.

Step 1: Define the cursor


To define a result table to be accessed with a cursor, use the DECLARE CURSOR statement. The DECLARE CURSOR statement names a cursor and specifies a select-statement. The select-statement defines a set of rows that, conceptually, make up the result table. For a serial cursor, the statement looks like this (the FOR UPDATE OF clause is optional):
EXEC SQL DECLARE cursor-name CURSOR FOR SELECT column-1, column-2 ,... FROM table-name , ... FOR UPDATE OF column-2 ,... END-EXEC.

For a scrollable cursor, the statement looks like this (the WHERE clause is optional):
EXEC SQL DECLARE cursor-name DYNAMIC SCROLL CURSOR FOR SELECT column-1, column-2 ,... FROM table-name ,... WHERE column-1 = expression ... END-EXEC.

The select-statements shown here are rather simple. However, you can code several other types of clauses in a select-statement within a DECLARE CURSOR statement for a serial and a scrollable cursor. If you intend to update any columns in any or all of the rows of the identified table (the table named in the FROM clause), include the FOR UPDATE OF clause. It names each column you intend to update. If you do not specify the names of columns, and you specify either the ORDER BY clause or FOR READ ONLY clause, a negative SQLCODE is returned if an update is attempted. If you do not

58

DB2 UDB for AS/400 SQL Programming Concepts V4R5

specify the FOR UPDATE OF clause, the FOR READ ONLY clause, or the ORDER BY clause, and the result table is not read-only, you can update any of the columns of the specified table. You can update a column of the identified table even though it is not part of the result table. In this case, you do not need to name the column in the SELECT statement. When the cursor retrieves a row (using FETCH) that contains a column value you want to update, you can use UPDATE ... WHERE CURRENT OF to update the row. For example, assume that each row of the result table includes the EMPNO, LASTNAME, and WORKDEPT columns from the CORPDATA.EMPLOYEE table. If you want to update the JOB column (one of the columns in each row of the CORPDATA.EMPLOYEE table), the DECLARE CURSOR statement should include FOR UPDATE OF JOB ... even though JOB is omitted from the SELECT statement. The result table and cursor are read-only if any of the following are true: v The first FROM clause identifies more than one table or view. v The first FROM clause identifies a read-only view. v The first SELECT clause specifies the keyword DISTINCT. v The outer subselect contains a GROUP BY clause. v The outer subselect contains a HAVING clause. v The first SELECT clause contains a column function. v The select-statement contains a subquery such that the base object of the outer subselect and of the subquery is the same table. v The select-statement contains a UNION or UNION ALL operator. v The select-statement contains an ORDER BY clause, and the FOR UPDATE OF clause and DYNAMIC SCROLL are not specified. v The select-statement includes a FOR READ ONLY clause. v The SCROLL keyword is specified without DYNAMIC. v The select-list includes a DataLink column and a FOR UPDATE OF clause is not specified.

Step 2: Open the cursor


To begin processing the rows of the result table, issue the OPEN statement. When your program issues the OPEN statement, SQL processes the select-statement within the DECLARE CURSOR statement to identify a set of rows, called a result table 3, using the current value of any host variables specified in the select-statement. The OPEN statement looks like this:
EXEC SQL OPEN cursor-name END-EXEC.

Step 3: Specify what to do when end-of-data is reached


To find out when the end of the result table is reached, test the SQLCODE field for a value of 100 or test the SQLSTATE field for a value of '02000' (that is,

3. A result table can contain zero, one, or many rows, depending on the extent to which the search condition is satisfied. Chapter 4. Using a Cursor

59

end-of-data). This condition occurs when the FETCH statement has retrieved the last row in the result table and your program issues a subsequent FETCH. For example:
... IF SQLCODE =100 GO TO DATA-NOT-FOUND. or IF SQLSTATE ='02000' GO TO DATA-NOT-FOUND.

An alternative to this technique is to code the WHENEVER statement. Using WHENEVER NOT FOUND can result in a branch to another part of your program, where a CLOSE statement is issued. The WHENEVER statement looks like this:
EXEC SQL WHENEVER NOT FOUND GO TO symbolic-address END-EXEC.

Your program should anticipate an end-of-data condition whenever a cursor is used to fetch a row, and should be prepared to handle this situation when it occurs. When you are using a serial cursor and the end-of-data is reached, every subsequent FETCH statement returns the end-of-data condition. You cannot position the cursor on rows that are already processed. The CLOSE statement is the only operation that can be performed on the cursor. When you are using a scrollable cursor and the end-of-data is reached, the result table can still process more data. You can position the cursor anywhere in the result table using a combination of the position options. You do not need to CLOSE the cursor when the end-of-data is reached.

Step 4: Retrieve a row using a cursor


To move the contents of a selected row into your programs host variables, use the FETCH statement. The SELECT statement within the DECLARE CURSOR statement identifies rows that contain the column values your program wants. However, SQL does not retrieve any data for your application program until the FETCH statement is issued. When your program issues the FETCH statement, SQL uses the current cursor position as a starting point to locate the requested row in the result table. This changes that row to the current row. If an INTO clause was specified, SQL moves the current rows contents into your programs host variables. This sequence is repeated each time the FETCH statement is issued. SQL maintains the position of the current row (that is, the cursor points to the current row) until the next FETCH statement for the cursor is issued. The UPDATE statement does not change the position of the current row within the result table, although the DELETE statement does. The serial cursor FETCH statement looks like this:
EXEC SQL FETCH cursor-name INTO :host variable-1[, :host variable-2] ... END-EXEC.

60

DB2 UDB for AS/400 SQL Programming Concepts V4R5

The scrollable cursor FETCH statement looks like this:


EXEC SQL FETCH RELATIVE integer FROM cursor-name INTO :host variable-1[, :host variable-2] ... END-EXEC.

Step 5a: Update the current row


When your program has positioned the cursor on a row, you can update its data by using the UPDATE statement with the WHERE CURRENT OF clause. The WHERE CURRENT OF clause specifies a cursor that points to the row you want to update. The UPDATE ... WHERE CURRENT OF statement looks like this:
EXEC SQL UPDATE table-name SET column-1 = value [, column-2 = value] ... WHERE CURRENT OF cursor-name END-EXEC.

When used with a cursor, the UPDATE statement: v Updates only one rowthe current row v Identifies a cursor that points to the row to be updated v Requires that the columns updated be named previously in the FOR UPDATE OF clause of the DECLARE CURSOR statement, if an ORDER BY clause was also specified After you update a row, the cursors position remains on that row (that is, the current row of the cursor does not change) until you issue a FETCH statement for the next row.

Step 5b: Delete the current row


When your program has retrieved the current row, you can delete the row by using the DELETE statement. To do this, you issue a DELETE statement designed for use with a cursor; the WHERE CURRENT OF clause specifies a cursor that points to the row you want to delete. The DELETE ... WHERE CURRENT OF statement looks like this:
EXEC SQL DELETE FROM table-name WHERE CURRENT OF cursor-name END-EXEC.

When used with a cursor, the DELETE statement: v Deletes only one rowthe current row v Uses the WHERE CURRENT OF clause to identify a cursor that points to the row to be deleted After you delete a row, you cannot update or delete another row using that cursor until you issue a FETCH statement to position the cursor. Removing rows from a table using the DELETE statement on page 34 shows you how to use the DELETE statement to delete all rows that meet a specific search condition. You can also use the FETCH and DELETE ... WHERE CURRENT OF statements when you want to obtain a copy of the row, examine it, then delete it.

Chapter 4. Using a Cursor

61

Step 6: Close the cursor


If you processed the rows of a result table for a serial cursor, and you want to use the cursor again, issue a CLOSE statement to close the cursor prior to re-opening it.
EXEC SQL CLOSE cursor-name END-EXEC.

If you processed the rows of a result table and you do not want to use the cursor again, you can let the system close the cursor. The system automatically closes the cursor when: v A COMMIT without HOLD statement is issued and the cursor is not declared using the WITH HOLD clause. v A ROLLBACK without HOLD statement is issued. v The job ends. v The activation group ends and CLOSQLCSR(*ENDACTGRP) was specified on the precompile. v The first SQL program in the call stack ends and neither CLOSQLCSR(*ENDJOB) or CLOSQLCSR(*ENDACTGRP) was specified when the program was precompiled. v The connection to the application server is ended using the DISCONNECT statement. v The connection to the application server was released and a successful COMMIT occurred. v An *RUW CONNECT occurred. Because an open cursor still holds locks on referred-to-tables or views, you should explicitly close any open cursors as soon as they are no longer needed.

Using the multiple-row FETCH statement


The multiple-row FETCH statement can be used to retrieve multiple rows from a table or view with a single FETCH. The program controls the blocking of rows by the number of rows requested on the FETCH statement (OVRDBF has no effect). The maximum number of rows that can be requested on a single fetch call is 32767. Once the data is retrieved, the cursor is positioned on the last row retrieved. There are two ways to define the storage where fetched rows are placed: a host structure array or a row storage area with an associated descriptor. Both methods can be coded in all of the languages supported by the SQL precompilers, with the exception of the host structure array in REXX. Refer to the SQL Programming with Host Languages information for details on the programming languages. Both forms of the multiple-row FETCH statement allow the application to code a separate indicator array. The indicator array should contain one indicator for each host variable that is null capable. The multiple-row FETCH statement can be used with both serial and scrollable cursors. The operations used to define, open, and close a cursor for a multiple-row FETCH remain the same. Only the FETCH statement changes to specify the number of rows to retrieve and the storage where the rows are placed.

62

DB2 UDB for AS/400 SQL Programming Concepts V4R5

After each multiple-row FETCH, information is returned to the program through the SQLCA. In addition to the SQLCODE and SQLSTATE fields, the SQLERRD provides the following information: v SQLERRD3 contains the number of rows retrieved on the multiple-row FETCH statement. If SQLERRD3 is less than the number of rows requested, then an error or end-of-data condition occurred. v SQLERRD4 contains the length of each row retrieved. v SQLERRD5 contains an indication that the last row in the table was fetched. It can be used to detect the end-of-data condition in the table being fetched when the cursor does not have immediate sensitivity to updates. Cursors which do have immediate sensitivity to updates should continue fetching until an SQLCODE +100 is received to detect an end-of-data condition.

Multiple-row FETCH using a host structure array


To use the multiple-row FETCH with the host structure array, the application must define a host structure array that can be used by SQL. Each language has its own conventions and rules for defining a host structure array. Host structure arrays can be defined by using variable declarations or by using compiler directives to retrieve External File Descriptions (such as the COBOL COPY directive). The host structure array consists of an array of structures. Each structure corresponds to one row of the result table. The first structure in the array corresponds to the first row, the second structure in the array corresponds to the second row, and so on. SQL determines the attributes of elementary items in the host structure array based on the declaration of the host structure array. To maximize performance, the attributes of the items that make up the host structure array should match the attributes of the columns being retrieved. Consider the following COBOL example:
EXEC SQL INCLUDE SQLCA END-EXEC. ... 01 TABLE-1. 02 DEPT OCCURS 10 TIMES. 05 EMPNO PIC X(6). 05 LASTNAME. 49 LASTNAME-LEN PIC S9(4) BINARY. 49 LASTNAME-TEXT PIC X(15). 05 WORKDEPT PIC X(3). 05 JOB PIC X(8). 01 TABLE-2. 02 IND-ARRAY OCCURS 10 TIMES. 05 INDS PIC S9(4) BINARY OCCURS 4 TIMES. ... EXEC SQL DECLARE D11 CURSOR FOR SELECT EMPNO, LASTNAME, WORKDEPT, JOB FROM CORPDATA.EMPLOYEE WHERE WORKDEPT = "D11" END-EXEC.

... EXEC SQL OPEN D11


Chapter 4. Using a Cursor

63

END-EXEC. PERFORM FETCH-PARA UNTIL SQLCODE NOT EQUAL TO ZERO. ALL-DONE. EXEC SQL CLOSE D11 END-EXEC. ... FETCH-PARA. EXEC SQL WHENEVER NOT FOUND GO TO ALL-DONE END-EXEC. EXEC SQL FETCH D11 FOR 10 ROWS INTO :DEPT :IND-ARRAY END-EXEC. ...

In this example, a cursor was defined for the CORPDATA.EMPLOYEE table to select all rows where the WORKDEPT column equals 'D11'. The result table contains eight rows. The DECLARE CURSOR and OPEN statements do not have any special syntax when they are used with a multiple-row FETCH statement. Another FETCH statement that returns a single row against the same cursor can be coded elsewhere in the program. The multiple-row FETCH statement is used to retrieve all of the rows in the result table. Following the FETCH, the cursor position remains on the last row retrieved. The host structure array DEPT and the associated indicator array IND-ARRAY are defined in the application. Both arrays have a dimension of ten. The indicator array has an entry for each column in the result table. The attributes of type and length of the DEPT host structure array elementary items match the columns that are being retrieved. When the multiple-row FETCH statement has successfully completed, the host structure array contains the data for all eight rows. The indicator array, IND_ARRAY, contains zeros for every column in every row because no NULL values were returned. The SQLCA that is returned to the application contains the following information: v SQLCODE contains 0 v SQLSTATE contains '00000' v SQLERRD3 contains 8, the number of rows fetched v SQLERRD4 contains 34, the length of each row v SQLERRD5 contains +100, indicating the last row in the result table is in the block See Appendix B of the SQL Reference book for a description of the SQLCA.

Multiple-row FETCH using a row storage area


The application must define a row storage area and an associated description area before the application can use a multiple-row FETCH with a row storage area. The row storage area is a host variable defined in the application program. The row storage area contains the results of the multiple-row FETCH. A row storage area can be a character variable with enough bytes to hold all of the rows requested on the multiple-row FETCH. An SQLDA that contains the SQLTYPE and SQLLEN for each returned column is defined by the associated descriptor used on the row storage area form of the

64

DB2 UDB for AS/400 SQL Programming Concepts V4R5

multiple-row FETCH. The information provided in the descriptor determines the data mapping from the database to the row storage area. To maximize performance, the attribute information in the descriptor should match the attributes of the columns retrieved. See Appendix C of the SQL Reference book for a description of the SQLDA. Consider the following PL/I example:
*....+....1....+....2....+....3....+....4....+....5....+....6....+....7...* EXEC SQL INCLUDE SQLCA; EXEC SQL INCLUDE SQLDA; ... DCL DEPTPTR PTR; DCL 1 DEPT(10) BASED(DEPTPTR), 3 EMPNO CHAR(6), 3 LASTNAME CHAR(15) VARYING, 3 WORKDEPT CHAR(3), 3 JOB CHAR(8); DCL I BIN(31) FIXED; DEC J BIN(31) FIXED; DCL ROWAREA CHAR(2000); ... ALLOCATE SQLDA SET(SQLDAPTR); EXEC SQL DECLARE D11 CURSOR FOR SELECT EMPNO, LASTNAME, WORKDEPT, JOB FROM CORPDATA.EMPLOYEE WHERE WORKDEPT = 'D11';

Figure 1. Example of Multiple-Row FETCH Using a Row Storage Area (Part 1 of 2)

Chapter 4. Using a Cursor

65

... EXEC SQL OPEN D11; /* SET UP THE DESCRIPTOR FOR THE MULTIPLE-ROW FETCH */ /* 4 COLUMNS ARE BEING FETCHED */ SQLD = 4; SQLN = 4; SQLDABC = 366; SQLTYPE(1) = 452; /* FIXED LENGTH CHARACTER - */ /* NOT NULLABLE */ SQLLEN(1) = 6; SQLTYPE(2) = 456; /*VARYING LENGTH CHARACTER */ /* NOT NULLABLE */ SQLLEN(2) = 15; SQLTYPE(3) = 452; /* FIXED LENGTH CHARACTER - */ SQLLEN(3) = 3; SQLTYPE(4) = 452; /* FIXED LENGTH CHARACTER - */ /* NOT NULLABLE */ SQLLEN(4) = 8; /*ISSUE THE MULTIPLE-ROW FETCH STATEMENT TO RETRIEVE*/ /*THE DATA INTO THE DEPT ROW STORAGE AREA */ /*USE A HOST VARIABLE TO CONTAIN THE COUNT OF */ /*ROWS TO BE RETURNED ON THE MULTIPLE-ROW FETCH */ J = 10; /*REQUESTS 10 ROWS ON THE FETCH */ ... EXEC SQL WHENEVER NOT FOUND GOTO FINISHED; EXEC SQL WHENEVER SQLERROR GOTO FINISHED; EXEC SQL FETCH D11 FOR :J ROWS USING DESCRIPTOR :SQLDA INTO :ROWAREA; /* ADDRESS THE ROWS RETURNED */ DEPTPTR = ADDR(ROWAREA); /*PROCESS EACH ROW RETURNED IN THE ROW STORAGE */ /*AREA BASED ON THE COUNT OF RECORDS RETURNED */ /*IN SQLERRD3. */ DO I = 1 TO SQLERRD(3); IF EMPNO(I) = '000170' THEN DO; : END; END; IF SQLERRD(5) = 100 THEN DO; /* PROCESS END OF FILE */ END; FINISHED:

Figure 1. Example of Multiple-Row FETCH Using a Row Storage Area (Part 2 of 2)

In this example, a cursor has been defined for the CORPDATA.EMPLOYEE table to select all rows where the WORKDEPT column equal 'D11'. The sample EMPLOYEE table in Appendix A. DB2 UDB for AS/400 Sample Tables shows the result table contains eight rows. The DECLARE CURSOR and OPEN statements do not have special syntax when they are used with a multiple-row FETCH statement. Another FETCH statement that returns a single row against the same cursor can be coded

66

DB2 UDB for AS/400 SQL Programming Concepts V4R5

elsewhere in the program. The multiple-row FETCH statement is used to retrieve all rows in the result table. Following the FETCH, the cursor position remains on the eighth record in the block. The row area, ROWAREA, is defined as a character array. The data from the result table is placed in the host variable. In this example, a pointer variable is assigned to the address of ROWAREA. Each item in the rows that are returned is examined and used with the based structure DEPT. The attributes (type and length) of the items in the descriptor match the columns that are retrieved. In this case, no indicator area is provided. After the FETCH statement is completed, the ROWAREA contains eight rows. The SQLCA that is returned to the application contains the following: v SQLCODE contains 0 v SQLSTATE contains '00000' v SQLERRD3 contains 8, the number of rows returned v SQLERRD4 contains 34, for the length of the row fetched v SQLERRD5 contains +100, indicating the last row in the result table was fetched In this example, the application has taken advantage of the fact that SQLERRD5 contains an indication of the end of the file being reached. As a result, the application does not need to call SQL again to attempt to retrieve more rows. If the cursor has immediate sensitivity to inserts, you should call SQL in case any records were added. Cursors have immediate sensitivity when the commitment control level is something other than *RR.

Unit of work and open cursors


When your program completes a unit of work, it should commit or rollback the changes you made. Unless you specified HOLD on the COMMIT or ROLLBACK statement, all open cursors are automatically closed by SQL. Cursors that are declared with the WITH HOLD clause are not automatically closed on COMMIT. They are automatically closed on a ROLLBACK (the WITH HOLD clause specified on the DECLARE CURSOR statement is ignored). If you want to continue processing from the current cursor position after a COMMIT or ROLLBACK, you must specify COMMIT HOLD or ROLLBACK HOLD. When HOLD is specified, any open cursors are left open and keep their cursor position so processing can resume. On a COMMIT statement, the cursor position is maintained. On a ROLLBACK statement, the cursor position is restored to just after the last row retrieved from the previous unit of work. All record locks are still released. After issuing a COMMIT or ROLLBACK statement without HOLD, all locks are released and all cursors are closed. You can open the cursor again, but you will begin processing at the first row of the result table. Note: Specification of the ALWBLK(*ALLREAD) parameter of the CRTSQLxxx commands can change the restoration of the cursor position for read-only cursors. See Chapter 10. Dynamic SQL Applications for information on the use of the ALWBLK parameter and other performance related options on the CRTSQLxxx commands.

Chapter 4. Using a Cursor

67

68

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Chapter 5. Advanced Coding Techniques


This chapter covers the more advanced SQL coding techniques. The topics included in this chapter are: v inserting rows v updating rows v preventing duplicate rows v searching v joining v using UNION v v v v using using using using subqueries views indexes the system catalog

Advanced insert techniques


The next two sections cover two advanced techniques on how to insert rows into a table. The first section Inserting rows into a table using a Select-Statement discusses how to insert more than one row at a time using a select statement. The second section Inserting multiple rows in a table with the blocked INSERT statement discusses how to insert multiple rows that are in a host structure array. The second method can be used with all languages except REXX.

Inserting rows into a table using a Select-Statement


You can use a select-statement within an INSERT statement to insert zero, one, or more rows selected from the table or view you specify into another table. The table you select the rows from can be the same table you are inserting into. If they are the same table, SQL will create a temporary result table containing the selected rows and then insert from the temporary table into the target table. One use for this kind of INSERT statement is to move data into a table you created for summary data. For example, suppose you want a table that shows each employees time commitments to projects. You could create a table called EMPTIME with the columns EMPNUMBER, PROJNUMBER, STARTDATE, ENDDATE, and TTIME, and then use the following INSERT statement to fill the table:
INSERT INTO CORPDATA.EMPTIME (EMPNUMBER, PROJNUMBER, STARTDATE, ENDDATE) SELECT EMPNO, PROJNO, EMSTDATE, EMENDATE FROM CORPDATA.EMP_ACT

The select-statement embedded in the INSERT statement is no different from the select-statement you use to retrieve data. With the exception of FOR READ ONLY, FOR UPDATE OF, or the OPTIMIZE clause, you can use all the keywords, column functions, and techniques used to retrieve data. SQL inserts all the rows that meet the search conditions into the table you specify. Inserting rows from one table into another table does not affect any existing rows in either the source table or the target table.
Copyright IBM Corp. 2000

69

Notes on multiple-row Iinsertion


You should consider the following when inserting multiple rows into a table: v The number of columns implicitly or explicitly listed in the INSERT statement must equal the number of columns listed in the select-statement. v The data in the columns you are selecting must be compatible with the columns you are inserting into when using the INSERT with select-statement. v In the event the select-statement embedded in the INSERT returns no rows, an SQLCODE of 100 is returned to alert you that no rows were inserted. If you successfully insert rows, the SQLERRD(3) field of the SQLCA has an integer representing the number of rows SQL actually inserted. v If SQL finds an error while running the INSERT statement, SQL stops the operation. If you specify COMMIT (*CHG), COMMIT(*CS), COMMIT (*ALL), or COMMIT(*RR), nothing is inserted into the table and a negative SQLCODE is returned. If you specify COMMIT(*NONE), any rows inserted prior to the error remain in the table. v You can join two or more tables with a select-statement in an INSERT statement. Loaded in this manner, the table can be operated on with UPDATE, DELETE, and INSERT statements, because the rows exist as physically stored rows in a table.

Inserting multiple rows in a table with the blocked INSERT statement


A blocked INSERT can be used to insert multiple rows into a table with a single statement. The blocked INSERT statement is supported in all of the languages except REXX. The data inserted into the table must be in a host structure array. If indicator variables are used with a blocked INSERT, they must also be in a host structure array. For information on host structure arrays for a particular language, refer to the chapter on that language. For example, to add ten employees to the CORPDATA.EMPLOYEE table:
INSERT INTO CORPDATA.EMPLOYEE (EMPNO,FIRSTNME,MIDINIT,LASTNAME,WORKDEPT) 10 ROWS VALUES(:DSTRUCT:ISTRUCT)

DSTRUCT is a host structure array with five elements that is declared in the program. The five elements correspond to EMPNO, FIRSTNME, MIDINIT, LASTNAME, and WORKDEPT. DSTRUCT has a dimension of at least ten to accommodate inserting ten rows. ISTRUCT is a host structure array that is declared in the program. ISTRUCT has a dimension of at least ten small integer fields for the indicators. Blocked INSERT statements are supported for non-distributed SQL applications and for distributed applications where both the application server and the application requester are AS/400 systems.

Advanced update techniques


The SET clause of an UPDATE statement can be used in many ways to determine the actual values to be set in each row being updated. The following example lists each column with its corresponding value:

70

DB2 UDB for AS/400 SQL Programming Concepts V4R5

UPDATE EMPLOYEE SET WORKDEPT = 'D11', PHONENO = '7213', JOB = 'DESIGNER' WHERE EMPNO = '000270'

The previous update can also be written by specifying all of the columns and then all of the values:
UPDATE EMPLOYEE SET (WORKDEPT, PHONENO, JOB) = ('D11', '7213', 'DESIGNER') WHERE EMPNO = '000270'

Another way to select a value (or multiple values) for an update is to use a scalar-subselect. The scalar-subselect allows you to update one or more columns by setting them to one or more values selected from another table. In the following example, an employee moves to a different department but continues working on the same projects. The employee table has already been updated to contain the new department number. Now the project table needs to be updated to reflect the new department number of this employee (employee number is 000030).
UPDATE PROJECT SET DEPTNO = (SELECT WORKDEPT FROM EMPLOYEE WHERE PROJECT.RESPEMP = EMPLOYEE.EMPNO) WHERE RESPEMP='000030'

This same technique could be used to update a list of columns with multiple values returned from a single select. It is also possible to update an entire row in one table with values from a row in another table. Suppose there is a master class schedule table that needs to be udpated with changes that have been made in a copy of the table. The changes are made to the work copy and merged into the master table every night. The two tables have exactly the same columns and one column, CLASS_CODE, is a unique key column.
UPDATE CL_SCHED SET ROW = (SELECT * FROM MYCOPY WHERE CL_SCHED.CLASS_CODE = MYCOPY.CLASS_CODE)

This update will update all of the rows in CL_SCHED with the values from MYCOPY.

Preventing duplicate rows


When SQL evaluates a select-statement, several rows might qualify to be in the result table, depending on the number of rows that satisfy the select-statements search condition. Some of the rows in the result table might be duplicates. You can specify that you do not want any duplicates by using the DISTINCT keyword, followed by the list of column names:
SELECT DISTINCT JOB, SEX ...

DISTINCT means you want to select only the unique rows. If a selected row duplicates another row in the result table, the duplicate row is ignored (it is not put into the result table). For example, suppose you want a list of employee job
Chapter 5. Advanced Coding Techniques

71

codes. You do not need to know which employee has what job code. Because it is probable that several people in a department have the same job code, you can use DISTINCT to ensure that the result table has only unique values. The following example shows how to do this:
DECLARE XMP2 CURSOR FOR SELECT DISTINCT JOB FROM CORPDATA.EMPLOYEE WHERE WORKDEPT = :JOB-DEPT ... FETCH XMP2 INTO :JOB

The result is two rows (in this example, JOB-DEPT is set to D11).
fetch 1 JOB Designer
RV2W557-2

If you do not include DISTINCT in a SELECT clause, you might find duplicate rows in your result, because SQL retrieves the JOB columns value for each row that satisfies the search condition. Null values are treated as duplicate rows for DISTINCT. If you include DISTINCT in a SELECT clause and you also include a shared-weight sort sequence, fewer values are returned. The sort sequence causes values that contain the same characters to be weighted the same. If 'MGR', 'Mgr', and 'mgr' were all in the same table, only one of these values would be returned.

Performing complex search conditions


The following section explains more advanced things you can do with search conditions.

Keywords for use in search conditions


A search condition can contain any of the keywords BETWEEN, IN, IS NULL, and LIKE. Note: Constants are shown in the following examples to keep the examples simple. However, you could just as easily code host variables instead. Remember to precede each host variable with a colon. For character and UCS-2 graphic column predicates, the sort sequence is applied to the operands before evaluation of the predicates for BETWEEN, IN, EXISTS, and LIKE clauses. See Sort sequences in SQL on page 50 for more information on the using sort sequence with selection. v BETWEEN ... AND ... is used to specify a search condition that is satisfied by any value that falls on or between two other values. For example, to find all employees who were hired in 1987, you could use this:
... WHERE HIREDATE BETWEEN '1987-01-01' AND '1987-12-31'

The BETWEEN keyword is inclusive. A more complex, but explicit, search condition that produces the same result is:
... WHERE HIREDATE >= '1987-01-01' AND HIREDATE <= '1987-12-31'

72

DB2 UDB for AS/400 SQL Programming Concepts V4R5

v IN says you are interested in rows in which the value of the specified expression is among the values you listed. For example, to find the names of all employees in departments A00, C01, and E21, you could specify:
... WHERE WORKDEPT IN ('A00', 'C01', 'E21')

v LIKE says you are interested in rows in which a column value is similar to the value you supply. When you use LIKE, SQL searches for a character string similar to the one you specify. The degree of similarity is determined by two special characters used in the string that you include in the search condition: _ % An underline character stands for any single character. A percent sign stands for an unknown string of 0 or more characters. If the percent sign starts the search string, then SQL allows 0 or more character(s) to precede the matching value in the column. Otherwise, the search string must begin in the first position of the column.

Note: If you are operating on MIXED data, the following distinction applies: an SBCS underline character refers to one SBCS character. No such restriction applies to the percent sign; that is, a percent sign refers to any number of SBCS or DBCS characters. See theSQL Reference book for more information on the LIKE predicate and MIXED data. Use the underline character or percent sign either when you do not know or do not care about all the characters of the columns value. For example, to find out which employees live in Minneapolis, you could specify:
... WHERE ADDRESS LIKE '%MINNEAPOLIS%'

In this case, you should be sure that MINNEAPOLIS was not part of a street address or part of another city name. SQL returns any row with the string MINNEAPOLIS in the ADDRESS column, no matter where the string occurs. In another example, to list the towns whose names begin with 'SAN', you could specify:
... WHERE TOWN LIKE 'SAN%'

If you want to search for a character string that contains either the underscore or percent character, use the ESCAPE clause to specify an escape character. For example, to see all businesses that have a percent in their name, you could specify:
... WHERE BUSINESS_NAME LIKE '%@%%' ESCAPE '@'

The first and last percent characters are interpreted as usual. The combination @% is taken as the actual percent character.

Special considerations for LIKE


v When host variables are used in place of string constants in a search pattern, you should consider using varying length host variables. This allows you to: Assign previously used string constants to host variables without any change. Obtain the same selection criteria and results as if a string constant was used. v When fixed-length host variables are used in place of string constants in a search pattern, you should ensure the value specified in the host variable matches the pattern previously used by the string constants. All characters in a host variable that are not assigned a value are initialized with a blank. For example, if you did a search using the string pattern ABC%, these are some of the values that could be returned:
Chapter 5. Advanced Coding Techniques

73

'ABCD

'

'ABCDE'

'ABCxxx'

'ABC '

For example, if you did a search using the search pattern ABC% contained in a host variable with a fixed length of 10, these are some the values that could be returned assuming the column has a length of 12:
'ABCDE ' 'ABCD ' 'ABCxxx ' 'ABC '

Note that all returned values start with ABC and end with at least six blanks. This is because the last six characters in the host variable were not assigned a specific value so blanks were used. If you wanted to do a search on a fixed-length host variable where the last 7 characters could be anything, you would search for ABC%%%%%%%. These are some values that could be returned:
'ABCDEFGHIJ' 'ABCXXXXXXX' 'ABCDE' 'ABCDD'

Multiple search conditions within a WHERE clause


You saw how to qualify a request using one search condition. You can qualify your request further by coding a search condition that includes several predicates. The search condition you specify can contain any of the comparison operators or the keywords BETWEEN, IN, LIKE, IS NULL, and IS NOT NULL. You can join any two predicates with the connectors AND and OR. In addition, you can use the NOT keyword to specify that the desired search condition is the negated value of the specified search condition. A WHERE clause can have as many predicates as you want. v AND says that, for a row to qualify, the row must satisfy both predicates of the search condition. For example, to find out which employees in department D21 were hired after December 31, 1987, you would specify:
... WHERE WORKDEPT = 'D21' AND HIREDATE > '1987-12-31'

v OR says that, for a row to qualify, the row can satisfy the condition set by either or both predicates of the search condition. For example, to find out which employees are in either department C01 or D11, you could specify 4:
... WHERE WORKDEPT = 'C01' OR WORKDEPT = 'D11'

v NOT says that, to qualify, a row must not meet the criteria set by the search condition or predicate that follows the NOT. For example, to find all employees in department E11 except those with a job code equal to analyst, you could specify:
... WHERE WORKDEPT = 'E11' AND NOT JOB = 'ANALYST'

When SQL evaluates search conditions that contain these connectors, it does so in a specific order. SQL first evaluates the NOT clauses, next evaluates the AND clauses, and then the OR clauses. You can change the order of evaluation by using parentheses. The search conditions enclosed in parentheses are evaluated first. For example, to select all employees in departments E11 and E21 who have education levels greater than 12, you could specify:

4. You could also use IN to specify this request: WHERE WORKDEPT IN ('C01', 'D11').

74

DB2 UDB for AS/400 SQL Programming Concepts V4R5

... WHERE EDLEVEL > 12 AND (WORKDEPT = 'E11' OR WORKDEPT = 'E21')

The parentheses determine the meaning of the search condition. In this example, you want all rows that have a: WORKDEPT value of E11 or E21, and EDLEVEL value greater than 12 If you did not use parentheses:
... WHERE EDLEVEL > 12 AND WORKDEPT = 'E11' OR WORKDEPT = 'E21'

Your result is different. The selected rows are rows that have: WORKDEPT = E11 and EDLEVEL > 12, or WORKDEPT = E21, regardless of the EDLEVEL value

Joining data from more than one table


Sometimes the information you want to see is not in a single table. To form a row of the result table, you might want to retrieve some column values from one table and some column values from another table. You can retrieve and join column values from two or more tables into a single row. You can join tables using Operations Navigator, or using the JOIN statement. Four different types of joins are supported by DB2 UDB for AS/400: inner join, left outer join, exception join, and cross join. v An Inner Join returns only the rows from each table that have matching values in the join columns. Any rows that do not have a match between the tables will not appear in the result table. v A Left Outer Join on page 76 returns values for all of the rows from the first table (the table on the left) and the values from the second table for the rows that match. Any rows that do not have a match in the second table will return the null value for all columns from the second table. v An Exception Join on page 77 returns only the rows from the left table that do not have a match in the right table. Columns in the result table that come from the right table have the null value. v A Cross Join on page 78 returns a row in the result table for each combination of rows from the tables being joined (a Cartesian Product).

Inner Join
With an inner join, column values from one row of a table are combined with column values from another row of another (or the same) table to form a single row of data. SQL examines both tables specified for the join to retrieve data from all the rows that meet the search condition for the join. There are two ways of specifying an inner join: using the JOIN syntax, and using the WHERE clause. Suppose you want to retrieve the employee numbers, names, and project numbers for all employees that are responsible for a project. In other words, you want the EMPNO and LASTNAME columns from the CORPDATA.EMPLOYEE table and the

Chapter 5. Advanced Coding Techniques

75

PROJNO column from the CORPDATA.PROJECT table. Only employees with last names starting with S or later should be considered. To find this information, you need to join the two tables.

Inner join using JOIN syntax


To use the inner join syntax, both of the tables you are joining are listed in the FROM clause, along with the join condition that applies to the tables. The join condition is specified after the ON keyword and determines how the two tables are to be compared to each other to produce the join result. The condition can be any comparison operator; it does not need to be the equal operator. Multiple join conditions can be specified in the ON clause separated by the AND keyword. Any additional conditions that do not relate to the actual join are specified in either the WHERE clause or as part of the actual join in the ON clause.
SELECT EMPNO, LASTNAME, PROJNO FROM CORPDATA.EMPLOYEE INNER JOIN CORPDATA.PROJECT ON EMPNO = RESPEMP WHERE LASTNAME > 'S'

In this example, the join is done on the two tables using the EMPNO and RESPEMP columns from the tables. Since only employees that have last names starting with at least S are to be returned, this additional condition is provided in the WHERE clause. This query returns the following output:
EMPNO 000020 000060 000100 000250 LASTNAME THOMPSON STERN SPENSER SMITH PROJNO PL2100 MA2110 OP2010 AD3112

Inner join using the WHERE clause


Using the WHERE clause to perform this same join is written with both the join condition and the additional selection condition in the WHERE clause. The tables to be joined are listed in the FROM clause, separated by commas.
SELECT EMPNO, LASTNAME, PROJNO FROM CORPDATA.EMPLOYEE, CORPDATA.PROJECT WHERE EMPNO = RESPEMP AND LASTNAME > 'S'

This query returns the same output as the previous example.

Left Outer Join


A left outer join will return all the rows that an inner join returns plus one row for each of the other rows in the first table that did not have a match in the second table. Suppose you want to find all employees and the projects they are currently responsible for. You want to see those employees that are not currently in charge of a project as well. The following query will return a list of all employees whose names are greater than S, along with their assigned project numbers.

76

DB2 UDB for AS/400 SQL Programming Concepts V4R5

SELECT EMPNO, LASTNAME, PROJNO FROM CORPDATA.EMPLOYEE LEFT OUTER JOIN CORPDATA.PROJECT ON EMPNO = RESPEMP WHERE LASTNAME > 'S'

The result of this query contains some employees that do not have a project number. They are listed in the query, but have the null value returned for their project number.
EMPNO 000020 000060 000100 000170 000180 000190 000250 000280 000300 000310 LASTNAME THOMPSON STERN SPENSER YOSHIMURA SCOUTTEN WALKER SMITH SCHNEIDER SMITH SETRIGHT PROJNO PL2100 MA2110 OP2010 AD3112 -

Notes
Using the RRN scalar function to return the relative record number for a column in the table on the right in a left outer join or exception join will return a value of 0 for the unmatched rows.

Exception Join
An exception join returns only the records from the first table that do NOT have a match in the second table. Using the same tables as before, return those employees that are not responsible for any projects.
SELECT EMPNO, LASTNAME, PROJNO FROM CORPDATA.EMPLOYEE EXCEPTION JOIN CORPDATA.PROJECT ON EMPNO = RESPEMP WHERE LASTNAME > 'S'

This join returns the output:


EMPNO 000170 000180 000190 000280 000300 000310 LASTNAME YOSHIMURA SCOUTTEN WALKER SCHNEIDER SMITH SETRIGHT PROJNO -

An exception join can also be written as a subquery using the NOT EXISTS predicate. The previous query could be rewritten in the following way:

Chapter 5. Advanced Coding Techniques

77

SELECT EMPNO, LASTNAME FROM CORPDATA.EMPLOYEE WHERE LASTNAME > 'S' AND NOT EXISTS (SELECT * FROM CORPDATA.PROJECT WHERE EMPNO = RESPEMP)

The only difference in this query is that it cannot return values from the PROJECT table.

Cross Join
A cross join (or Cartesian Product join) will return a result table where each row from the first table is combined with each row from the second table. The number of rows in the result table is the product of the number of rows in each table. If the tables involved are large, this join can take a very long time. A cross join can be specified in two ways: using the JOIN syntax or by listing the tables in the FROM clause separated by commas without using a WHERE clause to supply join criteria. Suppose the following tables exist.
Table 13. Table A T1COL1 A1 A2 A3 Table 14. Table B T2COL1 B1 B2 T2COL2 BB1 BB2 T1COL2 AA1 AA2 AA3

The following two select statements produce identical results.


SELECT * FROM A CROSS JOIN B SELECT * FROM A, B

The result table for either of these select statements looks like this:
T1COL1 A1 A1 A2 A2 A3 A3 T1COL2 AA1 AA1 AA2 AA2 AA3 AA3 T2COL1 B1 B2 B1 B2 B1 B2 T2COL2 BB1 BB2 BB1 BB2 BB1 BB2

Multiple join types in one statement


There are times when more than two tables need to be joined to produce the desired result. If you wanted to return all the employees, their department name, and the project they are responsible for, if any, the EMPLOYEE table,

78

DB2 UDB for AS/400 SQL Programming Concepts V4R5

DEPARTMENT table, and PROJECT table would all need to be joined to get the information. The following example shows the query and the results.
SELECT EMPNO, LASTNAME, DEPTNAME, PROJNO FROM CORPDATA.EMPLOYEE INNER JOIN CORPDATA.DEPARTMENT ON WORKDEPT = DEPTNO LEFT OUTER JOIN CORPDATA.PROJECT ON EMPNO = RESPEMP WHERE LASTNAME > 'S' EMPNO 000020 000060 000100 000170 000180 000190 000250 000280 000300 000310 LASTNAME THOMPSON STERN SPENSER YOSHIMURA SCOUTTEN WALKER SMITH SCHNEIDER SMITH SETRIGHT DEPTNAME PLANNING MANUFACTURING SYSTEMS SOFTWARE SUPPORT MANUFACTURING SYSTEMS MANUFACTURING SYSTEMS MANUFACTURING SYSTEMS ADMINISTRATION SYSTEMS OPERATIONS OPERATIONS OPERATIONS PROJNO PL2100 MA2110 OP2010 AD3112 -

Notes on joins
When you join two or more tables: v If there are common column names, you must qualify each common name with the name of the table (or a correlation name). Column names that are unique do not need to be qualified. v If you do not list the column names you want, but instead use SELECT *, SQL returns rows that consist of all the columns of the first table, followed by all the columns of the second table, and so on. v You must be authorized to select rows from each table or view specified in the FROM clause. v The sort sequence is applied to all character and UCS-2 graphic columns being joined.

Specifying itermediate join tables using table expressions


You can use table expressions to specify an intermediate result table. They can be used in place of a view to avoid creating the view when general use of the view is not required. Table expressions consist of nested table expressions and common table expressions. Nested table expressions are specified within parentheses in the FROM clause. For example, suppose you want a result table that shows the manager number, department number, and maximum salary for each department. The manager number is in the DEPARTMENT table, the department number is in both the DEPARTMENT and EMPLOYEE tables, and the salaries are in the EMPLOYEE table. You can use a table expression in the from clause to select the maximum salary for each department. You add a correlation name, T2, following the nested table expression to name the derived table. The outer select then uses T2 to qualify columns that are selected from the derived table, in this case MAXSAL and
Chapter 5. Advanced Coding Techniques

79

WORKDEPT. Note that the MAX(SALARY) column selected in the nested table expression must be named in order to be referenced in the outer select. The AS clause is used to do that.
SELECT MGRNO, T1.DEPTNO, MAXSAL FROM CORPDATA.DEPARTMENT T1, (SELECT MAX(SALARY) AS MAXSAL, WORKDEPT FROM CORPDATA.EMPLOYEE E1 GROUP BY WORKDEPT) T2 WHERE T1.DEPTNO = T2.WORKDEPT ORDER BY DEPTNO

The result of the query is:


MGRNO DEPTNO 000010 A00 000020 B01 000030 C01 000060 D11 000070 D21 000050 E01 000090 E11 000100 E21 MAXSAL 52,750.00 41,250.00 38,250.00 32,250.00 36,170.00 40,175.00 29,750.00 26,150.00

Common table expressions can be specified prior to the full-select in a SELECT statement, an INSERT statement, or a CREATE VIEW statement. They can be used when the same result table needs to be shared in a full-select. Common table expressions are preceeded with the keyword WITH. For example, suppose you want a table that shows the minimum and maximum of the average salary of a certain set of departments. The first character of the department number has some meaning and you want to get the minimum and maximum for those departments that start with the letter D and those that start with the letter E. You can use a common table expression to select the average salary for each department. Again, you must name the derived table; in this case, the name is DT. You can then specify a SELECT statement using a WHERE clause to restrict the selection to only the departments that begin with a certain letter. Specify the minimum and maximum of column AVGSAL from the derived table DT. Specify a UNION to get the results for the letter E and the results for the letter D.
WITH DT AS (SELECT E.WORKDEPT AS DEPTNO, AVG(SALARY) AS AVGSAL FROM CORPDATA.DEPARTMENT D , CORPDATA.EMPLOYEE E WHERE D.DEPTNO = E.WORKDEPT GROUP BY E.WORKDEPT) SELECT 'E', MAX(AVGSAL), MIN(AVGSAL) FROM DT WHERE DEPTNO LIKE 'E%' UNION SELECT 'D', MAX(AVGSAL), MIN(AVGSAL) FROM DT WHERE DEPTNO LIKE 'D%'

The result of the query is:


E D MAX ( AVGSAL ) 40,175.00 25,153.33 MIN ( AVGSAL ) 20,998.00 24,677.77

Using the UNION keyword to combine subselects


Using the UNION keyword, you can combine two or more subselects to form a single select-statement. When SQL encounters the UNION keyword, it processes each subselect to form an interim result table, then it combines the interim result table of each subselect and deletes duplicate rows to form a combined result table.

80

DB2 UDB for AS/400 SQL Programming Concepts V4R5

You use UNION to merge lists of values from two or more tables. You can use any of the clauses and techniques you have learned so far when coding select-statements, including ORDER BY. You can use UNION to eliminate duplicates when merging lists of values obtained from several tables. For example, you can obtain a combined list of employee numbers that includes: v People in department D11 v People whose assignments include projects MA2112, MA2113, and AD3111 The combined list is derived from two tables and contains no duplicates. To do this, specify:
MOVE 'D11' TO WORK-DEPT. ... EXEC SQL DECLARE XMP6 CURSOR FOR SELECT EMPNO FROM CORPDATA.EMPLOYEE WHERE WORKDEPT = :WORK-DEPT UNION SELECT EMPNO FROM CORPDATA.EMP_ACT WHERE PROJNO = 'MA2112' OR PROJNO = 'MA2113' OR PROJNO = 'AD3111' ORDER BY EMPNO END-EXEC. ... EXEC SQL FETCH XMP6 INTO :EMP-NUMBER END-EXEC.

To better understand what results from these SQL statements, imagine that SQL goes through the following process:

Chapter 5. Advanced Coding Techniques

81

Step 1: SQL processes the first SELECT statement:

Which results in an interim result table: (from CORPDATA.EMPLOYEE) 000060 000150 000160 000170 ...

Step 2: SQL processes the second SELECT statement:

Which results in another interim result table: (from CORPDATA.EMP ACT) 000230 000230 000230 ...

Step 3: SQL combines the two interim result tables:

Which results in a combined result table with values in ascending sequence: fetch EMP-NUMBER 1 2 3 4 5 ... 000060 000150 000160 000170 000180 ...
RV3W186-0

When you use UNION: v Any ORDER BY clause must appear after the last subselect that is part of the union. In this example, the results are sequenced on the basis of the first selected column, EMPNO. The ORDER BY clause specifies that the combined result table is to be in collated sequence. v A name may be specified on the ORDER BY clause if the result columns are named. A result column is named if the corresponding columns in each of the unioned select-statements have the same name. An AS clause can be used to assign a name to columns in the select list.
SELECT A + B AS X ... UNION SELECT X ... ORDER BY X

If the result columns are unnamed, use numbers to order the result. The number refers to the position of the expression in the list of expressions you include in your subselects.
SELECT A + B ... UNION SELECT X ... ORDER BY 1

You cannot use UNION when creating a view.

82

DB2 UDB for AS/400 SQL Programming Concepts V4R5

To identify which subselect each row is from, you can include a constant at the end of the select list of each subselect in the union. When SQL returns your results, the last column contains the constant for the subselect that is the source of that row. For example, you can specify:
SELECT A, B, 'A1' ... UNION SELECT X, Y, 'B2'

When a row is presented to your program, it includes a value (either A1 or B2) to indicate the table that is the source of the rows values. If the column names in the union are different, SQL uses the set of column names specified in the first subselect when interactive SQL displays or prints the results, or in the SQLDA resulting from processing an SQL DESCRIBE statement. For information on compatibility of the length and data type for columns in a UNION, see chapter 4 of the SQL Reference book. Note: Sort sequence is applied after the fields across the UNION pieces are made compatible. The sort sequence is used for the distinct processing that implicitly occurs during UNION processing.

Specifying UNION ALL


If you want to keep duplicates in the result of a UNION, specify UNION ALL instead of just UNION.

Step 3. SQL combines two interim result tables:

Resulting in a result table that includes duplicates: fetch EMP-NUMBER 1 2 3 4 5 6 7 8 ... 000060 000150 000150 000150 000160 000160 000170 000170 ...
RV3W187-0

v The UNION ALL operation is associative, for example:


(SELECT PROJNO FROM CORPDATA.PROJECT UNION ALL SELECT PROJNO FROM CORPDATA.PROJECT) UNION ALL SELECT PROJNO FROM CORPDATA.EMP_ACT

gives the same result as:


SELECT PROJNO FROM CORPDATA.PROJECT UNION ALL (SELECT PROJNO FROM CORPDATA.PROJECT UNION ALL SELECT PROJNO FROM CORPDATA.EMP_ACT)

v When you include the UNION ALL in the same SQL statement as a UNION operator, however, the result of the operation depends on the order of
Chapter 5. Advanced Coding Techniques

83

evaluation. Where there are no parentheses, evaluation is from left to right. Where parentheses are included, the parenthesized subselect is evaluated first, followed, from left to right, by the other parts of the statement.

Subqueries in SELECT statements


In the WHERE and HAVING clauses you have seen so far, you specified a search condition by using a literal value, a column name, an expression, or the registers. In those search conditions, you know that you are searching for a specific value, but sometimes you cannot supply that value until you have retrieved other data from a table. For example, suppose you want a list of the employee numbers, names, and job codes of all employees working on a particular project, say project number MA2100. The first part of the statement is easy to write:
DECLARE XMP CURSOR FOR SELECT EMPNO, LASTNAME, JOB FROM CORPDATA.EMPLOYEE WHERE EMPNO ...

But you cannot go further because the CORPDATA.EMPLOYEE table does not include project number data. You do not know which employees are working on project MA2100 without issuing another SELECT statement against the CORPDATA.EMP_ACT table. With SQL, you can nest one SELECT statement within another to solve this problem. The inner SELECT statement is called a subquery. The SELECT statement surrounding the subquery is called the outer-level SELECT. Using a subquery, you could issue just one SQL statement to retrieve the employee numbers, names, and job codes for employees who work on project MA2100:
DECLARE XMP CURSOR FOR SELECT EMPNO, LASTNAME, JOB FROM CORPDATA.EMPLOYEE WHERE EMPNO IN (SELECT EMPNO FROM CORPDATA.EMP_ACT WHERE PROJNO = 'MA2100')

To better understand what will result from this SQL statement, imagine that SQL goes through the following process:

84

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Step 1: SQL evaluates the subquery to obtain a list of EMPNO values:

Which results in an interim results table: (from CORPDATA.EMP ACT) 000010 000110

Step 2: The interim results table then serves as a list in the search condition of the outer-level SELECT. Essentially, this is what is executed.

The final result table looks like this:

fetch 1 2

EMPNO 000010 000110

LASTNAME HAAS LUCCHESSI

JOB PRES SALESREP

RV2W559-2

Correlation
The purpose of a subquery is to supply information needed to qualify a row (WHERE clause) or a group of rows (HAVING clause). This is done through the result table that the subquery produces. Conceptually, the subquery is evaluated whenever a new row or group of rows must be qualified. In fact, if the subquery is the same for every row or group, it is evaluated only once. For example, the previous subquery has the same content for every row of the table CORPDATA.EMPLOYEE. Subqueries like this are said to be uncorrelated. Some subqueries vary in content from row to row or group to group. The mechanism that allows this is called correlation, and the subqueries are said to be correlated. More information on correlated subqueries can be found in Correlated subqueries on page 88. Even so, what is said before that point applies equally to correlated and uncorrelated subqueries.

Subqueries and search conditions


A subquery is always part of a search condition. The search condition is in the form operand operator (subquery). In the example, the operand is EMPNO and operator is IN. The search condition can be part of a WHERE or HAVING clause. The clause can include more than one search condition that contains a subquery. A search condition containing a subquery, like any other search condition, can be enclosed in parentheses, can be preceded by the keyword NOT, and can be linked to other search conditions through the keywords AND and OR. For example, the WHERE clause of some query could look something like this:
WHERE X IN (subquery1) AND (Y > SOME (subquery2) OR Z = 100)
Chapter 5. Advanced Coding Techniques

85

Subqueries can also appear in the search conditions of other subqueries. Such subqueries are said to be nested at some level of nesting. For example, a subquery within a subquery within an outer-level SELECT is nested at a nesting level of two. SQL allows nesting down to a nesting level of 32, but few queries require a nesting level greater than 1.

How subqueries are used


There are four ways to include a subquery in either a WHERE or HAVING clause:

Basic comparisons
You can use a subquery immediately after any of the comparison operators. If you do, the subquery can return at most one value. The value can be the result of a column function or an arithmetic expression. SQL then compares the value that results from the subquery with the value to the left of the comparison operator. For example, suppose you want to find the employee numbers, names, and salaries for employees whose education level is higher than the average education level throughout the company.
DECLARE XMP CURSOR FOR SELECT EMPNO, LASTNAME, SALARY FROM CORPDATA.EMPLOYEE WHERE EDLEVEL > (SELECT AVG(EDLEVEL) FROM CORPDATA.EMPLOYEE)

SQL first evaluates the subquery and then substitutes the result in the WHERE clause of the SELECT statement. In this example, the result is (as it should be) the company-wide average educational level. Besides returning a single value, a subquery could return no value at all. If it does, the result of the compare is unknown. Consider, for example, the first query shown in this section, and assume that there are not any employees currently working on project MA2100. Then the subquery would return no value, and the search condition would be unknown for every row. In this case, then, the result produced by the query would be an empty table.

Quantified comparisons (ALL, ANY, and SOME)


You can use a subquery after a comparison operator followed by the keyword ALL, ANY, or SOME. When used in this way, the subquery can return zero, one, or many values, including null values. You can use ALL, ANY, and SOME in the following ways: v Use ALL to indicate that the value you supplied must compare in the indicated way to ALL the values the subquery returns. For example, suppose you use the greater-than comparison operator with ALL:
... WHERE expression > ALL (subquery)

To satisfy this WHERE clause, the value in the expression must be greater than all the values (that is, greater than the highest value) returned by the subquery. If the subquery returns an empty set (that is, no values were selected), the condition is satisfied. v Use ANY or SOME to indicate that the value you supplied must compare in the indicated way to at least one of the values the subquery returns. For example, suppose you use the greater-than comparison operator with ANY:
... WHERE expression > ANY (subquery)

86

DB2 UDB for AS/400 SQL Programming Concepts V4R5

To satisfy this WHERE clause, the value in the expression must be greater than at least one of the values (that is, greater than the lowest value) returned by the subquery. If what the subquery returns is empty, the condition is not satisfied. Note: The results when a subquery returns one or more null values may surprise you, unless you are familiar with formal logic. For applicable rules, read the discussion of quantified predicates in the SQL Reference.

IN keyword
You can use IN to say that the value in the expression must be among the values returned by the subquery. The first example in this chapter illustrates this type of usage. Using IN is equivalent to using =ANY or =SOME. Using ANY and SOME were previously described. You could also use the IN keyword with the NOT keyword in order to select rows when the value is not among the values returned by the subquery. For example, you could use:
... WHERE WORKDEPT NOT IN (SELECT ...)

EXISTS Keyword
In the subqueries presented so far, SQL evaluates the subquery and uses the result as part of the WHERE clause of the outer-level SELECT. In contrast, when you use the keyword EXISTS, SQL simply checks whether the subquery returns one or more rows. If it does, the condition is satisfied. If it does not (if it returns no rows), the condition is not satisfied. For example:
DECLARE XMP CURSOR FOR SELECT EMPNO,LASTNAME FROM CORPDATA.EMPLOYEE WHERE EXISTS (SELECT * FROM CORPDATA.PROJECT WHERE PRSTDATE > '1982-01-01');

In the example, the search condition holds if any project represented in the CORPDATA.PROJECT table has an estimated start date that is later than January 1, 1982. Please note that this example does not show the full power of EXISTS, because the result is always the same for every row examined for the outer-level SELECT. As a consequence, either every row appears in the results, or none appear. In a more powerful example, the subquery itself would be correlated, and would change from row to row. See Correlated subqueries on page 88 for more information on correlated subqueries. As shown in the example, you do not need to specify column names in the subquery of an EXISTS clause. Instead, you can code SELECT *. You could also use the EXISTS keyword with the NOT keyword in order to select rows when the data or condition you specify does not exist. That is, you could use:
... WHERE NOT EXISTS (SELECT ...)

For all general types of usage for subqueries but one (using a subquery with the EXISTS keyword), the subquery must produce a one-column result table. This means that the SELECT clause in a subquery must name a single column, or contain a single expression. For example, both of the following SELECT clauses would be allowed for all four usage types:
SELECT AVG(SALARY) SELECT EMPNO

Chapter 5. Advanced Coding Techniques

87

The result table produced by a subquery can have zero or more rows. For some usages, no more than one row is allowed.

Using subqueries with UPDATE and DELETE


In the examples shown so far, you have seen subqueries within SELECT statements. You can also use subqueries in the WHERE clause of the UPDATE or DELETE statements or in the SET clause of an UPDATE. For the most part, this is not very different from using subqueries with outer-level SELECTs.

Notes on using subqueries


1. When nesting SELECT statements, you can use as many as you need to satisfy your requirements (1 to 31 subqueries), although performance is slower for each additional subquery. A maximum of 128 tables can be specified in an SQL statement. 2. When the outer statement is a SELECT statement (at any level of nesting): v The subquery can be based on the same table or view as the outer statement, or on a different table or view. v You can use a subquery in the WHERE clause of the outer-level SELECT, even when the outer-level SELECT is part of a DECLARE CURSOR, CREATE VIEW, or INSERT statement. v You can use a subquery in the HAVING clause of a SELECT statement. When you do, SQL evaluates the subquery and uses it to qualify each group. 3. When the statement is an UPDATE or DELETE statement, you can use subqueries in the WHERE clause of the UPDATE or DELETE statement. 4. When a subquery is used in the SET clause of an UPDATE statement, the result table of a subselect must contain the same number of values as the corresponding list of columns to be updated. In all other cases, the result table for a subquery must consist of a single column, unless the subquery is being used with the EXISTS keyword. The number of rows in this table can vary from zero to many, but for comparisons not involving the keywords ALL, ANY, or SOME, the number of rows must be zero or one. 5. A subquery cannot include the ORDER BY, UNION, UNION ALL, FOR READ ONLY, UPDATE, or OPTIMIZE clauses. 6. In any subquery, as in any search condition, the values compared must be compatible. 7. Using a column function or an arithmetic expression with a column name in a subquery does not make it incompatible. The data type of the column does not change after SQL applies a column function or arithmetic operator.

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

Example: Correlated Subquery in a WHERE Clause


Suppose that you want a list of all the employees whose education levels are higher than the average education levels in their respective departments. To get

88

DB2 UDB for AS/400 SQL Programming Concepts V4R5

this information, SQL must search the CORPDATA.EMPLOYEE table. For each employee in the table, SQL needs to compare the employees education level to the average education level for the employees department. In the subquery, you tell SQL to calculate the average education level for the department number in the current row. For example:
DECLARE XMP CURSOR FOR SELECT EMPNO, LASTNAME, WORKDEPT, EDLEVEL FROM CORPDATA.EMPLOYEE X WHERE EDLEVEL > (SELECT AVG(EDLEVEL) FROM CORPDATA.EMPLOYEE WHERE WORKDEPT = X.WORKDEPT)

A correlated subquery looks like an uncorrelated one, except for the presence of one or more correlated references. In the example, the single correlated reference is the occurrence of X.WORKDEPT in the subselects FROM clause. Here, the qualifier X is the correlation name defined in the FROM clause of the outer SELECT statement. In that clause, X is introduced as the correlation name of the table CORPDATA.EMPLOYEE. Now, consider what happens when the subquery is executed for a given row of CORPDATA.EMPLOYEE. Before it is executed, the occurrence of X.WORKDEPT is replaced with the value of the WORKDEPT column for that row. Suppose, for example, that the row is for CHRISTINE I HAAS. Her work department is A00, which is the value of WORKDEPT for this row. The subquery executed for this row is:
(SELECT AVG(EDLEVEL) FROM CORPDATA.EMPLOYEE WHERE WORKDEPT = 'A00')

Thus, for the row considered, the subquery produces the average education level of Christines department. This is then compared in the outer statement to Christines own education level. For some other row for which WORKDEPT has a different value, that value appears in the subquery in place of A00. For example, for the row for MICHAEL L THOMPSON, this value would be B01, and the subquery for his row would deliver the average education level for department B01. The result table produced by the query would have the following values:
(from CORPDATA.EMPLOYEE)

fetch EMPNO 1 2 3 4 000010 000030 000070 000090

LASTNAME HAAS KWAN PULASKI HENDERSON

WORKDEPT A00 C01 D21 E11

EDLEVEL 18 20 16 16

RV2W560-3

Chapter 5. Advanced Coding Techniques

89

Example: Correlated Subquery in a HAVING Clause


Suppose that you want a list of all the departments whose average salary is higher than the average salary of their area (all departments whose WORKDEPT begins with the same letter belong to the same area). To get this information, SQL must search the CORPDATA.EMPLOYEE table. For each department in the table, SQL compares the departments average salary to the average salary of the area. In the subquery, SQL calculates the average salary for the area of the department in the current group. For example:
DECLARE XMP CURSOR FOR SELECT WORKDEPT, DECIMAL(AVG(SALARY),8,2) FROM CORPDATA.EMPLOYEE X GROUP BY WORKDEPT HAVING AVG(SALARY) > (SELECT AVG(SALARY) FROM CORPDATA.EMPLOYEE WHERE SUBSTR(X.WORKDEPT,1,1) = SUBSTR(WORKDEPT,1,1))

Consider what happens when the subquery is executed for a given department of CORPDATA.EMPLOYEE. Before it is executed, the occurrence of X.WORKDEPT is replaced with the value of the WORKDEPT column for that group. Suppose, for example, that the first group selected has A00 for the value of WORKDEPT. The subquery executed for this group is:
(SELECT AVG(SALARY) FROM CORPDATA.EMPLOYEE WHERE SUBSTR('A00',1,1) = SUBSTR(WORKDEPT,1,1))

Thus, for the group considered, the subquery produces the average salary for the area. This is then compared in the outer statement to the average salary for department 'A00'. For some other group for which WORKDEPT is B01, the subquery would result in the average salary for the area where department B01 belongs. The result table produced by the query would have the following values:
(from CORPDATA.EMPLOYEE) fetch WORKDEPT 1 2 D21 E01 AVG SALARY 25153.33 40175.00
RV2W561-3

Correlated names and references


A correlated reference can appear only in a search condition in a subquery. The reference is always of the form X.C, where X is a correlation name and C is the name of a column in the table that X represents. In the preceding example, for instance, X represents the table CORPDATA.EMPLOYEE, and C identifies the column WORKDEPT in this table. The correlation name is defined in the FROM clause of some query. This query could be the outer-level SELECT, or any of the subqueries that contain the one with the reference. Suppose, for example, that a query contains subqueries A, B, and C, and that A contains B and B contains C. Then a correlation name used in C could be defined in B, A, or the outer-level SELECT.

90

DB2 UDB for AS/400 SQL Programming Concepts V4R5

You can define a correlation name for each table name appearing in a FROM clause. Simply include the correlation names after the table names. Leave one or more blanks between a table name and its correlation name, and place a comma after the correlation name if it is followed by another table name. The following FROM clause, for example, defines the correlation names TA and TB for the tables TABLEA and TABLEB, and no correlation name for the table TABLEC.
FROM TABLEA TA, TABLEC, TABLEB TB

Any number of correlated references can appear in a subquery. There are no restrictions on variety. For example, one correlated name in a reference could be defined in the outer-level SELECT, while another could be defined in a containing subquery. Before the subquery is executed, a value from the referenced column is always substituted for the correlated reference. The value is determined as follows: Note: Use D to designate the query in which the correlation name is defined. Then the subquery is either in the WHERE clause of D, or in its HAVING clause. v If the subquery is in the WHERE clause, its results are used by D to qualify a row. The substituted value is then taken from this row. This is the case for the example, where the defining query is the outer one and the subquery appears in the outer querys WHERE clause. v If the subquery is in the HAVING clause, its results are used by D to qualify a group of rows. The substituted value is then taken from this group. Note that in this case, the column specified must be identified in the GROUP BY clause in D. If it is not, the specified column could have more than one value for the group.

Using correlated subqueries in an UPDATE statement


When you use a correlated subquery in an UPDATE statement, the correlation name refers to the rows you are interested in updating. For example, when all activities of a project must be completed before September 1983, your department considers that project to be a priority project. You could use the SQL statement below to evaluate the projects in the CORPDATA.PROJECT table, and write a 1 (a flag to indicate PRIORITY) in the PRIORITY column (a column you added to CORPDATA.PROJECT for this purpose) for each priority project.
UPDATE CORPDATA.PROJECT X SET PRIORITY = 1 WHERE '1983-09-01' > (SELECT MAX(EMENDATE) FROM CORPDATA.EMP_ACT WHERE PROJNO = X.PROJNO)

As SQL examines each row in the CORPDATA.EMP_ACT table, it determines the maximum activity end date (EMENDATE) for all activities of the project (from the CORPDATA.PROJECT table). If the end date of each activity associated with the project is prior to September 1983, the current row in the CORPDATA.PROJECT table qualifies and is updated.

Using correlated subqueries in a DELETE statement


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

91

Suppose a row in the CORPDATA.PROJECT table was deleted. Rows related to the deleted project in the CORPDATA.EMP_ACT table must also be deleted. To do this, you can use:
DELETE FROM CORPDATA.EMP_ACT X WHERE NOT EXISTS (SELECT * FROM CORPDATA.PROJECT WHERE PROJNO = X.PROJNO)

SQL determines, for each row in the CORPDATA.EMP_ACT table, whether a row with the same project number exists in the CORPDATA.PROJECT table. If not, the CORPDATA.EMP_ACT row is deleted.

Notes on using correlated subqueries


v The correlation name is separated from its associated table name with a space. To specify another table name, precede the table name with a comma, for example:
FROM CORPDATA.EMPLOYEE X, CORPDATA.PROJECT ....

v The correlated subquery and the outer-level statement can refer to the same table or to different tables. v In an INSERT statement, neither the correlated subquery nor an outer-level SELECT within the INSERT statement can be based on the same table into which you are inserting. v The outer-level SELECT that defines the correlation name can join two or more tables. v You can use correlated subqueries in HAVING clauses. When you do, SQL evaluates the subquery, once per group, of the outer-level SELECT. The column you refer to in the HAVING clause must specify a property of each group (for example, WORKDEPT) either the columns you grouped the rows by or another column with one of the column functions. v You can nest correlated subqueries.

Changing a table definition


Changing the definition of a table allows you to add new columns, change an existing column definition (change its length, default value, and so on), drop existing columns, and add and remove constraints. You can change the definition of a table using Operations Navigator. Or, use the SQL ALTER TABLE statement. You can add, change, or drop columns and add or remove constraints all with one ALTER TABLE statement. However, a single column can be referenced only once in the ADD COLUMN, ALTER COLUMN, and DROP COLUMN clauses. That is, you cannot add a column and then alter that column in the same ALTER TABLE statement.

Adding a column
You can add a column to a table using Operations Navigator. Or use the ADD COLUMN clause of the SQL ALTER TABLE statement. When you add a new column to a table, the column is initialized with its default value for all existing rows. If NOT NULL is specified, a default value must also be specified.

92

DB2 UDB for AS/400 SQL Programming Concepts V4R5

The altered table may consist of up to 8000 columns. The sum of the byte counts of the columns must not be greater than 32766 or, if a VARCHAR or VARGRAPHIC column is specified, 32740. If a LOB column is specified, the sum of record data byte counts of the columns must not be greater than 15 728 640.

Changing a column
You can change a column definition in a table using Operations Navigator. Or, you can use the ALTER COLUMN clause of the ALTER TABLE statement. When you change the data type of an existing column, the old and new attributes must be compatible. Allowable conversions shows the conversions with compatible attributes. When you convert to a data type with a longer length, data will be padded with the appropriate pad character. When you convert to a data type with a shorter length, data may be lost due to truncation. An inquiry message prompts you to confirm the request. If you have a column that does not allow the null value and you want to change it to now allow the null value, use the DROP NOT NULL clause. If you have a column that allows the null value and you want to prevent the use of null values, use the SET NOT NULL clause. If any of the existing values in that column are the null value, the ALTER TABLE will not be performed and an SQLCODE of -190 will result.

Allowable conversions
Table 15. Allowable Conversions FROM data type Decimal TO data type Numeric Bigint, Integer, Smallint Float Decimal Bigint, Integer, Smallint Float Decimal Numeric Float Numeric Bigint, Integer, Smallint DBCS-open UCS-2 graphic Character UCS-2 graphic Character DBCS-open UCS-2 graphic DBCS-open

Decimal Decimal Numeric

| | | | |

Numeric Numeric Bigint, Integer, Smallint Bigint, Integer, Smallint Bigint, Integer, Smallint Float Float Character Character DBCS-open DBCS-open DBCS-either DBCS-either DBCS-either DBCS-only

Chapter 5. Advanced Coding Techniques

93

Table 15. Allowable Conversions (continued) FROM data type DBCS-only DBCS-only DBCS graphic UCS-2 graphic UCS-2 graphic UCS-2 graphic distinct type source type TO data type DBCS graphic UCS-2 graphic UCS-2 graphic Character DBCS-open DBCS graphic source type distinct type

When modifying an existing column, only the attributes that you specify will be changed. All other attributes will remain unchanged. For example, given the following table definition:
CREATE TABLE EX1 (COL1 CHAR(10) DEFAULT 'COL1', COL2 VARCHAR(20) ALLOCATE(10) CCSID 937, COL3 VARGRAPHIC(20) ALLOCATE(10) NOT NULL WITH DEFAULT)

After running the following ALTER TABLE statement:


ALTER TABLE EX1 ALTER COLUMN COL2 SET DATA TYPE VARCHAR(30) ALTER COLUMN COL3 DROP NOT NULL

COL2 would still have an allocated length of 10 and CCSID 937, and COL3 would still have an allocated length of 10.

Deleting a column
You can delete a column using Operations Navigator. Or you can delete a column using the DROP COLUMN clause of the ALTER TABLE statement. Dropping a column deletes that column from the table definition. If CASCADE is specified, any views, indexes, and constraints dependent on that column will also be dropped. If RESTRICT is specified, and any views, indexes, or constraints are dependent on the column, the column will not be dropped and SQLCODE of -196 will be issued.

Order of operations for ALTER TABLE statement


An ALTER TABLE statement is performed as a set of steps as follows: 1. Drop constraints 2. Drop columns for which the RESTRICT option was specified 3. Alter column definitions (this includes adding columns and dropping columns for which the CASCADE option was specified) 4. Add constraints Within each of these steps, the order in which you specify the clauses is the order in which they are performed, with one exception. If any columns are being dropped, that operation is logically done before any column definitions are added or altered, in case record length is increased as a result of the ALTER TABLE statement.

94

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Creating and using views


A view can be used to access part of the data in one or more tables. You can define the columns of the view in the SELECT clause and the tables the view is based on in the FROM clause. To define the rows in the view, you can specify a WHERE clause, a GROUP by clause, or a HAVING clause. For example, to create a view that selects only the last name and the department of all the managers, specify:
CREATE VIEW CORPDATA.EMP_MANAGERS AS SELECT LASTNAME, WORKDEPT FROM CORPDATA.EMPLOYEE WHERE JOB = 'MANAGER'

If the select list contains elements other than columns such as expressions, functions, constants, or special registers, and the AS clause was not used to name the columns, a column list must be specified for the view. In the following example, the columns of the view are LASTNAME and YEARSOFSERVICE.
CREATE VIEW CORPDATA.EMP_YEARSOFSERVICE (LASTNAME, YEARSOFSERVICE) AS SELECT LASTNAME, YEARS (CURRENT DATE - HIREDATE) FROM CORPDATA.EMPLOYEE

The previous view can also be defined by using the AS clause in the select list to name the columns in the view. For example:
CREATE VIEW CORPDATA.EMP_YEARSOFSERVICE AS SELECT LASTNAME, YEARS (CURRENT_DATE - HIREDATE) AS YEARSOFSERVICE FROM CORPDATA.EMPLOYEE

Once you have created the view, you can use it to select the data or possibly change the data in the base table. The following restrictions must be considered when creating the view: v You cannot change, insert, or delete data in a read-only view. A view is read-only if it includes any of the following: The first FROM clause identifies more than one table (join). The first FROM clause identifies a read-only view. The first SELECT clause contains any of the SQL column functions (SUM, MAX, MIN, AVG, COUNT, STDDEV, or VAR). The first SELECT clause specifies the keyword DISTINCT. The outer subselect contains a GROUP BY or HAVING clause. A subquery, such that the base object of the outer-most subselect and a table of a subquery are the same table In the above cases, you can get data from the views by means of the SQL SELECT statement, but you cannot use statements such as INSERT, UPDATE, or DELETE. v You cannot insert a row in a view if: The table on which the view is based has a column that has no default value, does not allow nulls, and is not in the view. The view has a column resulting from an expression, a constant, a function, or a special register and the column was specified in the INSERT column list. The WITH CHECK OPTION was specified when the view was created and the row does not match the selection criteria.
Chapter 5. Advanced Coding Techniques

95

v You cannot update a column of a view that results from an expression, a constant, a function, or a special register. v You cannot use UNION, UNION ALL, FOR UPDATE OF, FOR READ ONLY, ORDER BY, or OPTIMIZE FOR n ROWS in the definition of a view. Views are created with the sort sequence in effect at the time the CREATE VIEW statement is run. The sort sequence applies to all character and UCS-2 graphic comparisons in the CREATE VIEW statement subselect. See Sort sequences in SQL on page 50 for more information on sort sequences. Views can also be created using the WITH CHECK OPTION to specify the level of checking that should be done when data is inserted or updated through the view. See WITH CHECK OPTION on a View on page 108 for more information.

Adding indexes
You can use indexes to sort and select data. In addition, indexes help the system retrieve data faster for better query performance. You can create an index when creating a table using Operations Navigator. Or use the SQL CREATE INDEX statement. The following example creates an index over the column LASTNAME in the CORPDATA.EMPLOYEE table:
CREATE INDEX CORPDATA.INX1 ON CORPDATA.EMPLOYEE (LASTNAME)

You can create a number of indexes. However, because the indexes are maintained by the system, a large number of indexes can adversely affect performance. For more information about indexes and query performance, see Effectively Using SQL Indexes in the Database Performance and Query Optimization information. One type of index, the encoded vector index, allows for faster scans that can be more easily processed in parallel. You create encoded vector indexes by using the SQL CREATE INDX statement. For more information about accelerating your queries with encoded vector indexes , go to the DB2 for AS/400 webpages.

If an index is created that has exactly the same attributes as an existing index, the new index shares the existing indexes binary tree. Otherwise, another binary tree is created. If the attributes of the new index are exactly the same as another index, except the new index has fewer columns, another binary tree is still created. It is still created because the extra columns would prevent the index from being used by cursors or UPDATE statements which update those extra columns. Indexes are created with the sort sequence in effect at the time the CREATE INDEX statement is run. The sort sequence applies to all SBCS character fields and UCS-2 graphic fields of the index. See Sort sequences in SQL on page 50 for more information on sort sequences.

96

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Catalogs in database design


A catalog is automatically created when you create a collection. There is also a system-wide catalog that is always in the QSYS2 library. When an SQL object is created in a collection, information is added to both the system catalog tables and the collections catalog tables. When an SQL object is created in a library, only the QSYS2 catalog is updated. For more information about catalogs, see the SQL Reference book. As the following examples show, you can display catalog information. You cannot INSERT, DELETE, or UPDATE catalog information. You must have SELECT privileges on the catalog views to run the following examples. Attention: Operations that normally update the SQL catalog for a collection can no longer update the catalog if the collection is saved, restored, and given a different name. Saving in one collection and restoring to another is not supported by the product.

Getting catalog information about a table


SYSTABLES contains a row for every table and view in the SQL collection. It tells you if the object is a table or view, the object name, the owner of the object, what SQL collection it is in, and so forth. The following sample statement displays information for the CORPDATA.DEPARTMENT table:
SELECT * FROM CORPDATA.SYSTABLES WHERE NAME = 'DEPARTMENT'

Getting catalog information about a column


SYSCOLUMNS contains a row for each column of every table and view in the collection. The following sample statement displays all the column names in the CORPDATA.DEPARTMENT table:
SELECT * FROM CORPDATA.SYSCOLUMNS WHERE TBNAME = 'DEPARTMENT'

The result of the previous sample statement is a row of information for each column in the table. Some of the information is not visible because the width of the information is wider than the display screen. For more information about each column, specify a select-statement like this:
SELECT NAME, TBNAME, COLTYPE, LENGTH, DEFAULT FROM CORPDATA.SYSCOLUMNS WHERE TBNAME = 'DEPARTMENT'

In addition to the column name for each column, the select-statement shows: v The name of the table that contains the column v The data type of the column v The length attribute of the column
Chapter 5. Advanced Coding Techniques

97

v If the column allows default values The result looks like this:
NAME DEPTNO DEPTNAME MGRNO ADMRDEPT TBNAME DEPARTMENT DEPARTMENT DEPARTMENT DEPARTMENT COLTYPE CHAR VARCHAR CHAR CHAR LENGTH 3 29 6 3 DEFAULT N N Y N

98

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Chapter 6. Data Integrity


Data integrity is the principle of ensuring data values between tables of a collection are kept in a state which makes sense to the business. For example, if a bank has a list of customers in table A and a list of customer accounts in table B, it would not make sense to allow a new account to be added to table B unless an associated customer exists in table A. This chapter describes the different ways the system automatically enforces these kinds of relationships. Referential integrity, check constraints, and triggers are all ways of accomplishing data integrity. Additionally, the WITH CHECK OPTION clause on a CREATE VIEW constrains the inserting or updating of data through a view. For comprehensive information about data integrity, see theDatabase Programming book.

Adding and using check constraints


A check constraint assures the validity of data during inserts and updates by limiting the allowable values in a column or group of columns. You can add check constraints using Operations Navigator when creating a table. Or use the SQL CREATE TABLE and ALTER TABLE statements to add or drop check constraints. In this example, the following statement creates a table with three columns and a check constraint over COL2 which limits the values allowed in that column to positive integers:
CREATE TABLE T1 (COL1 INT, COL2 INT CHECK (COL2>0), COL3 INT)

Given this table, the following statement:


INSERT INTO T1 VALUES (-1, -1, -1)

would fail because the value to be inserted into COL2 does not meet the check constraint; that is, -1 is not greater than 0. The following statement would be successful:
INSERT INTO T1 VALUES (1, 1, 1)

Once that row is inserted, the following statement would fail:


ALTER TABLE T1 ADD CONSTRAINT C1 CHECK (COL1=1 AND COL1<COL2)

This ALTER TABLE statement attempts to add a second check constraint which limits the value allowed in COL1 to 1 and also effectively rules that values in COL2 be greater than 1. This constraint would not be be allowed because the second part of the constraint is not met by the existing data (the value of 1 in COL2 is not less than the value of 1 in COL1).

Referential integrity
Referential integrity is the condition of a set of tables in a database in which all references from one table to another are valid.
Copyright IBM Corp. 2000

99

Consider the following example: (These sample tables are given in Appendix A. DB2 UDB for AS/400 Sample Tables: v CORPDATA.EMPLOYEE serves as a master list of employees. v CORPDATA.DEPARTMENT acts as a master list of all valid department numbers. v CORPDATA.EMP_ACT provides a master list of activities performed for projects. Other tables refer to the same entities described in these tables. When a table contains data for which there is a master list, that data should actually appear in the master list, or the reference is not valid. The table that contains the master list is the parent table, and the table that refers to it is a dependent table. When the references from the dependent table to the parent table are valid, the condition of the set of tables is called referential integrity. Stated another way, referential integrity is the state of a database in which all values of all foreign keys are valid. Each value of the foreign key must also exist in the parent key or be null. This definition of referential integrity requires an understanding of the following terms: v A unique key is a column or set of columns in a table which uniquely identify a row. Although a table can have several unique keys, no two rows in a table can have the same unique key value. v A primary key is a unique key that does not allow nulls. A table cannot have more than one primary key. v A parent key is either a unique key or a primary key which is referenced in a referential constraint. v A foreign key is a column or set of columns whose values must match those of a parent key. If any column value used to build the foreign key is null, then the rule does not apply. v A parent table is a table that contains the parent key. v A dependent table is the table that contains the foreign key. v A descendent table is a table that is a dependent table or a descendent of a dependent table. Enforcement of referential integrity prevents the violation of the rule which states that every non-null foreign key must have a matching parent key. SQL supports the referential integrity concept with the CREATE TABLE and ALTER TABLE statements. For detailed descriptions of these commands, see the SQL Reference book.

Adding or dropping referential constraints


Constraints on page 245 are rules that ensure that references from one table, a dependent table, to data in another table, the parent table, are valid. You use referential constraints to ensure Referential integrity on page 99. You can add referential constraints using Operations Navigator when creating a table. Or, use the SQL CREATE TABLE and ALTER TABLE statements to add or change referential constraints. With a referential constraint, non-null values of the foreign key are valid only if they also appear as values of a parent key. When you define a referential constraint, you specify:

100

DB2 UDB for AS/400 SQL Programming Concepts V4R5

v A primary or unique key v A foreign key v Delete and update rules that specify the action taken with respect to dependent rows when the parent row is deleted or updated. Optionally, you can specify a name for the constraint. If a name is not specified, one is automatically generated. Once a referential constraint is defined, the system enforces the constraint on every INSERT, DELETE, and UPDATE operation performed through SQL or any other interface including Operations Navigator, CL commands, utilities, or high-level language statements.

Example: Adding referential constraints


The rule that every department number shown in the sample employee table must appear in the department table is a referential constraint. This constraint ensures that every employee belongs to an existing department. The following SQL statements create the CORPDATA.DEPARTMENT and CORPDATA.EMPLOYEE tables with those constraint relationships defined.
CREATE TABLE CORPDATA.DEPARTMENT (DEPTNO CHAR(3) NOT NULL PRIMARY KEY, DEPTNAME VARCHAR(29) NOT NULL, MGRNO CHAR(6), ADMRDEPT CHAR(3) NOT NULL CONSTRAINT REPORTS_TO_EXISTS REFERENCES CORPDATA.DEPARTMENT (DEPTNO) ON DELETE CASCADE) CREATE TABLE CORPDATA.EMPLOYEE (EMPNO CHAR(6) NOT NULL PRIMARY KEY, FIRSTNAME VARCHAR(12) NOT NULL, MIDINIT CHAR(1) NOT NULL, LASTNAME VARCHAR(15) NOT NULL, WORKDEPT CHAR(3) CONSTRAINT WORKDEPT_EXISTS REFERENCES CORPDATA.DEPARTMENT (DEPTNO) ON DELETE SET NULL ON UPDATE RESTRICT, PHONENO CHAR(4), HIREDATE DATE, JOB CHAR(8), EDLEVEL SMALLINT NOT NULL, SEX CHAR(1), BIRTHDATE DATE, SALARY DECIMAL(9,2), BONUS DECIMAL(9,2), COMM DECIMAL(9,2), CONSTRAINT UNIQUE_LNAME_IN_DEPT UNIQUE (WORKDEPT, LASTNAME))

In this case, the DEPARTMENT table has a column of unique department numbers (DEPTNO) which functions as a primary key, and is a parent table in two constraint relationships: REPORTS_TO_EXISTS is a self-referencing constraint in which the DEPARTMENT table is both the parent and the dependent in the same relationship. Every non-null value of ADMRDEPT must match a value of DEPTNO. A department must report to an existing department in the database. The DELETE CASCADE rule indicates that if a row with a DEPTNO value n is deleted, every row in the table for which the ADMRDEPT is n is also deleted.

Chapter 6. Data Integrity

101

WORKDEPT_EXISTS establishes the EMPLOYEE table as a dependent table, and the column of employee department assignments (WORKDEPT) as a foreign key. Thus, every value of WORKDEPT must match a value of DEPTNO. The DELETE SET NULL rule says that if a row is deleted from DEPARTMENT in which the value of DEPTNO is n, then the value of WORKDEPT in EMPLOYEE is set to null in every row in which the value was n. The UPDATE RESTRICT rule says that a value of DEPTNO in DEPARTMENT cannot be updated if there are values of WORKDEPT in EMPLOYEE that match the current DEPTNO value. Constraint UNIQUE_LNAME_IN_DEPT in the EMPLOYEE table causes last names to be unique within a department. While this constraint is unlikely, it illustrates how a constraint made up of several columns can be defined at the table level.

Removing referential constraints


The ALTER TABLE statement can be used to add or drop one constraint at a time for a table. If the constraint being dropped is the parent key in some referential constraint relationship, the constraint between this parent file and any dependent files is also removed. DROP TABLE and DROP COLLECTION statements also remove any constraints on the table or collection being dropped.

Example: Removing Constraints


The following example removes the primary key over column DEPTNO in table DEPARTMENT. The constraints REPORTS_TO_EXISTS and WORKDEPT_EXISTS defined on tables DEPARTMENT and EMPLOYEE respectively will be removed as well, since the primary key being removed is the parent key in those constraint relationships.
ALTER TABLE CORPDATA.EMPLOYEE DROP PRIMARY KEY

You can also remove a constraint by name, as in the following example:


ALTER TABLE CORPDATA.DEPARTMENT DROP CONSTRAINT UNIQUE_LNAME_IN_DEPT

Inserting into tables with referential constraints


There are some important things to remember when inserting data into tables with referential constraints. If you are inserting data into a parent table with a parent key, SQL does not allow: v Duplicate values for the parent key v If the parent key is a primary key, a null value for any column of the primary key If you are inserting data into a dependent table with foreign keys: v Each non-null value you insert into a foreign key column must be equal to some value in the corresponding parent key of the parent table. v If any column in the foreign key is null, the entire foreign key is considered null. If all foreign keys that contain the column are null, the INSERT succeeds (as long as there are no unique index violations).

102

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Example: Inserting data with constraints


Alter the sample application project table (PROJECT) to define two foreign keys: v A foreign key on the department number (DEPTNO) which references the department table v A foreign key on the employee number (RESPEMP) which references the employee table.
ALTER TABLE CORPDATA.PROJECT ADD CONSTRAINT RESP_DEPT_EXISTS FOREIGN KEY (DEPTNO) REFERENCES CORPDATA.DEPARTMENT ON DELETE RESTRICT ALTER TABLE CORPDATA.PROJECT ADD CONSTRAINT RESP_EMP_EXISTS FOREIGN KEY (RESPEMP) REFERENCES CORPDATA.EMPLOYEE ON DELETE RESTRICT

Notice that the parent table columns are not specified in the REFERENCES clause. The columns are not required to be specified as long as the referenced table has a primary key or eligible unique key which can be used as the parent key. Every row inserted into the PROJECT table must have a value of DEPTNO that is equal to some value of DEPTNO in the department table. (The null value is not allowed because DEPTNO in the project table is defined as NOT NULL.) The row must also have a value of RESPEMP that is either equal to some value of EMPNO in the employee table or is null. The tables with the sample data as they appear in Appendix A. DB2 UDB for AS/400 Sample Tables conform to these constraints. The following INSERT statement fails because there is no matching DEPTNO value (A01) in the DEPARTMENT table.
INSERT INTO CORPDATA.PROJECT (PROJNO, PROJNAME, DEPTNO, RESPEMP) VALUES ('AD3120', 'BENEFITS ADMIN', 'A01', '000010')

Likewise, the following INSERT statement would be unsuccessful since there is no EMPNO value of 000011 in the EMPLOYEE table.
INSERT INTO CORPDATA.PROJECT (PROJNO, PROJNAME, DEPTNO, RESPEMP) VALUES ('AD3130', 'BILLING', 'D21', '000011')

The following INSERT statement completes successfully because there is a matching DEPTNO value of E01 in the DEPARTMENT table and a matching EMPNO value of 000010 in the EMPLOYEE table.
INSERT INTO CORPDATA.PROJECT (PROJNO, PROJNAME, DEPTNO, RESPEMP) VALUES ('AD3120', 'BENEFITS ADMIN', 'E01', '000010')

Updating tables with referential constraints


If you are updating a parent table, you cannot modify a primary key for which dependent rows exist. Changing the key violates referential constraints for dependent tables and leaves some rows without a parent. Furthermore, you cannot give any part of a primary key a null value.

Chapter 6. Data Integrity

103

Update Rules
The action taken on dependent tables when an UPDATE is performed on a parent table depends on the update rule specified for the referential constraint. If no update rule was defined for a referential constraint, the UPDATE NO ACTION rule is used. v UPDATE NO ACTION Specifies that the row in the parent table can be updated if no other row depends on it. If a dependent row exists in the relationship, the UPDATE fails. The check for dependent rows is performed at the end of the statement. v UPDATE RESTRICT Specifies that the row in the parent table can be updated if no other row depends on it. If a dependent row exists in the relationship, the UPDATE fails. The check for dependent rows is performed immediately. The subtle difference between RESTRICT and NO ACTION rules is easiest seen when looking at the interaction of triggers and referential constraints. Triggers can be defined to fire either before or after an operation (an UPDATE statement, in this case). A before trigger fires before the UPDATE is performed and therefore before any checking of constraints. An after trigger is fired after the UPDATE is performed, and after a constraint rule of RESTRICT (where checking is performed immediately), but before a constraint rule of NO ACTION (where checking is performed at the end of the statement). The triggers and rules would occur in the following order: 1. A before trigger would be fired before the UPDATE and before a constraint rule of RESTRICT or NO ACTION. 2. An after trigger would be fired after a constraint rule of RESTRICT, but before a NO ACTION rule. If you are updating a dependent table, any non-null foreign key values that you change must match the primary key for each relationship in which the table is a dependent. For example, department numbers in the employee table depend on the department numbers in the department table. You can assign an employee to no department (the null value), but not to a department that does not exist. If an UPDATE against a table with a referential constraint fails, all changes made during the update operation are undone. For more information on the implications of commitment control and journaling when working with constraints, see Journaling on page 239 and Commitment control on page 239.

Examples: UPDATE Rules


For example, you cannot update a department number from the department table if it is still responsible for some project, which is described by a dependent row in the project table. The following UPDATE fails because the PROJECT table has rows which are dependent on DEPARTMENT.DEPTNO having a value of D01 (the row targeted by the WHERE statement). If this UPDATE were allowed, the referential constraint between the PROJECT and DEPARTMENT tables would be broken.
UPDATE CORPDATA.DEPARTMENT SET DEPTNO = 'D99' WHERE DEPTNAME = 'DEVELOPMENT CENTER'

104

DB2 UDB for AS/400 SQL Programming Concepts V4R5

The following statement fails because it violates the referential constraint that exists between the primary key DEPTNO in DEPARTMENT and the foreign key DEPTNO in PROJECT:
UPDATE CORPDATA.PROJECT SET DEPTNO = 'D00' WHERE DEPTNO = 'D01';

The statement attempts to change all department numbers of D01 to department number D00. Since D00 is not a value of the primary key DEPTNO in DEPARTMENT, the statement fails.

Deleting from tables with referential constraints


If a table has a primary key but no dependents, DELETE operates as it does without referential constraints. The same is true if a table has only foreign keys, but no primary key. If a table has a primary key and dependent tables, DELETE deletes or updates rows according to the delete rules specified. All delete rules of all affected relationships must be satisfied in order for the delete operation to succeed. If a referential constraint is violated, the DELETE fails. The action to be taken on dependent tables when a DELETE is performed on a parent table depends on the delete rule specified for the referential constraint. If no delete rule was defined, the DELETE NO ACTION rule is used. v DELETE NO ACTION Specifies that the row in the parent table can be deleted if no other row depends on it. If a dependent row exists in the relationship, the DELETE fails. The check for dependent rows is performed at the end of the statement. v DELETE RESTRICT Specifies that the row in the parent table can be deleted if no other row depends on it. If a dependent row exists in the relationship, the DELETE fails. The check for dependent rows is performed immediately. For example, you cannot delete a department from the department table if it is still responsible for some project which is described by a dependent row in the project table. v DELETE CASCADE Specifies that first the designated rows in the parent table are deleted. Then, the dependent rows are deleted. For example, you can delete a department by deleting its row in the department table. Deleting the row from the department table also deletes: The rows for all departments that report to it All departments that report to those departments and so forth. v DELETE SET NULL Specifies that each nullable column of the foreign key in each dependent row is set to its default value. This means that the column is only set to its default value if it is a member of a foreign key that references the row being deleted. Only the dependent rows that are immediate descendents are affected. v DELETE SET DEFAULT Specifies that each column of the foreign key in each dependent row is set to its default value. This means that the column is only set to its default value if it is a member of a foreign key that references the row being deleted. Only the dependent rows that are immediate descendants are affected.

Chapter 6. Data Integrity

105

For example, you can delete an employee from the employee table even if the employee manages some department. In that case, the value of MGRNO for each employee who reported to the manager is set to blanks in the department table. If some other default value was specified on the create of the table, that value is used. This is due to the REPORTS_TO_EXISTS constraint defined for the department table. If a descendent table has a delete rule of RESTRICT or NO ACTION and a row is found such that a descendant row cannot be deleted, the entire DELETE fails. When running this statement with a program, the number of rows deleted is returned in SQLERRD(3) in the SQLCA. This number includes only the number of rows deleted in the table specified in the DELETE statement. It does not include those rows deleted according to the CASCADE rule. SQLERRD(5) in the SQLCA contains the number of rows that were affected by referential constraints in all tables. The subtle difference between RESTRICT and NO ACTION rules is easiest seen when looking at the interaction of triggers and referential constraints. Triggers can be defined to fire either before or after an operation (a DELETE statement, in this case). A before trigger fires before the DELETE is performed and therefore before any checking of constraints. An after trigger is fired after the DELETE is performed, and after a constraint rule of RESTRICT (where checking is performed immediately), but before a constraint rule of NO ACTION (where checking is performed at the end of the statement). The triggers and rules would occur in the following order: 1. A before trigger would be fired before the DELETE and before a constraint rule of RESTRICT or NO ACTION. 2. An after trigger would be fired after a constraint rule of RESTRICT, but before a NO ACTION rule.

Example: DELETE Cascade Rule


Deleting a department from the department table sets WORKDEPT (in the employee table) to null for every employee assigned to that department. Consider the following DELETE statement:
DELETE FROM CORPDATA.DEPARTMENT WHERE DEPTNO = 'E11'

Given the tables and the data as they appear in Appendix A. DB2 UDB for AS/400 Sample Tables, one row is deleted from table DEPARTMENT, and table EMPLOYEE is updated to set the value of WORKDEPT to its default wherever the value was E11. A question mark (?) in the sample data below reflects the null value. The results would appear as follows:
Table 16. DEPARTMENT Table. Contents of the table after the DELETE statement is complete. DEPTNO A00 B01 C01 D01 D11 DEPTNAME SPIFFY COMPUTER SERVICE DIV. PLANNING INFORMATION CENTER DEVELOPMENT CENTER MANUFACTURING SYSTEMS MGRNO 000010 000020 000030 ? 000060 ADMRDEPT A00 A00 A00 A00 D01

106

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Table 16. DEPARTMENT Table (continued). Contents of the table after the DELETE statement is complete. DEPTNO D21 E01 E21 DEPTNAME ADMINISTRATION SYSTEMS SUPPORT SERVICES SOFTWARE SUPPORT MGRNO 000070 000050 000100 ADMRDEPT D01 A00 E01

Note that there were no cascaded deletes in the DEPARTMENT table because no department reported to department E11. Below are snapshots of the affected portion of the EMPLOYEE table before and after the DELETE statement is completed.
Table 17. Partial EMPLOYEE Table. Partial contents before the DELETE statement. EMPNO 000230 000240 000250 000260 000270 000280 000290 000300 000310 000320 000330 000340 FIRSTNME MI JAMES J LASTNAME WORKDEPTPHONENO HIREDATE JEFFERSON MARINO SMITH JOHNSON PEREZ D21 D21 D21 D21 D21 2094 3780 0961 8953 9001 0997 4502 2095 3332 9990 2103 5696 1966-11-21 1979-12-05 1960-10-30 1975-09-11 1980-09-30 1967-03-24 1980-05-30 1972-06-19 1964-09-12 1965-07-07 1976-02-23 1947-05-05

SALVATORE M DANIEL SYBIL MARIA ETHEL JOHN PHILIP MAUDE RAMLAL WING JASON R S P L R R X F V

SCHNEIDER E11 PARKER SMITH SETRIGHT MEHTA LEE GOUNOT E11 E11 E11 E21 E21 E21

Table 18. Partial EMPLOYEE Table. Partial contents after the DELETE statement. EMPNO 000230 000240 000250 000260 000270 000280 000290 000300 000310 000320 000330 000340 FIRSTNME MI JAMES J LASTNAME WORKDEPTPHONENO HIREDATE JEFFERSON MARINO SMITH JOHNSON PEREZ D21 D21 D21 D21 D21 2094 3780 0961 8953 9001 0997 4502 2095 3332 9990 2103 5696 1966-11-21 1979-12-05 1960-10-30 1975-09-11 1980-09-30 1967-03-24 1980-05-30 1972-06-19 1964-09-12 1965-07-07 1976-02-23 1947-05-05

SALVATORE M DANIEL SYBIL MARIA ETHEL JOHN PHILIP MAUDE RAMLAL WING JASON R S P L R R X F V

SCHNEIDER ? PARKER SMITH SETRIGHT MEHTA LEE GOUNOT ? ? ? E21 E21 E21

Check pending
Referential constraints and check constraints can be in a state known as check pending, where potential violations of the constraint exist. For referential
Chapter 6. Data Integrity

107

constraints, a violation occurs when potential mismatches exist between parent and foreign keys. For check constraints, a violation occurs when potential values exist in columns which are limited by the check constraint. When the system determines that the constraint may have been violated (such as after a restore operation), the constraint is marked as check pending. When this happens, restrictions are placed on the use of tables involved in the constraint. For referential constraints, the following restrictions apply: v No input or output operations are allowed on the dependent file. v Only read and insert operations are allowed on the parent file. When a check constraint is in check pending, the following restrictions apply: v Read operations are not allowed on the file. v Inserts and updates are allowed and the constraint is enforced. To get a constraint out of check pending, you must: 1. Disable the relationship with the Change Physical File Constraint (CHGPFCST) CL command. 2. Correct the key (foreign, parent, or both) data for referential constraints or column data for check constraints. 3. Enable the constraint again with the CHGPFCST CL command. You can identify the rows that are in violation of the constraint with the Display Check Pending Constraint (DSPCPCST) CL command. For more information on working with tables in check pending, see the Database Programming book.

WITH CHECK OPTION on a View


WITH CHECK OPTION is an optional clause on the CREATE VIEW statement that specifies the level of checking to be done when inserting or updating data through a view. If the option is specified, every row that is inserted or updated through the view must conform to the definition of that view. WITH CHECK OPTION cannot be specified if the view is read-only. The definition of the view must not include a subquery. If the view is created without a WITH CHECK OPTION clause, insert and update operations that are performed on the view are not checked for conformance to the view definition. Some checking might still occur if the view is directly or indirectly dependent on another view that includes WITH CHECK OPTION. Because the definition of the view is not used, rows might be inserted or updated through the view that do not conform to the definition of the view. This means that the rows could not be selected again using the view. The checking can either be CASCADED or LOCAL. See the SQL Reference book for additional discussion of WITH CHECK OPTION.

WITH CASCADED CHECK OPTION


The WITH CASCADED CHECK OPTION specifies that every row that is inserted or updated through the view must conform to the definition of the view. In

108

DB2 UDB for AS/400 SQL Programming Concepts V4R5

addition, the search conditions of all dependent views are checked when a row is inserted or updated. If a row does not conform to the definition of the view, that row cannot be retrieved using the view. For example, consider the following updateable view:
CREATE VIEW V1 AS SELECT COL1 FROM T1 WHERE COL1 > 10

Because no WITH CHECK OPTION is specified, the following INSERT statement is successful even though the value being inserted does not meet the search condition of the view.
INSERT INTO V1 VALUES (5)

Create another view over V1, specifying the WITH CASCADED CHECK OPTION:
CREATE VIEW V2 AS SELECT COL1 FROM V1 WITH CASCADED CHECK OPTION

The following INSERT statement fails because it would produce a row that does not conform to the definition of V2:
INSERT INTO V2 VALUES (5)

Consider one more view created over V2:


CREATE VIEW V3 AS SELECT COL1 FROM V2 WHERE COL1 < 100

The following INSERT statement fails only because V3 is dependent on V2, and V2 has a WITH CASCADED CHECK OPTION.
INSERT INTO V3 VALUES (5)

However, the following INSERT statement is successful because it conforms to the definition of V2. Because V3 does not have a WITH CASCADED CHECK OPTION, it does not matter that the statement does not conform to the definition of V3.
INSERT INTO V3 VALUES (200)

WITH LOCAL CHECK OPTION


WITH LOCAL CHECK OPTION is identical to WITH CASCADED CHECK OPTION except that you can update a row so that it no longer can be retrieved through the view. This can only happen when the view is directly or indirectly dependent on a view that was defined with no WITH CHECK OPTION clause. For example, consider the same updateable view used in the previous example:
CREATE VIEW V1 AS SELECT COL1 FROM T1 WHERE COL1 > 10

Create second view over V1, this time specifying WITH LOCAL CHECK OPTION:
CREATE VIEW V2 AS SELECT COL1 FROM V1 WITH LOCAL CHECK OPTION

The same INSERT that failed in the previous CASCADED CHECK OPTION example would succeed now because V2 does not have any search conditions, and the search conditions of V1 do not need to be checked since V1 does not specify a check option.
INSERT INTO V2 VALUES (5)
Chapter 6. Data Integrity

109

If we again consider one more view created over V2:


CREATE VIEW V3 AS SELECT COL1 FROM V2 WHERE COL1 < 100

The following INSERT is successful again because the search condition on V1 is not checked due to the WITH LOCAL CHECK OPTION on V2, versus the WITH CASCADED CHECK OPTION in the previous example.
INSERT INTO V3 VALUES (5)

The difference between LOCAL and CASCADED CHECK OPTION lies in how many of the dependent views search conditions are checked when a row is inserted or updated. v WITH LOCAL CHECK OPTION specifies that the search conditions of only those dependent views that have the WITH LOCAL CHECK OPTION or WITH CASCADED CHECK OPTION are checked when a row is inserted or updated. v WITH CASCADED CHECK OPTION specifies that the search conditions of all dependent views are checked when a row is inserted or updated.

Example: Cascaded check option


Use the following table and views:
CREATE TABLE T1 (COL1 CHAR(10)) CREATE VIEW V1 AS SELECT COL1 FROM T1 WHERE COL1 LIKE 'A%' CREATE VIEW V2 AS SELECT COL1 FROM V1 WHERE COL1 LIKE '%Z' WITH LOCAL CHECK OPTION CREATE VIEW V3 AS SELECT COL1 FROM V2 WHERE COL1 LIKE 'AB%' CREATE VIEW V4 AS SELECT COL1 FROM V3 WHERE COL1 LIKE '%YZ' WITH CASCADED CHECK OPTION CREATE VIEW V5 AS SELECT COL1 FROM V4 WHERE COL1 LIKE 'ABC%'

Different search conditions are going to be checked depending on which view is being operated on with an INSERT or UPDATE. v If V1 is operated on, no conditions are checked because V1 does not have a WITH CHECK OPTION specified. v If V2 is operated on, COL1 must end in the letter Z, but it doesnt have to start with the letter A. This is because the check option is LOCAL, and view V1 does not have a check option specified. v If V3 is operated on, COL1 must end in the letter Z, but it does not have to start with the letter A. V3 does not have a check option specified, so its own search condition must not be met. However, the search condition for V2 must be checked since V3 is defined on V2, and V2 has a check option. v If V4 is operated on,

110

DB2 UDB for AS/400 SQL Programming Concepts V4R5

COL1 must start with AB, and must end with YZ. Because V4 has the WITH CASCADED CHECK OPTION specified, every search condition for every view on which V4 is dependent must be checked. v If V5 is operated on, COL1 must start with AB, but not necessarily ABC. This is because V5 does not specify a check option, so its own search condition does not need to be checked. However, because V5 is defined on V4, and V4 had a cascaded check option, every search condition for V4, V3, V2, and V1 must be checked. That is, COL1 must start with AB and end with YZ. If V5 were created WITH LOCAL CHECK OPTION, operating on V5 would mean that COL1 must start with ABC and end with YZ. The LOCAL CHECK OPTION adds the additional requirement that the third character must be a C.

DB2 UDB for AS/400 trigger support


A trigger is a set of actions that are run automatically when a specified change operation is performed on a specified physical database file. In this discussion, a table is a physical file. The change operation can be an insert, update, or delete high level language statement in an application program, or an SQL INSERT, UPDATE, or DELETE statement. Triggers are useful for tasks such as enforcing business rules, validating input data, and keeping an audit trail. In DB2 UDB for AS/400, the program containing the set of trigger actions can be defined in any supported high level language. The trigger program can have SQL embedded in it. To use trigger support, you must create a trigger program and add it to a physical file using the ADDPFTRG CL command. To add a trigger to a file, you must: v Identify the physical file v Identify the kind of operation v Identify the program that performs the desired actions. There is no SQL statement to associate a physical file with a trigger program. SQL is only involved in that the trigger program can contain embedded SQL statements, and that it could be an SQL INSERT, UPDATE, or DELETE that causes the trigger to be fired. Once a trigger program is associated with a physical file, the system trigger support calls the trigger program when a change operation is initiated against the physical file or table, or any logical file or view created over the physical file. Each change operation can call a trigger before or after the change operation occurs. Thus, a physical file can be associated with a maximum of six triggers v Before delete trigger v v v v v Before insert trigger Before update trigger After delete trigger After insert trigger After update trigger

Chapter 6. Data Integrity

111

Trigger sample
A sample trigger program follows. It is written in ILE C, with embedded SQL. See the Database Programming book for a full discussion and more examples of trigger usage in DB2 UDB for AS/400.
#include "string.h" #include "stdlib.h" #include "stdio.h" #include <recio.h> #include <xxcvt.h> #include "qsysinc/h/trgbuf" /* Trigger input parameter */ #include "lib1/csrc/msghand1" /* User defined message handler */ /*********************************************************************/ /* This is a trigger program which is called whenever there is an */ /* update to the EMPLOYEE table. If the employee's commission is */ /* greater than the maximum commission, this trigger program will */ /* increase the employee's salary by 1.04 percent and insert into */ /* the RAISE table. */ /* */ /* The EMPLOYEE record information is passed from the input parameter*/ /* to this trigger program. */ /*********************************************************************/ Qdb_Trigger_Buffer_t *hstruct; char *datapt; /*******************************************************/ /* Structure of the EMPLOYEE record which is used to */ /* store the old or the new record that is passed to */ /* this trigger program. */ /* */ /* Note : You must ensure that all the numeric fields */ /* are aligned at 4 byte boundary in C. */ /* Used either Packed struct or filler to reach */ /* the byte boundary alignment. */ /*******************************************************/ _Packed struct rec{ char empn[6]; _Packed struct { short fstlen ; char fstnam[12]; } fstname; char minit[1]; _Packed struct { short lstlen; char lstnam[15]; } lstname; char dept[3]; char phone[4]; char hdate[10]; char jobn[8]; short edclvl; char sex1[1]; char bdate[10]; decimal(9,2) salary1; decimal(9,2) bonus1; decimal(9,2) comm1; } oldbuf, newbuf; EXEC SQL INCLUDE SQLCA; Figure 2. Sample Trigger Program (Part 1 of 5)

112

DB2 UDB for AS/400 SQL Programming Concepts V4R5

main(int argc, char **argv) { int i; int obufoff; /* int nuloff; /* int nbufoff; /* int nul2off; /* short work_days = 253; /* decimal(9,2) commission = 2000.00; /* decimal(9,2) percentage = 1.04; /* char raise_date[12] = "1982-06-01";/* struct { char empno[6]; char name[30]; decimal(9,2) salary; decimal(9,2) new_salary; } rpt1;

old buffer offset old null byte map offset new buffer offset new null byte map offset work days during in one year cutoff to qualify for raised salary as percentage effective raise date

*/ */ */ */ */ */ */ */

/*******************************************************/ /* Start to monitor any exception. */ /*******************************************************/ _FEEDBACK fc; _HDLR_ENTRY hdlr = main_handler; /****************************************/ /* Make the exception handler active. */ /****************************************/ CEEHDLR(&hdlr, NULL, &fc); /****************************************/ /* Ensure exception handler OK */ /****************************************/ if (fc.MsgNo != CEE0000) { printf("Failed to register exception handler.\n"); exit(99); }; /*******************************************************/ /* Move the data from the trigger buffer to the local */ /* structure for reference. */ /*******************************************************/ hstruct = (Qdb_Trigger_Buffer_t *)argv[1]; datapt = (char *) hstruct; obufoff = hstruct ->Old_Record_Offset; /* old buffer memcpy(&oldbuf,datapt+obufoff,; hstruct->Old_Record_Len); nbufoff = hstruct ->New_Record_Offset; /* new buffer memcpy(&newbuf,datapt+nbufoff,; hstruct->New_Record_Len); Figure 2. Sample Trigger Program (Part 2 of 5) */ */

Chapter 6. Data Integrity

113

EXEC SQL WHENEVER SQLERROR

GO TO ERR_EXIT;

/*******************************************************/ /* Set the transaction isolation level to the same as */ /* the application based on the input parameter in the */ /* trigger buffer. */ /*******************************************************/ if(strcmp(hstruct->Commit_Lock_Level,"0") == 0) EXEC SQL SET TRANSACTION ISOLATION LEVEL NONE; else{ if(strcmp(hstruct->Commit_Lock_Level,"1") == 0) EXEC SQL SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED, READ WRITE; else { if(strcmp(hstruct->Commit_Lock_Level,"2") == 0) EXEC SQL SET TRANSACTION ISOLATION LEVEL READ COMMITTED; else if(strcmp(hstruct->Commit_Lock_Level,"3") == 0) EXEC SQL SET TRANSACTION ISOLATION LEVEL ALL; } } /********************************************************/ /* If the employee's commission is greater than maximum */ /* commission, then increase the employee's salary */ /* by 1.04 percent and insert into the RAISE table. */ /********************************************************/ if (newbuf.comm1 >= commission) { EXEC SQL SELECT EMPNO, EMPNAME, SALARY INTO :rpt1.empno, :rpt1.name, :rpt1.salary FROM TRGPERF/EMP_ACT WHERE EMP_ACT.EMPNO=:newbuf.empn ; if (sqlca.sqlcode == 0) then { rpt1.new_salary = salary * percentage; EXEC SQL INSERT INTO TRGPERF/RAISE VALUES(:rpt1); } goto finished;

} err_exit: exit(1);

/* All done */ finished: return; } /* end of main line

*/

Figure 2. Sample Trigger Program (Part 3 of 5)

114

DB2 UDB for AS/400 SQL Programming Concepts V4R5

/******************************************************************/ /* INCLUDE NAME : MSGHAND1 */ /* */ /* DESCRIPTION : Message handler to signal an exception to */ /* the application to inform that an */ /* error occured in the trigger program. */ /* */ /* NOTE : This message handler is a user defined routine. */ /* */ /******************************************************************/ #include <stdio.h> #include <stdlib.h> #include <recio.h> #include <leawi.h> #pragma linkage (QMHSNDPM, OS) void QMHSNDPM(char *, void *, void *, int, char *, char *, int, void *, void *, ...); Message identifier */ Qualified message file name */ Message data or text */ Length of message data or text */ Message type */ Call message queue */ Call stack counter */ Message key */ Error code */ Optionals: length of call message queue name Call stack entry qualification display external messages screen wait time */ /*********************************************************************/ /******** This is the start of the exception handler function. */ /*********************************************************************/ void main_handler(_FEEDBACK *cond, _POINTER *token, _INT4 *rc, _FEEDBACK *new) { /****************************************/ /* Initialize variables for call to */ /* QMHSNDPM. */ /* User must create a message file and */ /* define a message ID to match the */ /* following data. */ /****************************************/ char message_id[7] = "TRG9999"; char message_file[20] = "MSGF LIB1 "; char message_data[50] = "Trigger error " ; int message_len = 30; char message_type[10] = "*ESCAPE "; char message_q[10] = "_C_pep "; int pgm_stack_cnt = 1; char message_key[4]; Figure 2. Sample Trigger Program (Part 4 of 5) /* /* /* /* /* /* /* /* /* /*

Chapter 6. Data Integrity

115

struct error_code { int bytes_provided; int bytes_available; char message_id[7]; } error_code;

/****************************************/ /* Declare error code structure for */ /* QMHSNDPM. */ /****************************************/

error_code.bytes_provided = 15; /****************************************/ /* Set the error handler to resume and */ /* mark the last escape message as */ /* handled. */ /****************************************/ *rc = CEE_HDLR_RESUME; /****************************************/ /* Send my own *ESCAPE message. */ /****************************************/ QMHSNDPM(message_id, &message_file, &message_data, message_len, message_type, message_q, pgm_stack_cnt, &message_key, &error_code ); /****************************************/ /* Check that the call to QMHSNDPM */ /* finished correctly. */ /****************************************/ if (error_code.bytes_available != 0) { printf("Error in QMHOVPM : %s\n", error_code.message_id); } } Figure 2. Sample Trigger Program (Part 5 of 5)

116

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Chapter 7. Stored Procedures


DB2 SQL for AS/400 stored procedure support provides a way for an SQL application to define and then invoke a procedure through SQL statements. Stored procedures can be used in both distributed and non-distributed DB2 SQL for AS/400 applications. One of the big advantages in using stored procedures is that for distributed applications, the execution of one CALL statement on the application requester, or client, can perform any amount of work on the application server. You may define a procedure as either an SQL procedure or an external procedure. An external procedure can be any supported high level language program (except System/36* programs and procedures) or a REXX procedure. The procedure does not need to contain SQL statements, but it may contain SQL statements. An SQL procedure is defined entirely in SQL, and can contain SQL statements that include SQL control statements. Coding stored procedures requires that the user understand the following: v Stored procedure definition through the CREATE PROCEDURE statement v Stored procedure invocation through the CALL statement v Parameter passing conventions v Methods for returning a completion status to the program invoking the procedure. You may define stored procedures by using the CREATE PROCEDURE statement. The CREATE PROCEDURE statement adds procedure and parameter definitions to the catalog tables SYSROUTINES and SYSPARMS. These definitions are then accessible by any SQL CALL statement on the system. The following sections describe the SQL statements used to define and invoke the stored procedure, information on passing parameters to the stored procedure, and examples of stored procedure usage.

Creating a procedure
A procedure (often called a stored procedure) is a program that can be called to perform operations that can include both host language statements and SQL statements. Procedures in SQL provide the same benefits as procedures in a host language. That is, a common piece of code need only be written and maintained once and can be called from several programs. To create an external procedure or an SQL procedure, you can use the SQL CREATE PROCEDURE statement. Or, you can use Operations Navigator.

Defining an external procedure


The CREATE PROCEDURE statement for an external procedure: v Names the procedure v Defines the parameters and their attributes

Copyright IBM Corp. 2000

117

v Gives other information about the procedure which will the system uses when it calls the procedure. Consider the following example:
EXEC SQL CREATE PROCEDURE P1 (INOUT PARM1 CHAR(10)) EXTERNAL NAME MYLIB.PROC1 LANGUAGE C GENERAL WITH NULLS;

This CREATE PROCEDURE statement: v Names the procedure P1 v Defines one parameter which is used both as an input parameter and an output parameter. The parameter is a character field of length ten. Parameters can be defined to be type IN, OUT, or INOUT. The parameter type determines when the values for the parameters get passed to and from the procedure. v Defines the name of the program which corresponds to the procedure, which is PROC1 in MYLIB. MYLIB.PROC1 is the program which is called when the procedure is invoked on a CALL statement. v Indicates that the procedure P1 (program MYLIB.PROC1) is written in C. The language is important since it impacts the types of parameters that can be passed. It also affects how the parameters are passed to the procedure (for example, for ILE C procedures, a NUL-terminator is passed on character, graphic, date, time, and timestamp parameters). v Defines the CALL type to be GENERAL WITH NULLS. This indicates that the parameter for the procedure can possibly contain the NULL value, and therefore would like an additional argument passed to the procedure on the CALL statement. The additional argument is an array of N short integers, where N is the number of parameters that are declared in the CREATE PROCEDURE statement. In this example, the array contains only one element since there is only parameter. It is important to note that it is not necessary to define a procedure in order to call it. However, if no procedure definition is found, either from a prior CREATE PROCEDURE or from a DECLARE PROCEDURE in this program, certain restrictions and assumptions are made when the procedure is invoked on the CALL statement. For example, the NULL indicator argument cannot be passed. See Using Embedded CALL Statement where no procedure definition exists on page 125 for an example of a CALL statement without a corresponding procedure definition.

Defining an SQL procedure


The CREATE PROCEDURE statement for SQL procedures: v Names the procedure v Defines the parameters and their attributes v Provides other information about the procedure which will be used when the procedure is called v Defines the procedure body. The procedure body is the executable part of the procedure and is a single SQL statement.

118

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Consider the following simple example that takes as input an employee number and a rate and updates the employees salary:
EXEC SQL CREATE PROCEDURE UPDATE_SALARY_1 (IN EMPLOYEE_NUMBER CHAR(10), IN RATE DECIMAL(6,2)) LANGUAGE SQL MODIFIES SQL DATA UPDATE CORPDATA.EMPLOYEE SET SALARY = SALARY * RATE WHERE EMPNO = EMPLOYEE_NUMBER;

This CREATE PROCEDURE statement: v Names the procedure UPDATE_SALARY_1. v Defines parameter EMPLOYEE_NUMBER which is an input parameter and is a character data type of length 6 and parameter RATE which is an input parameter and is a decimal data type. v Indicates the procedure is an SQL procedure that modifies SQL data. v Defines the procedure body as a single UPDATE statement. When the procedure is called, the UPDATE statement is executed using the values passed for EMPLOYEE_NUMBER and RATE. Instead of a single UPDATE statement, logic can be added to the SQL procedure using SQL control statements. SQL control statements consist of the following: v an assignment statement v a CALL statement v v v v v a CASE statement a compound statement a FOR statement an IF statement a LOOP statement

v a REPEAT statement v a WHILE statement The following example takes as input the employee number and a rating that was received on the last evaluation. The procedure uses a CASE statement to determine the appropriate increase and bonus for the update:
EXEC SQL CREATE PROCEDURE UPDATE_SALARY_2 (IN EMPLOYEE_NUMBER CHAR(6), IN RATING INT) LANGUAGE SQL MODIFIES SQL DATA CASE RATING WHEN 1 THEN UPDATE CORPDATA.EMPLOYEE SET SALARY = SALARY * 1.10, BONUS = 1000 WHERE EMPNO = EMPLOYEE_NUMBER; WHEN 2 THEN UPDATE CORPDATA.EMPLOYEE SET SALARY = SALARY * 1.05, BONUS = 500 WHERE EMPNO = EMPLOYEE_NUMBER; ELSE UPDATE CORPDATA.EMPLOYEE SET SALARY = SALARY * 1.03, BONUS = 0 WHERE EMPNO = EMPLOYEE_NUMBER; END CASE;

Chapter 7. Stored Procedures

119

This CREATE PROCEDURE statement: v Names the procedure UPDATE_SALARY_2. v Defines parameter EMPLOYEE_NUMBER which is an input parameter and is a character data type of length 6 and parameter RATING which is an input parameter and is an integer data type. v Indicates the procedure is an SQL procedure that modifies SQL data. v Defines the procedure body. When the procedure is called, input parameter RATING is checked and the appropriate update statement is executed. Multiple statements can be added to a procedure body by adding a compound statement. Within a compound statement, any number of SQL statements can be specified. In addition, SQL variables, cursors, and handlers can be declared. The following example takes as input the department number. It returns the total salary of all the employees in that department and the number of employees in that department who get a bonus.
EXEC SQL CREATE PROCEDURE RETURN_DEPT_SALARY (IN DEPT_NUMBER CHAR(3), OUT DEPT_SALARY DECIMAL(15,2), OUT DEPT_BONUS_CNT INT) LANGUAGE SQL READS SQL DATA P1: BEGIN DECLARE EMPLOYEE_SALARY DECIMAL(9,2); DECLARE EMPLOYEE_BONUS DECIMAL(9,2); DECLARE TOTAL_SALARY DECIMAL(15,2)DEFAULT 0 DECLARE BONUS_CNT INT DEFAULT 0; DECLARE END_TABLE INT DEFAULT 0; DECLARE C1 CURSOR FOR SELECT SALARY, BONUS FROM CORPDATA.EMPLOYEE WHERE WORKDEPT = DEPT_NUMBER; DECLARE CONTINUE HANDLER FOR NOT FOUND SET END_TABLE = 1; DECLARE EXIT HANDLER FOR SQLEXCEPTION SET DEPT_SALARY = NULL; OPEN C1; FETCH C1 INTO EMPLOYEE_SALARY, EMPLOYEE_BONUS; WHILE END_TABLE = 0 DO SET TOTAL_SALARY = TOTAL_SALARY + EMPLOYEE_SALARY + EMPLOYEE_BONUS; IF EMPLOYEE_BONUS > 0 THEN SET BONUS_CNT = BONUS_CNT + 1; END IF; FETCH C1 INTO EMPLOYEE_SALARY, EMPLOYEE_BONUS; END WHILE; CLOSE C1; SET DEPT_SALARY = TOTAL_SALARY; SET DEPT_BONUS_CNT = BONUS_CNT; END P1;

This CREATE PROCEDURE statement: v Names the procedure RETURN_DEPT_SALARY. v Defines parameter DEPT_NUMBER which is an input parameter and is a character data type of length 3, parameter DEPT_SALARY which is an output parameter and is a decimal data type, and parameter DEPT_BONUS_CNT which is an output parameter and is an integer data type. v Indicates the procedure is an SQL procedure that reads SQL data v Defines the procedure body. Declares SQL variables EMPLOYEE_SALARY and TOTAL_SALARY as decimal fields.

120

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Declares SQL variables BONUS_CNT and END_TABLE which are integers and are initialized to 0. Declares cursor C1 that selects the columns from the employee table. Declares a continue handler for NOT FOUND, which, when invoked sets variable END_TABLE to 1. This handler is invoked when the FETCH has no more rows to return. When the handler is invoked, SQLCODE and SQLSTATE are reinitialized to 0. Declares an exit handler for SQLEXCEPTION. If invoked, DEPT_SALARY is set to NULL and the processing of the compound statement is terminated. This handler is invoked if any errors occur, ie, the SQLSTATE class is not 00, 01 or 02. Since indicators are always passed to SQL procedures, the indicator value for DEPT_SALARY is 1 when the procedure returns. If this handler is invoked, SQLCODE and SQLSTATE are reinitialized to 0. If the handler for SQLEXCEPTION is not specified and an error occurs that is not handled in another handler, execution of the compound statement is terminated and the error is returned in the SQLCA. Similar to indicators, the SQLCA is always returned from SQL procedures. Includes an OPEN, FETCH, and CLOSE of cursor C1. If a CLOSE of the cursor is not specified, the cursor is closed at the end of the compound statement since SET RESULT SETS is not specified in the CREATE PROCEDURE statement. Includes a WHILE statement which loops until the last record is fetched. For each row retrieved, the TOTAL_SALARY is incremented and, if the employees bonus is more than 0, the BONUS_CNT is incremented. Returns DEPT_SALARY and DEPT_BONUS_CNT as output parameters. Compound statements can be made atomic so if an error occurs that is not expected, the statements within the atomic statement are rolled back. When a procedure that contains an atomic compound statement is called, the transaction must be at a commit boundary. If the compound statement is successful, the transaction is committed. The following example takes as input the department number. It ensures the EMPLOYEE_BONUS table exists, and inserts the name of all employees in the department who get a bonus. The procedure returns the total count of all employees who get a bonus.
EXEC SQL CREATE PROCEDURE CREATE_BONUS_TABLE (IN DEPT_NUMBER CHAR(3), INOUT CNT INT) LANGUAGE SQL MODIFIES SQL DATA CS1: BEGIN ATOMIC DECLARE NAME VARCHAR(30) DEFAULT NULL; DECLARE CONTINUE HANDLER FOR SQLSTATE '42710' SELECT COUNT(*) INTO CNT FROM DATALIB.EMPLOYEE_BONUS; DECLARE CONTINUE HANDLER FOR SQLSTATE '23505' SET CNT = CNT + 1; DECLARE UNDO HANDLER FOR SQLEXCEPTION SET CNT = NULL; IF DEPT_NUMBER IS NOT NULL THEN CREATE TABLE DATALIB.EMPLOYEE_BONUS (FULLNAME VARCHAR(30), BONUS DECIMAL(10,2), PRIMARY KEY (FULLNAME)); FOR_1:FOR V1 AS C1 CURSOR FOR SELECT FIRSTNME, MIDINIT, LASTNAME, BONUS FROM CORPDATA.EMPLOYEE
Chapter 7. Stored Procedures

| |

| |

121

| |

WHERE WORKDEPT = CREATE_BONUS_TABLE.DEPT_NUMBER; DO IF BONUS > 0 THEN SET NAME = FIRSTNME CONCAT ' ' CONCAT MIDINIT CONCAT ' 'CONCAT LASTNAME; INSERT INTO DATALIB.EMPLOYEE_BONUS VALUES(CS1.NAME, FOR_1.BONUS); SET CNT = CNT + 1; END IF; END FOR FOR_1; END IF; END CS1;

This CREATE PROCEDURE statement: v Names the procedure CREATE_BONUS_TABLE. v Defines parameter DEPT_NUMBER which is an input parameter and is a character data type of length 3 and parameter CNT which is an input/output parameter and is an integer data type. v Indicates the procedure is an SQL procedure that modifies SQL data v Defines the procedure body. Declares SQL variable NAME as varying character. Declares a continue handler for SQLSTATE 42710, table already exists. If the EMPLOYEE_BONUS table already exists, the handler is invoked and retrieves the number of records in the table. The SQLCODE and SQLSTATE are reset to 0 and processing continues with the FOR statement. Declares a continue handler for SQLSTATE 23505, duplicate key. If the procedure attempts to insert a name that already exists in the table, the handler is invoked and decrements CNT. Processing continues on the SET statement following the INSERT statement. Declares an UNDO handler for SQLEXCEPTION. If invoked, the previous statements are rolled back, CNT is set to 0, and processing continues after the compound statement. In this case, since there is no statement following the compound statement, the procedure returns. Uses the FOR statement to declare cursor C1 to read the records from the EMPLOYEE table. Within the FOR statement, the column names from the select list are used as SQL variables that contain the data from the row fetched. For each row, data from columns FIRSTNME, MIDINIT, and LASTNAME are concatenated together with a blank in between and the result is put in SQL variable NAME. SQL variables NAME and BONUS are inserted into the EMPLOYEE_BONUS table. Because the data type of the select list items must be known when the procedure is created, the table specified in the FOR statement must exist when the procedure is created. An SQL variable name can be qualified with the label name of the FOR statement or compound statement in which it is defined. In the example, FOR_1.BONUS refers to the SQL variable that contains the value of column BONUS for each row selected. CS1.NAME is the variable NAME defined in the compound statement with the beginning label CS1. Parameter names can also be qualified with the procedure name. CREATE_BONUS_TABLE.DEPT_NUMBER is the DEPT_NUMBER parameter for the procedure CREATE_BONUS_TABLE. If unqualified SQL variable names are used in SQL statements where column names are also allowed, and the variable name is the same as a column name, the name will be used to refer to the column.

122

DB2 UDB for AS/400 SQL Programming Concepts V4R5

You can also use dynamic SQL in an SQL procedure. The following example creates a table that contains all employees in a specific department. The department number is passed as input to the procedure and is concatenated to the table name.
CREATE PROCEDURE CREATE_DEPT_TABLE (IN P_DEPT CHAR(3)) LANGUAGE SQL BEGIN DECLARE STMT CHAR(1000); DECLARE MESSAGE CHAR(20); DECLARE TABLE_NAME CHAR(30); DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET MESSAGE = 'ok'; SET TABLE_NAME = 'CORPDATA.DEPT_' CONCAT P_DEPT CONCAT '_T'; SET STMT = 'DROP TABLE ' CONCAT TABLE_NAME; PREPARE S1 FROM STMT; EXECUTE S1; SET STMT = 'CREATE TABLE ' CONCAT TABLE_NAME CONCAT '( EMPNO CHAR(6) NOT NULL, FIRSTNME VARCHAR(12) NOT NULL, MIDINIT CHAR(1) NOT NULL, LASTNAME CHAR(15) NOT NULL, SALARY DECIMAL(9,2))'; PREPARE S2 FROM STMT; EXECUTE S2; SET STMT = 'INSERT INTO ' CONCAT TABLE_NAME CONCAT 'SELECT EMPNO, FIRSTNME, MIDINIT, LASTNAME, SALARY FROM CORPDATA.EMPLOYEE WHERE WORKDEPT = ?'; PREPARE S3 FROM STMT; EXECUTE S3 USING P_DEPT; END;

| | | |

| |

This CREATE PROCEDURE statement: v Names the procedure CREATE_DEPT_TABLE v Defines parameter P_DEPT which is an input parameter and is a character data type of length 3. v Indicates the procedure is an SQL procedure. v Defines the procedure body. Declares SQL variable STMT and an SQL variable TABLE_NAME as character. Declares a CONTINUE handler. The procedure attempts to DROP the table in case it already exists. If the table does not exist, the first EXECUTE would fail. With the handler, processing will continue. Sets variable TABLE_NAME to DEPT_ followed by the characters passed in parameter P_DEPT, followed by _T. Sets variable STMT to the DROP statement, and prepares and executes the statement. Sets variable STMT to the CREATE statement, and prepares and executes the statement. Sets variable STMT to the INSERT statement, and prepares and executes the statement. A parameter marker is specified in the where clause. When the statement is executed, the variable P_DEPT is passed on the USING clause. If the procedure is called passing value D21 for the department, table DEPT_D21_T is created and the table is initialized with all the employees that are in department D21.

Chapter 7. Stored Procedures

123

Invoking a stored procedure


The CALL statement invokes a stored procedure. On the CALL statement, the name of the stored procedure and any arguments are specified. Arguments may be constants, special registers, or host variables. The external stored procedure specified in the CALL statement does not need to have a corresponding CREATE PROCEDURE statement. Programs created by SQL procedures can only be called by invoking the procedure name specified on the CREATE PROCEDURE statement. There are three types of CALL statements which need to be addressed since DB2 SQL for AS/400 has different rules for each type. They are: v Embedded or dynamic CALL statement where a procedure definition exists v Embedded CALL statement where no procedure definition exists v Dynamic CALL statement where no CREATE PROCEDURE exists Note: Dynamic here refers to: v A dynamically prepared and executed CALL statement v A CALL statement issued in an interactive environment (for example, through STRSQL or Query Manager) v A CALL statement executed in an EXECUTE IMMEDIATE statement. Following is a discussion of each type.

Using CALL Statement where procedure definition exists


This type of CALL statement gets all the information about the procedure and the argument attributes from the CREATE PROCEDURE catalog definition. The following PL/I example shows a CALL statement which corresponds to the CREATE PROCEDURE statement shown.
DCL HV1 CHAR(10); DCL IND1 FIXED BIN(15); : EXEC SQL CREATE P1 PROCEDURE (INOUT PARM1 CHAR(10)) EXTERNAL NAME MYLIB.PROC1 LANGUAGE C GENERAL WITH NULLS; : EXEC SQL CALL P1 (:HV1 :IND1); :

When this CALL statement is invoked, a call to program MYLIB/PROC1 is made and two arguments are passed. Since the language of the program is ILE C, the first argument is a C NUL-terminated string eleven characters long containing the contents of host variable HV1. Note that on a call to an ILE C procedure, DB2 SQL for AS/400 adds one character to the parameter declaration if the parameter is declared to be a character, graphic, date, time, or timestamp variable. The second argument is the indicator array. In this case, it is one short integer since there is only one parameter in the CREATE PROCEDURE statement. This argument contains the contents of indicator variable IND1 on entry to the procedure. Since the first parameter is declared as INOUT, SQL updates the host variable HV1 and the indicator variable IND1 with the values returned from MYLIB.PROC1 before returning to the user program.

124

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Note: The procedure names specified on the CREATE PROCEDURE and CALL statements must match EXACTLY in order for the link between the two to be made during the SQL precompile of the program. Note: For an embedded CALL statement where both a CREATE PROCEDURE and a DECLARE PROCEDURE statement exist, the DECLARE PROCEDURE statement will be used.

Using Embedded CALL Statement where no procedure definition exists


A static CALL statement without a corresponding CREATE PROCEDURE statement is processed with the following rules: v All host variable arguments are treated as INOUT type parameters. v The CALL type is GENERAL (no indicator argument is passed). v The program to call is determined based on the procedure name specified on the CALL, and, if necessary, the naming convention. v The language of the program to call is determined based on information retrieved from the system about the program.

Example: Embedded CALL Statement Where No Procedure Definition Exists


The following is a PL/I example of an embedded CALL statement where no procedure definition exists:
DCL HV2 CHAR(10); : EXEC SQL CALL P2 (:HV2); :

When the CALL statement is invoked, DB2 SQL for AS/400 attempts to find the program based on standard SQL naming conventions. For the above example, assume that the naming option of *SYS (system naming) is used and that a DFTRDBCOL parameter was not specified on the CRTSQLPLI command. In this case, the library list is searched for a program named P2. Since the call type is GENERAL, no additional argument is passed to the program for indicator variables. Note: If an indicator variable is specified on the CALL statement and its value is less than zero when the CALL statement is executed, an error results because there is no way to pass the indicator to the procedure. Assuming program P2 is found in the library list, the contents of host variable HV2 are passed in to the program on the CALL and the argument returned from P2 is mapped back to the host variable after P2 has completed execution.

Using Embedded CALL statement with an SQLDA


In either type of embedded CALL (where a procedure definition may or may not exist), an SQLDA may be passed rather than a parameter list, as illustrated in the following C example. Assume that the stored procedure is expecting 2 parameters, the first of type SHORT INT and the second of type CHAR with a length of 4.

Chapter 7. Stored Procedures

125

#define SQLDA_HV_ENTRIES 2 #define SHORTINT 500 #define NUL_TERM_CHAR 460 exec sql include sqlca; exec sql include sqlda; ... typedef struct sqlda Sqlda; typedef struct sqlda* Sqldap; ... main() { Sqldap dap; short col1; char col2[4]; int bc; dap = (Sqldap) malloc(bc=SQLDASIZE(SQLDA_HV_ENTRIES)); /* SQLDASIZE is a macro defined in the sqlda include */ col1 = 431; strcpy(col2,"abc"); strncpy(dap->sqldaid,"SQLDA ",8); dap->sqldabc = bc; /* bc set in the malloc statement above */ dap->sqln = SQLDA_HV_ENTRIES; dap->sqld = SQLDA_HV_ENTRIES; dap->sqlvar[0].sqltype = SHORTINT; dap->sqlvar[0].sqllen = 2; dap->sqlvar[0].sqldata = (char*) &col1; dap->sqlvar[0].sqlname.length = 0; dap->sqlvar[1].sqltype = NUL_TERM_CHAR; dap->sqlvar[1].sqllen = 4; dap->sqlvar[1].sqldata = col2; ... EXEC SQL CALL P1 USING DESCRIPTOR :*dap; ... }

It should be noted that the name of the called procedure may also be stored in a host variable and the host variable used in the CALL statement, instead of the hard-coded procedure name. For example:
... main() { char proc_name[15]; ... strcpy (proc_name, "MYLIB.P3"); ... EXEC SQL CALL :proc_name ...; ... }

In the above example, if MYLIB.P3 is expecting parameters, then either a parameter list or an SQLDA passed with the USING DESCRIPTOR clause may be used, as shown in the previous example. When a host variable containing the procedure name is used in the CALL statement and a CREATE PROCEDURE catalog definition exists, it will be used. The procedure name cannot be specified as a parameter marker. More examples for calling stored procedures may be found later in this chapter and also in the DATABASE 2 Advanced Database Functions book.

126

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Using Dynamic CALL Statement where no CREATE PROCEDURE exists


The following rules pertain to the processing of a dynamic CALL statement when there is no CREATE PROCEDURE definition: v All arguments are treated as IN type parameters. v The CALL type is GENERAL (no indicator argument is passed). v The program to call is determined based on the procedure name specified on the CALL and the naming convention. v The language of the program to call is determined based on information retrieved from the system about the program.

Example: Dynamic CALL statement where no CREATE PROCEDURE exists


The following is a C example of a dynamic CALL statement:
char hv3[10],string[100]; : strcpy(string,"CALL MYLIB.P3 ('P3 TEST')"); EXEC SQL EXECUTE IMMEDIATE :string; :

This example shows a dynamic CALL statement executed through an EXECUTE IMMEDIATE statement. The call is made to program MYLIB.P3 with one parameter passed as a character variable containing P3 TEST. When executing a CALL statement and passing a constant, as in the previous example, the length of the expected argument in the program must be kept in mind. If program MYLIB.P3 expected an argument of only 5 characters, the last 2 characters of the constant specified in the example would be lost to the program. Note: For this reason, it is always safer to use host variables on the CALL statement so that the attributes of the procedure can be matched exactly and so that characters are not lost. For dynamic SQL, host variables can be specified for CALL statement arguments if the PREPARE and EXECUTE statements are used to process it. For numeric constants passed on a CALL statement, the following rules apply: v All integer constants are passed as fullword binary integers. v All decimal constants are passed as packed decimal values. Precision and scale are determined based on the constant value. For instance, a value of 123.45 is passed as a packed decimal(5,2). Likewise, a value of 001.01 is also passed with a precision and scale of 5 and 2, respectively. v All floating point constants are passed as double-precision floating point. Special registers specified on a dynamic CALL statement are passed as follows: v CURRENT DATE Passed as a 10-byte character string in ISO format. v CURRENT TIME Passed as an 8-byte character string in ISO format. v CURRENT TIMESTAMP Passed as a 26-byte character string in IBM SQL format.
Chapter 7. Stored Procedures

127

v CURRENT TIMEZONE Passed as a packed decimal number with a precision of 6 and a scale of 0. v CURRENT SERVER Passed as an 18-byte varying length character string. v USER Passed as an 18-byte varying length character string. v CURRENT PATH Passed as a 558-byte varying character length character string.

Parameter passing conventions for stored procedures


The CALL statement can pass arguments to programs written in all supported host languages and REXX procedures. Each language supports different data types which are tailored to it. The SQL data type is contained in the leftmost column of the following table. Other columns in that row contain an indication of whether that data type is supported as a parameter type for a particular language. If the column contains a dash (-), the data type is not supported as a parameter type for that language. A host variable declaration indicates that DB2 SQL for AS/400 supports this data type as a parameter in this language. The declaration indicates how host variables must be declared to be received and set properly by the procedure. When calling an SQL procedure, all SQL data types are supported so no column is provided in the table.
Table 19. Data Types of Parameters SQL Data Type SMALLINT INTEGER C and C++ short long long long CL COBOL for AS/400 and ILE COBOL for AS/400 PIC S9(4) BINARY PIC S9(9) BINARY PIC S9(18) BINARY Note: Only supported for ILE COBOL for AS/400. PIC S9(p-s)V9(s) PACKED-DECIMAL Note: Precision must not be greater than 18. PIC S9(p-s)V9(s) DISPLAY SIGN LEADING SEPARATE Note: Precision must not be greater than 18. COMP-1 Note: Only supported for ILE COBOL for AS/400. COMP-2 Note: Only supported for ILE COBOL for AS/400. PIC X(n) Varying-Length Character String (see COBOL chapter) Note: Only supported for ILE COBOL for AS/400.

| | |

BIGINT

DECIMAL(p,s)

decimal(p,s)

TYPE(*DEC) LEN(p s)

NUMERIC(p,s)

REAL or FLOAT(p)

float

DOUBLE PRECISION or FLOAT or FLOAT(p) CHARACTER(n) VARCHAR(n)

double

char ... [n+1] char ... [n+1]

TYPE(*CHAR) LEN(n) -

128

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Table 19. Data Types of Parameters (continued) SQL Data Type VARCHAR(n) FOR BIT DATA C and C++ CL COBOL for AS/400 and ILE COBOL for AS/400 Varying-Length Character String (see COBOL chapter) Note: Only supported for ILE COBOL for AS/400. PIC G(n) DISPLAY-1 or PIC N(n) Note: Only supported for ILE COBOL for AS/400. Varying-Length Graphic String (see COBOL chapter) Note: Only supported for ILE COBOL for AS/400. PIC X(10) For ILE COBOL for AS/400 only, FORMAT DATE. PIC X(8) For ILE COBOL for AS/400 only, FORMAT TIME. PIC X(26) For ILE COBOL for AS/400 only, FORMAT TIMESTAMP. PIC S9(4) BINARY CLOB structured form (see COBOL chapter in SQL Programming with Host Languages). Note: only supported for ILE COBOL for AS/400. BLOB structured form (see COBOL chapter in SQL Programming with Host Languages). Note: only supported for ILE COBOL for AS/400. DBCLOB structured form (see COBOL chapter in SQL Programming with Host Languages). Note: only supported for ILE COBOL for AS/400. -

VARCHAR structured form (see C chapter)

GRAPHIC(n)

wchar_t ... [n+1]

VARGRAPHIC(n)

VARGRAPHIC structured form (see C chapter)

DATE

char ... [11]

TYPE(*CHAR) LEN(10)

TIME

char ... [9]

TYPE(*CHAR) LEN(8)

TIMESTAMP

char ... [27]

TYPE(*CHAR) LEN(26)

Indicator Variable CLOB

short CLOB structured form (see C chapter in SQL Programming with Host Languages)

BLOB

BLOB structured form (see C chapter in SQL Programming with Host Languages)

DBCLOB

DBCLOB structured form (see C chapter in SQL Programming with Host Languages)

DataLink

Table 20. Data Types of Parameters SQL Data Type SMALLINT INTEGER FORTRAN INTEGER*2 INTEGER*4 Java Parameter Style JAVA short int long BigDecimal Java Parameter Style DB2GENERAL short int long BigDecimal PL/I FIXED BIN(15) FIXED BIN(31) FIXED DEC(p,s)

BIGINT DECIMAL(p,s)

Chapter 7. Stored Procedures

129

Table 20. Data Types of Parameters (continued) SQL Data Type NUMERIC(p,s) REAL or FLOAT(p) FORTRAN REAL*4 Java Parameter Style JAVA BigDecimal float double Java Parameter Style DB2GENERAL BigDecimal float double PL/I FLOAT BIN(p) FLOAT BIN(p)

DOUBLE PRECISION REAL*8 or FLOAT or FLOAT(p) CHARACTER(n) VARCHAR(n) VARCHAR(n) FOR BIT DATA GRAPHIC(n) VARGRAPHIC(n) DATE TIME TIMESTAMP Indicator Variable CLOB CHARACTER*n CHARACTER*10 CHARACTER*8 CHARACTER*26 INTEGER*2 -

String String String String Date Time Timestamp -

String String

CHAR(n) CHAR(n) VAR

com.ibm.db2.app.Blob CHAR(n) VAR String String String String String CHAR(10) CHAR(8) CHAR(26) FIXED BIN(15)

com.ibm.db2.app.Clob CLOB structured form (see PL/I chapter in SQL Programming with Host Languages) com.ibm.db2.app.Blob BLOB structured form (see PL/I chapter in SQL Programming with Host Languages) com.ibm.db2.app.Clob DBCLOB structured form (see PL/I chapter in SQL Programming with Host Languages) -

BLOB

DBCLOB

DataLink

Table 21. Data Types of Parameters SQL Data Type REXX RPG Data structure that contains a single sub-field. B in position 43, length must be 2, and 0 in position 52 of the sub-field specification. ILE RPG Data specification. B in position 40, length must be <= 4, and 00 in positions 41-42 of the sub-field specification. or Data specification. I in position 40, length must be 5, and 00 in positions 41-42 of the sub-field specification.

| | | | | | | | |

SMALLINT

130

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Table 21. Data Types of Parameters (continued) SQL Data Type REXX RPG ILE RPG Data specification. B in position 40, length must be <=09 and >=05, and 00 in positions 41-42 of the sub-field specification. or Data specification. I in position 40, length must be 10, and 00 in positions 41-42 of the sub-field specification. Data specification. I in position 40, length must be 20, and 00 in positions 41-42 of the sub-field specification. Data specification. P in position 40 and 00 through 31 in positions 41-42 of the sub-field specification.

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

INTEGER

numeric string with Data structure that contains a no decimal (and an single sub-field. B in position 43, optional leading sign) length must be 4, and 0 in position 52 of the sub-field specification.

BIGINT

DECIMAL(p,s)

numeric string with a Data structure that contains a decimal (and an single sub-field. P in position 43 optional leading sign) and 0 through 9 in position 52 of the sub-field specification. or A numeric input field or calculation result field. Data structure that contains a single sub-field. Blank in position 43 and 0 through 9 in position 52 of the sub-field specification. -

NUMERIC(p,s)

Data specification. S in position 40, or Blank in position 40 and 00 through 31 in position 41-42 of the sub-field specification. Data specification. F in position 40, length must be 4.

REAL or FLOAT(p)

string with digits, then an E, (then an optional sign), then digits

DOUBLE PRECISION string with digits, then an E, (then an or FLOAT or optional sign), then FLOAT(p) digits CHARACTER(n) string with n characters within two apostrophes

Data specification. F in position 40, length must be 8.

Data structure field without sub-fields or data structure that contains a single sub-field. Blank in position 43 and 52 of the sub-field specification. or A character input field or calculation result field. -

Data specification. A in position 40, or Blank in position 40 and 41-42 of the sub-field specification.

VARCHAR(n)

string with n characters within two apostrophes

Data specification. A in position 40, or Blank in position 40 and 41-42 of the sub-field specification and the keyword VARYING in positions 44-80. Data specification. A in position 40, or Blank in position 40 and 41-42 of the sub-field specification and the keyword VARYING in positions 44-80. Data specification. G in position 40 of the sub-field specification.

VARCHAR(n) FOR BIT DATA

string with n characters within two apostrophes

GRAPHIC(n)

string starting with G, then n double byte characters, then

Chapter 7. Stored Procedures

131

Table 21. Data Types of Parameters (continued) SQL Data Type VARGRAPHIC(n) REXX RPG ILE RPG Data specification. G in position 40 of the sub-field specification and the keyword VARYING in positions 44-80.

string starting with G, then n double byte characters, then string with 10 characters within two apostrophes

DATE

Data structure field without Data specification. D in position sub-fields or data structure that 40 of the sub-field specification. contains a single sub-field. Blank DATFMT(*ISO) in position 44-80. in position 43 and 52 of the sub-field specification. Length is 10. or A character input field or calculation result field. Data specification. T in position Data structure field without 40 of the sub-field specification. sub-fields or data structure that contains a single sub-field. Blank TIMFMT(*ISO) in position 44-80. in position 43 and 52 of the sub-field specification. Length is 8. or A character input field or calculation result field. Data specification. Z in position Data structure field without 40 of the sub-field specification. sub-fields or data structure that contains a single sub-field. Blank in position 43 and 52 of the sub-field specification. Length is 26. or A character input field or calculation result field. Data specification. B in position 40, length must be <=4, and 00 in positions 41-42 of the sub-field specification. CLOB structured form (see RPG chapter in SQL Programming with Host Languages) BLOB structured form (see RPG chapter in SQL Programming with Host Languages) DBCLOB structured form (see RPG chapter in SQL Programming with Host Languages) -

TIME

string with 8 characters within two apostrophes

TIMESTAMP

string with 26 characters within two apostrophes

Indicator Variable

Data structure that contains a numeric string with single sub-field. B in position 43, no decimal (and an optional leading sign). length must be 2, and 0 in position 52 of the sub-field specification. -

CLOB

BLOB

DBCLOB

DataLink

Indicator variables and stored procedures


Indicator variables can be used with the CALL statement, provided host variables are used for the parameters, to pass additional information to and from the procedure. Indicator variables are the SQL standard means of denoting that the associated host variable should be interpreted as containing the null value, and this is their primary use.

132

DB2 UDB for AS/400 SQL Programming Concepts V4R5

To indicate that an associated host variable contains the null value, the indicator variable, which is a two-byte integer, is set to a negative value. A CALL statement with indicator variables is processed as follows: v If the indicator variable is negative, this denotes the null value. A default value is passed for the associated host variable on the CALL and the indicator variable is passed unchanged. v If the indicator variable is not negative, this denotes that the host variable contains a non-null value. In this case, the host variable and the indicator variable are passed unchanged. Note that these rules of processing are the same for input parameters to the procedure as well as output parameters returned from the procedure. When indicator variables are used with stored procedures, the correct method of coding their handling is to check the value of the indicator variable first before using the associated host variable. The following example illustrates the handling of indicator variables in CALL statements. Notice that the logic checks the value of the indicator variable before using the associated variable. Also note the method that the indicator variables are passed into procedure PROC1 (as a third argument consisting of an array of two-byte values). Assume a procedure was defined as follows:
CREATE PROCEDURE PROC1 (INOUT DECIMALOUT DECIMAL(7,2), INOUT DECOUT2 DECIMAL(7,2)) EXTERNAL NAME LIB1.PROC1 LANGUAGE RPGLE GENERAL WITH NULLS)

Chapter 7. Stored Procedures

133

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Program CRPG ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ D INOUT1 S 7P 2 D INOUT1IND S 4B 0 D INOUT2 S 7P 2 D INOUT2IND S 4B 0 C EVAL INOUT1 = 1 C EVAL INOUT1IND = 0 C EVAL INOUT2 = 1 C EVAL INOUT2IND = -2 C/EXEC SQL CALL PROC1 (:INOUT1 :INOUT1IND , :INOUT2 C+ :INOUT2IND) C/END-EXEC C EVAL INOUT1 = 1 C EVAL INOUT1IND = 0 C EVAL INOUT2 = 1 C EVAL INOUT2IND = -2 C/EXEC SQL CALL PROC1 (:INOUT1 :INOUT1IND , :INOUT2 C+ :INOUT2IND) C/END-EXEC C INOUT1IND IFLT 0 C* : C* HANDLE NULL INDICATOR C* : C ELSE C* : C* INOUT1 CONTAINS VALID DATA C* : C ENDIF C* : C* HANDLE ALL OTHER PARAMETERS C* IN A SIMILAR FASHION C* : C RETURN ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ End of PROGRAM CRPG ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Figure 3. Handling of Indicator Variables in CALL Statements (Part 1 of 2)

134

DB2 UDB for AS/400 SQL Programming Concepts V4R5

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Program PROC1 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ D INOUTP S 7P 2 D INOUTP2 S 7P 2 D NULLARRAY S 4B 0 DIM(2) C *ENTRY PLIST C PARM INOUTP C PARM INOUTP2 C PARM NULLARRAY C NULLARRAY(1) IFLT 0 C* : C* INOUTP DOES NOT CONTAIN MEANINGFUL DATA C* C ELSE C* : C* INOUTP CONTAINS MEANINGFUL DATA C* : C ENDIF C* PROCESS ALL REMAINING VARIABLES C* C* BEFORE RETURNING, SET OUTPUT VALUE FOR FIRST C* PARAMETER AND SET THE INDICATOR TO A NON-NEGATIV C* VALUE SO THAT THE DATA IS RETURNED TO THE CALLING C* PROGRAM C* C EVAL INOUTP2 = 20.5 C EVAL NULLARRAY(2) = 0 C* C* INDICATE THAT THE SECOND PARAMETER IS TO CONTAIN C* THE NULL VALUE UPON RETURN. THERE IS NO POINT C* IN SETTING THE VALUE IN INOUTP SINCE IT WON'T BE C* PASSED BACK TO THE CALLER. C EVAL NULLARRAY(1) = -5 C RETURN ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ End of PROGRAM PROC1 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Figure 3. Handling of Indicator Variables in CALL Statements (Part 2 of 2)

Returning a completion status to the calling program


One method of returning a status to the SQL program issuing the CALL statement is to code an extra INOUT type parameter and set it prior to returning from the procedure. When the procedure being called is an existing program, this is not always possible. Another method of returning a status to the SQL program issuing the CALL statement is to send an escape message to the calling program (operating system program QSQCALL) which invokes the procedure. The calling program that invokes the procedure is QSQCALL. Each language has methods for signalling conditions and sending messages. Refer to the respective language reference to determine the proper way to signal a message. When the message is signalled, QSQCALL turns the error into SQLCODE/SQLSTATE -443/38501.

Chapter 7. Stored Procedures

135

Examples of CALL statements


These examples show how the arguments of the CALL statement are passed to the procedure for several languages. They also show how to receive the arguments into local variables in the procedure. The first example shows the calling ILE C program that uses the CREATE PROCEDURE definitions to call the P1 and P2 procedures. Procedure P1 is written in C and has 10 parameters. Procedure P2 is written in PL/I and also has 10 parameters. Assume two procedures are defined as follows:
EXEC SQL CREATE PROCEDURE P1 (INOUT PARM1 CHAR(10), INOUT PARM2 INTEGER, INOUT PARM3 SMALLINT, INOUT PARM4 FLOAT(22), INOUT PARM5 FLOAT(53), INOUT PARM6 DECIMAL(10,5), INOUT PARM7 VARCHAR(10), INOUT PARM8 DATE, INOUT PARM9 TIME, INOUT PARM10 TIMESTAMP) EXTERNAL NAME TEST12.CALLPROC2 LANGUAGE C GENERAL WITH NULLS EXEC SQL CREATE PROCEDURE P2 (INOUT PARM1 CHAR(10), INOUT PARM2 INTEGER, INOUT PARM3 SMALLINT, INOUT PARM4 FLOAT(22), INOUT PARM5 FLOAT(53), INOUT PARM6 DECIMAL(10,5), INOUT PARM7 VARCHAR(10), INOUT PARM8 DATE, INOUT PARM9 TIME, INOUT PARM10 TIMESTAMP) EXTERNAL NAME TEST12.CALLPROC LANGUAGE PLI GENERAL WITH NULLS

136

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Example 1: ILE C and PL/I procedures called from ILE C applications


/**************************************************************/ /*********** START OF SQL C Application ***********************/ #include <stdio.h> #include <string.h> #include <decimal.h> main() { EXEC SQL INCLUDE SQLCA; char PARM1[10]; signed long int PARM2; signed short int PARM3; float PARM4; double PARM5; decimal(10,5) PARM6; struct { signed short int parm7l; char parm7c[10]; } PARM7; char PARM8[10]; /* FOR DATE */ char PARM9[8]; /* FOR TIME */ char PARM10[26]; /* FOR TIMESTAMP */

Figure 4. Sample of CREATE PROCEDURE and CALL (Part 1 of 2)

Chapter 7. Stored Procedures

137

/*******************************************************/ /* Initialize variables for the call to the procedures */ /*******************************************************/ strcpy(PARM1,"PARM1"); PARM2 = 7000; PARM3 = -1; PARM4 = 1.2; PARM5 = 1.0; PARM6 = 10.555; PARM7.parm7l = 5; strcpy(PARM7.parm7c,"PARM7"); strncpy(PARM8,"1994-12-31",10); /* FOR DATE */ strncpy(PARM9,"12.00.00",8); /* FOR TIME */ strncpy(PARM10,"1994-12-31-12.00.00.000000",26); /* FOR TIMESTAMP */ /***********************************************/ /* Call the C procedure */ /* */ /* */ /***********************************************/ EXEC SQL CALL P1 (:PARM1, :PARM2, :PARM3, :PARM4, :PARM5, :PARM6, :PARM7, :PARM8, :PARM9, :PARM10 ); if (strncmp(SQLSTATE,"00000",5)) { /* Handle error or warning returned on CALL statement */ } /* Process return values from the CALL. : /***********************************************/ /* Call the PLI procedure */ /* */ /* */ /***********************************************/ /* Reset the host variables prior to making the CALL /* : EXEC SQL CALL P2 (:PARM1, :PARM2, :PARM3, :PARM4, :PARM5, :PARM6, :PARM7, :PARM8, :PARM9, :PARM10 ); if (strncmp(SQLSTATE,"00000",5)) { /* Handle error or warning returned on CALL statement } /* Process return values from the CALL. : } */

*/ */

*/ */

/******** END OF C APPLICATION **********************************/ /****************************************************************/ Figure 4. Sample of CREATE PROCEDURE and CALL (Part 2 of 2)

138

DB2 UDB for AS/400 SQL Programming Concepts V4R5

/******** START OF C PROCEDURE P1 *******************************/ /* PROGRAM TEST12/CALLPROC2 */ /****************************************************************/ #include <stdio.h> #include <string.h> #include <decimal.h> main(argc,argv) int argc; char *argv[]; { char parm1[11]; long int parm2; short int parm3,i,j,*ind,ind1,ind2,ind3,ind4,ind5,ind6,ind7, ind8,ind9,ind10; float parm4; double parm5; decimal(10,5) parm6; char parm7[11]; char parm8[10]; char parm9[8]; char parm10[26]; /* *********************************************************/ /* Receive the parameters into the local variables */ /* Character, date, time, and timestamp are passed as */ /* NUL terminated strings - cast the argument vector to */ /* the proper data type for each variable. Note that */ /* the argument vector could be used directly instead of */ /* copying the parameters into local variables - the copy */ /* is done here just to illustrate the method. */ /* *********************************************************/ /* Copy 10 byte character string into local variable strcpy(parm1,argv[1]); /* Copy 4 byte integer into local variable parm2 = *(int *) argv[2]; /* Copy 2 byte integer into local variable parm3 = *(short int *) argv[3]; /* Copy floating point number into local variable parm4 = *(float *) argv[4]; /* Copy double precision number into local variable parm5 = *(double *) argv[5]; /* Copy decimal number into local variable parm6 = *(decimal(10,5) *) argv[6]; Figure 5. Sample Procedure P1 (Part 1 of 2) */ */ */ */ */ */

Chapter 7. Stored Procedures

139

/**********************************************************/ /* Copy NUL terminated string into local variable. */ /* Note that the parameter in the CREATE PROCEDURE was */ /* declared as varying length character. For C, varying */ /* length are passed as NUL terminated strings unless */ /* FOR BIT DATA is specified in the CREATE PROCEDURE */ /**********************************************************/ strcpy(parm7,argv[7]); /**********************************************************/ /* Copy date into local variable. */ /* Note that date and time variables are always passed in */ /* ISO format so that the lengths of the strings are */ /* known. strcpy would work here just as well. */ /**********************************************************/ strncpy(parm8,argv[8],10); /* Copy time into local variable strncpy(parm9,argv[9],8); */

/**********************************************************/ /* Copy timestamp into local variable. */ /* IBM SQL timestamp format is always passed so the length*/ /* of the string is known. */ /**********************************************************/ strncpy(parm10,argv[10],26); /**********************************************************/ /* The indicator array is passed as an array of short */ /* integers. There is one entry for each parameter passed */ /* on the CREATE PROCEDURE (10 for this example). */ /* Below is one way to set each indicator into separate */ /* variables. */ /**********************************************************/ ind = (short int *) argv[11]; ind1 = *(ind++); ind2 = *(ind++); ind3 = *(ind++); ind4 = *(ind++); ind5 = *(ind++); ind6 = *(ind++); ind7 = *(ind++); ind8 = *(ind++); ind9 = *(ind++); ind10 = *(ind++); : /* Perform any additional processing here */ : return; } /******** END OF C PROCEDURE P1 *******************************/ Figure 5. Sample Procedure P1 (Part 2 of 2)

140

DB2 UDB for AS/400 SQL Programming Concepts V4R5

/******** START OF PL/I PROCEDURE P2 **************************/ /******** PROGRAM TEST12/CALLPROC *****************************/ /**************************************************************/ CALLPROC :PROC( PARM1,PARM2,PARM3,PARM4,PARM5,PARM6,PARM7, PARM8,PARM9,PARM10,PARM11); DCL SYSPRINT FILE STREAM OUTPUT EXTERNAL; OPEN FILE(SYSPRINT); DCL PARM1 CHAR(10); DCL PARM2 FIXED BIN(31); DCL PARM3 FIXED BIN(15); DCL PARM4 BIN FLOAT(22); DCL PARM5 BIN FLOAT(53); DCL PARM6 FIXED DEC(10,5); DCL PARM7 CHARACTER(10) VARYING; DCL PARM8 CHAR(10); /* FOR DATE */ DCL PARM9 CHAR(8); /* FOR TIME */ DCL PARM10 CHAR(26); /* FOR TIMESTAMP */ DCL PARM11(10) FIXED BIN(15); /* Indicators */ /* PERFORM LOGIC - Variables can be set to other values for /* return to the calling program. : END CALLPROC; */ */

Figure 6. Sample Procedure P2

The next example shows a REXX procedure called from an ILE C program. Assume a procedure is defined as follows:
EXEC SQL CREATE PROCEDURE REXXPROC (IN PARM1 CHARACTER(20), IN PARM2 INTEGER, IN PARM3 DECIMAL(10,5), IN PARM4 DOUBLE PRECISION, IN PARM5 VARCHAR(10), IN PARM6 GRAPHIC(4), IN PARM7 VARGRAPHIC(10), IN PARM8 DATE, IN PARM9 TIME, IN PARM10 TIMESTAMP) EXTERNAL NAME 'TEST.CALLSRC(CALLREXX)' LANGUAGE REXX GENERAL WITH NULLS

Chapter 7. Stored Procedures

141

Example 2. Sample REXX Procedure Called From C Application


/**************************************************************/ /*********** START OF SQL C Application ***********************/ #include <decimal.h> #include <stdio.h> #include <string.h> #include <wcstr.h> /*-----------------------------------------------------------*/ exec sql include sqlca; exec sql include sqlda; /* ***********************************************************/ /* Declare host variable for the CALL statement */ /* ***********************************************************/ char parm1[20]; signed long int parm2; decimal(10,5) parm3; double parm4; struct { short dlen; char dat[10]; } parm5; wchar_t parm6[4] = { 0xC1C1, 0xC2C2, 0xC3C3, 0x0000 }; struct { short dlen; wchar_t dat[10]; } parm7 = {0x0009, 0xE2E2,0xE3E3,0xE4E4, 0xE5E5, 0xE6E6, 0xE7E7, 0xE8E8, 0xE9E9, 0xC1C1, 0x0000 }; char parm8[10]; char parm9[8]; char parm10[26]; main() {

Figure 7. Sample REXX Procedure Called From C Application (Part 1 of 4)

142

DB2 UDB for AS/400 SQL Programming Concepts V4R5

/* *************************************************************/ /* Call the procedure - on return from the CALL statement the */ /* SQLCODE should be 0. If the SQLCODE is non-zero, */ /* the procedure detected an error. */ /* *************************************************************/ strcpy(parm1,"TestingREXX"); parm2 = 12345; parm3 = 5.5; parm4 = 3e3; parm5.dlen = 5; strcpy(parm5.dat,"parm6"); strcpy(parm8,"1994-01-01"); strcpy(parm9,"13.01.00"); strcpy(parm10,"1994-01-01-13.01.00.000000"); EXEC SQL CALL REXXPROC (:parm1, :parm2, :parm3,:parm4, :parm5, :parm6, :parm7, :parm8, :parm9, :parm10); if (strncpy(SQLSTATE,"00000",5)) { /* handle error or warning returned on CALL : } :

*/

/****** END OF SQL C APPLICATION ************************************/ /**********************************************************************/ Figure 7. Sample REXX Procedure Called From C Application (Part 2 of 4)

Chapter 7. Stored Procedures

143

/**********************************************************************/ /****** START OF REXX MEMBER TEST/CALLSRC CALLREXX ********************/ /**********************************************************************/ /* REXX source member TEST/CALLSRC CALLREXX */ /* Note the extra parameter being passed for the indicator*/ /* array. */ /* */ /* ACCEPT THE FOLLOWING INPUT VARIABLES SET TO THE */ /* SPECIFIED VALUES : */ /* AR1 CHAR(20) = 'TestingREXX' */ /* AR2 INTEGER = 12345 */ /* AR3 DECIMAL(10,5) = 5.5 */ /* AR4 DOUBLE PRECISION = 3e3 */ /* AR5 VARCHAR(10) = 'parm6' */ /* AR6 GRAPHIC = G'C1C1C2C2C3C3' */ /* AR7 VARGRAPHIC = */ /* G'E2E2E3E3E4E4E5E5E6E6E7E7E8E8E9E9EAEA' */ /* AR8 DATE = '1994-01-01' */ /* AR9 TIME = '13.01.00' */ /* AR10 TIMESTAMP = */ /* '1994-01-01-13.01.00.000000' */ /* AR11 INDICATOR ARRAY = +0+0+0+0+0+0+0+0+0+0 */ /**********************************************************/ /* Parse the arguments into individual parameters */ /**********************************************************/ parse arg ar1 ar2 ar3 ar4 ar5 ar6 ar7 ar8 ar9 ar10 ar11 /**********************************************************/ /* Verify that the values are as expected */ /**********************************************************/ if ar1<>"'TestingREXX'" then signal ar1tag if ar2<>12345 then signal ar2tag if ar3<>5.5 then signal ar3tag if ar4<>3e3 then signal ar4tag if ar5<>"'parm6'" then signal ar5tag if ar6 <>"G'AABBCC'" then signal ar6tag if ar7 <>"G'SSTTUUVVWWXXYYZZAA'" then , signal ar7tag if ar8 <> "'1994-01-01'" then signal ar8tag if ar9 <> "'13.01.00'" then signal ar9tag if ar10 <> "'1994-01-01-13.01.00.000000'" then signal ar10tag if ar11 <> "+0+0+0+0+0+0+0+0+0+0" then signal ar11tag Figure 7. Sample REXX Procedure Called From C Application (Part 3 of 4)

144

DB2 UDB for AS/400 SQL Programming Concepts V4R5

/************************************************************/ /* Perform other processing as necessary .. */ /************************************************************/ : /************************************************************/ /* Indicate the call was successful by exiting with a */ /* return code of 0 */ /************************************************************/ exit(0) ar1tag: say "ar1 did not match" ar1 exit(1) ar2tag: say "ar2 did not match" ar2 exit(1) : : /************ END OF REXX MEMBER **********************************/

Figure 7. Sample REXX Procedure Called From C Application (Part 4 of 4)

| | |

Considerations for stored procedures that are written in Java


When using Java to write stored procedures, you can use two possible parameter passing styles. The recommended style is the JAVA parameter style, which matches the parameter style specified in the SQLj:SQL routines standard. The second style, DB2GENERAL, is a parameter style defined by DB2 UDB. The parameter style also determines the conventions that you must use when coding a Java stored procedure.

Coding a Java stored procedure that uses the JAVA parameter


When you code a Java stored procedure that uses the JAVA parameter style, you must follow the following conventions: v The Java method must be a public void static (not instance) method. v The parameters of the Java method must be SQL-compatible types. v A Java method may test for a SQL NULL value when the parameter is a nullable type (like String). v Output parameters are returned by using single element arrays. v The Java method may access the current database using the getConnection( ) method. v The compiled class file must reside in the /QIBM/UserData/OS400/SQLLib/Function directory. Java stored procedures using the JAVA parameter style are public static methods. Within the classes, the stored procedures are identified by their method name and signature. When you call a stored procedure, its signature is generated dynamically, based on the variable types defined by the CREATE PROCEDURE statement. If a parameter is passed in a Java type that permits the null value, a Java method can compare the parameter to null to determine if an input parameter is an SQL NULL. Output parameters are passed as arrays that contain one element. The Java stored procedure can set the first element of the array to set the output parameter.
Chapter 7. Stored Procedures

145

A connection to the embedding application context is accessed using the following Java Database Connectivity (JDBC) call: connection=DriverManager.getConnection(jdbc:default:connection); This connection then runsSQL statements with JDBC APIs. The following is a small stored procedure with one input and two outputs. It executes the given SQL query, and returns the number of rows in the result, and the SQLSTATE.
package mystuff; import java.sql.*; public class sample2 { public static void donut(String query, int[] rowCount, String[] sqlstate) throws Exception { try { Connection c=DriverManager.getConnection("jdbc:default:connection"); Statement s=c.createStatement(); ResultSet r=s.executeQuery(query); int counter=0; while(r.next()){ counter++; } r.close(); s.close(); rowCount[0] = counter; }catch(SQLException x){ sqlstate[0]= x.getSQLState(); } } }

All Java class files that are used by a Java stored procedure must reside in the /QIBM/UserData/OS400/SQLLib/Function directory. This directory is the AS/400 equivalent of sqllib/function, the directory where DB2 UDB stores Java stored procedures on other platforms.

Coding a Java stored procedure using the DB2GENERAL parameter style


When coding a Java stored procedure that uses the DB2GENERAL parameter style, you must follow the following conventions: v The class which defines a Java stored procedure must extend, or be a subclass of, the Java com.ibm.db2.app.StoredProc class. v The Java method must be a public void instance method. v The parameters of the Java method must be SQL-compatible types. v A Java method may test for a SQL NULL value using the isNull( ) method. v The Java method must explicitly set the return parameters using the set( ) method. v The Java method may access the current database using the getConnection ( ) method. v The compiled class file must reside in the /QIBM/UserData/OS400/SQLLib/Function directory. A class which includes a Java stored procedure must extend the class, com.ibm.db2.app.StoredProc. Java stored procedures are public instance methods.

146

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Within the classes, the stored procedures are identified by their method name and signature. When you call a stored procedure, its signature is generated dynamically, based on the variable types defined by the CREATE PROCEDURE statement. The com.ibm.db2.app.StoredProc class provides the isNull( ) method which permits a Java method to determine if an input parameter is an SQL NULL. The com.ibm.db2.app.StoredProc class also provides set...( ) methods that set output parameters. You must use these methods to set output parameters. If you do not set an output parameter, then the output parameter will return the SQL NULL value. The com.ibm.db2.app.StoredProc class provides the following routine to fetch a JDBC connection to the embedding application context. A connection to the embedding application context is accessed using the following JDBC call:
public Java.sql.Connection getConnection( )

This connection then runs SQL statements with JDBC APIs. The following is a small stored procedure with one input and two outputs. It executes the given SQL query, and returns the number of rows in the result, and the SQLSTATE.
package mystuff; import com.ibm.db2.app.*; import java.sql.*; public class sample2 extends StoredProc { public void donut(String query, int rowCount, String sqlstate) throws Exception { try { Statement s=getConnection().createStatement(); ResultSet r=s.executeQuery(query); int counter=0; while(r.next()){ counter++; } r.close(); s.close(); set(2, counter); }catch(SQLException x){ set(3, x.getSQLState()); } } }

All Java class files that are used by a Java stored procedure must reside in the /QIBM/UserData/OS400/SQLLib/Function directory. This directory is the AS/400 equivalent of sqllib/function, the directory where DB2 UDB stores Java stored procedures on other platforms. When compiling a Java stored procedure that uses the DB2GENERAL parameter style, the user must add /QIBM/ProdData/Java400/ext/db2routines_classes.jar to the CLASSPATH.

Restrictions on Java stored procedures


The following restrictions apply to Java Stored Procedures. v A Java stored procedure should not create additional threads. An additional thread may be created in a job only if the job is multithread capable. Since there
Chapter 7. Stored Procedures

147

v v

v v v

is no guaranteed that a job that calls an SQL stored procedure is multithread capable, a Java stored procedure should not create additional threads. Like stored procedures that are written in other programming languages, Java stored procedures may not execute the following SQL statements: COMMIT, ROLLBACK, SET TRANSACTION, CONNECT, DISCONNECT, RELEASE, or SET CONNECTION. Java stored procedures do no have the ability to return RESULT SETS. Since there is not a program object associated with a Java class file, the CREATE PROCEDURE information associated with the database is not stored with the program object. Therefore, it is not restored when a Java class is restored. You cannot use adopted authority to access Java class files. A Java stored procedure always uses the latest version of the Java Development Kit that is installed on the system. Since Blob and Clob classes reside in both the java.sql and com.ibm.db2.app packages, the programmer must use the entire name of these classes if both classes are used in the same program. The program must ensure that the Blob and Clob classes from the com.ibm.db2.app are used as the parameters passed to the stored procedure. Java stored procedures are stored in Java class files instead of *PGM objects or *SRVPGM objects. Therefore, the REVOKE and GRANT SQL commands cannot be used to revoke or grant authority to the Java class files.

148

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Chapter 8. Using the Object-Relational Capabilities


This chapter discusses the object-oriented capabilities of DB2. v Why use the DB2 object extensions? v DB2 approach to supporting objects v Using Large Objects (LOBs) v User-defined functions (UDF) v User-defined distinct types (UDT) v Synergy between UDTs, UDFs, and LOBs One of the most important recent developments in modern programming language technology is object-orientation. Object orientation is the notion that entities in the application domain can be modeled as independent objects that are related to one another by means of classification. Object-orientation lets you capture the similarities and differences among objects in your application domain and group those objects together into related types. Objects of the same type behave in the same way because they share the same set of type-specific functions. These functions reflect the behavior of your objects in the application domain.

Why use the DB2 object extensions?


With the object extensions of DB2, you can incorporate object-oriented (OO) concepts and methodologies into your relational database. You accomplish this by extending it with richer sets of types and functions. With these extensions, you can store instances of object-oriented data types in columns of tables, and operate on them by means of functions in SQL statements. In addition, you can make the semantic behavior of stored objects an important resource that can be shared among all your applications by means of the database. To incorporate object-orientation into your relational database systems, you can define new types and functions of your own. These new types and functions should reflect the semantics of the objects in your application domain. Some of the data objects you want to model may be large and complex (for example, text, voice, image, and financial data). Therefore, you may also need mechanisms for the storage and manipulation of large objects. User-defined Distinct types (UDTs), user-defined functions (UDFs), and Large Objects (LOBs) are the mechanisms that are provided by DB2. With DB2, you can now define new types and functions of your own to store and manipulate application objects within the database. As described in subsequent sections, there is an important synergy among these object-oriented features. You can model a complex object in the application domain as a UDT. The UDT may in turn be internally represented as a LOB. In turn, the UDTs behavior may be implemented in terms of UDFs. This section shows you how to use LOBs along with the steps that are required to define UDTs and UDFs. You will also learn how UDTs, UDFs, and LOBs can better represent the objects in your application and thus work together. Note: The use of the DB2 object-oriented mechanisms (UDTs, UDFs, and LOBs) is not restricted to the support of object-oriented applications. Just as the C++ programming language implements all sorts of non-object-oriented applications, the object-oriented mechanisms provided by DB2 can also support all kinds of non-object-oriented applications. UDTs, UDFs, and
Copyright IBM Corp. 2000

149

LOBs are general-purpose mechanisms that can be used to model any database application. For this reason, these DB2 object extensions offer extensive support for both non-traditional, that is, object-oriented applications, in addition to improving support for traditional ones.

DB2 approach to supporting objects


The object extensions of DB2 enable you to realize the benefits of object technology while building on the strengths of relational technology. In a relational system, data types describe the data stored in columns of tables where the instances (or objects) of these data types are stored. Operations on these instances are supported by means of operators or functions that can be invoked anywhere that expressions are allowed. The DB2 approach to support object extensions fits exactly into the relational paradigm. UDTs are data types that you define. UDTs, like built-in types, can be used to describe the data that is stored in columns of tables. UDFs are functions that you define. UDFs, like built-in functions or operators, support the manipulation of UDT instances. Thus, UDT instances are stored in columns of tables and manipulated by UDFs in SQL queries. UDTs can be internally represented in different ways. LOBs are just one example of this.

Using Large Objects (LOBs)


The VARCHAR and VARGRAPHIC data types have a limit of 32K bytes of storage. While this may be sufficient for small to medium size text data, applications often need to store large text documents. They may also need to store a wide variety of additional data types such as audio, video, drawings, mixed text and graphics, and images. DB2 provides three data types to store these data objects as strings of up to fifteen (15) megabytes (MB) in size. The three data types are: Binary Large OBjects (BLOBs), single-byte Character Large OBjects (CLOBs), and Double-Byte Character Large OBjects (DBCLOBs). Along with storing large objects (LOBs), you will also need a method to refer to, use, and modify each LOB in the database. Each DB2 table may have a large amount of associated LOB data. Although a single row containing one or more LOB values cannot exceed 15 megabytes, a table may contain nearly 256 gigabytes of LOB data. The content of the LOB column of a particular row at any point in time has a large object value. You can refer to and manipulate LOBs using host variables just as you would any other data type. However, host variables use the client memory buffer which may not be large enough to hold LOB values. Other means are necessary to manipulate these large values. Locators are useful to identify and manipulate a large object value at the database server and for extracting pieces of the LOB value. File reference variables are useful for physically moving a large object value (or a large part of it) to and from the client. The subsections that follow discuss the topics that are introduced above in more detail.

150

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Understanding large object data types (BLOB, CLOB, DBCLOB)


Large object data types store data ranging in size from zero bytes to 15 megabytes. The three large object data types have the following definitions: v Character Large OBjects (CLOBs) A character string made up of single-byte characters with an associated code page. This data type is best for holding text-oriented information where the amount of information could grow beyond the limits of a regular VARCHAR data type (upper limit of 32K bytes). Code page conversion of the information is supported as well as compatibility with the other character types. v Double-Byte Character Large OBjects (DBCLOBs) A character string made up of double-byte characters with an associated code page. This data type is best for holding text-oriented information where double-byte character sets are used. Again, code page conversion of the information is supported as well as compatibility with the other double-byte character types. v Binary Large OBjects (BLOBs) A binary string made up of bytes with no associated code page. This data type may be the most useful because it can store binary data. Therefore, it is a perfect source type for use by User-defined Distinct Types (UDTs). UDTs using BLOBs as the source type are created to store image, voice, graphical, and other types of business or application-specific data. For more information on UDTs, see User-defined distinct types (UDT) on page 173.

Understanding large object locators


Conceptually, LOB locators represent a simple idea that has been around for a while; use a small, easily managed value to refer to a much larger value. Specifically, a LOB locator is a 4-byte value stored in a host variable that a program uses to refer to a LOB value (or LOB expression) held in the database system. Using a LOB locator, a program can manipulate the LOB value as if the LOB value was stored in a regular host variable. When you use the LOB locator, there is no need to transport the LOB value from the server to the application (and possibly back again). The LOB locator is associated with a LOB value or LOB expression, not a row or physical storage location in the database. Therefore, after selecting a LOB value into a locator, you cannot perform an operation on the original row(s) or tables(s) that would have any effect on the value referenced by the locator. The value associated with the locator is valid until the unit of work ends, or the locator is explicitly freed, whichever comes first. The FREE LOCATOR statement releases a locator from its associated value. In a similar way, a commit or roll-back operation frees all LOB locators associated with the transaction. LOB locators can also be passed between DB2 and UDFs. Within the UDF, those functions that work on LOB data are available to manipulate the LOB values using LOB locators. When selecting a LOB value, you have three options. v Select the entire LOB value into a host variable. The entire LOB value is copied into the host variable.

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 is not copied to the host variable. v Select the entire LOB value into a file reference variable. The LOB value is moved to an Integrated File System (IFS) file. The use of the LOB value within the program can help the programmer determine which method is best. If the LOB value is very large and is needed only as an input value for one or more subsequent SQL statements, keep the value in a locator. If the program needs the entire LOB value regardless of the size, then there is no choice but to transfer the LOB. Even in this case, there are still three options available to you. You can select the entire value into a regular or file reference host variable. You may also select the LOB value into a locator and read it piecemeal from the locator into a regular host variable, as suggested in the following example.

Example: Using a locator to work with a CLOB value


In this example, the application program retrieves a locator for a LOB value; then it uses the locator to extract the data from the LOB value. Using this method, the program allocates only enough storage for one piece of LOB data (the size is determined by the program). In addition, the program needs to issue only one fetch call using the cursor.

How the sample LOBLOC program works


1. Declare host variables. The BEGIN DECLARE SECTION and END DECLARE SECTION statements delimit the host variable declarations. Host variables are prefixed with a colon (:) when referenced in an SQL statement. CLOB LOCATOR host variables are declared. 2. Fetch the LOB value into the locator host variable. A CURSOR and FETCH routine is used to obtain the location of a LOB field in the database to a locator host variable. 3. Free the LOB LOCATORS. The LOB LOCATORS used in this example are freed, releasing the locators from their previously associated values. The CHECKERR macro/function is an error checking utility which is external to the program. The location of this error checking utility depends on the programming language that is used: C check_error is redefined as CHECKERR and is located in the util.c file.

152

DB2 UDB for AS/400 SQL Programming Concepts V4R5

C Sample: LOBLOC.SQC
#include <stdio.h> #include <stdlib.h> #include <string.h> #include "util.h" EXEC SQL INCLUDE SQLCA; #define CHECKERR(CE_STR) if (check_error (CE_STR, &sqlca) != 0) return 1;

int main(int argc, char *argv[]) { #ifdef DB2MAC char * bufptr; #endif EXEC SQL BEGIN DECLARE SECTION; 1 char number[7]; long deptInfoBeginLoc; long deptInfoEndLoc; SQL TYPE IS CLOB_LOCATOR resume; SQL TYPE IS CLOB_LOCATOR deptBuffer; short lobind; char buffer[1000]=""; char userid[9]; char passwd[19]; EXEC SQL END DECLARE SECTION; printf( "Sample C program: LOBLOC\n" ); if (argc == 1) { EXEC SQL CONNECT TO sample; CHECKERR ("CONNECT TO SAMPLE"); } else if (argc == 3) { strcpy (userid, argv[1]); strcpy (passwd, argv[2]); EXEC SQL CONNECT TO sample USER :userid USING :passwd; CHECKERR ("CONNECT TO SAMPLE"); } else { printf ("\nUSAGE: lobloc [userid passwd]\n\n"); return 1; } /* endif */ /* Employee A10030 is not included in the following select, because the lobeval program manipulates the record for A10030 so that it is not compatible with lobloc */ EXEC SQL DECLARE c1 CURSOR FOR SELECT empno, resume FROM emp_resume WHERE resume_format='ascii' AND empno <> 'A00130'; EXEC SQL OPEN c1; CHECKERR ("OPEN CURSOR"); do { EXEC SQL FETCH c1 INTO :number, :resume :lobind; 2 if (SQLCODE != 0) break; if (lobind < 0) { printf ("NULL LOB indicated\n"); } else { /* EVALUATE the LOB LOCATOR */ /* Locate the beginning of "Department Information" section */ EXEC SQL VALUES (POSSTR(:resume, 'Department Information')) INTO :deptInfoBeginLoc; CHECKERR ("VALUES1"); /* Locate the beginning of "Education" section (end of "Dept.Info" */ EXEC SQL VALUES (POSSTR(:resume, 'Education')) INTO :deptInfoEndLoc; CHECKERR ("VALUES2"); /* Obtain ONLY the "Department Information" section by using SUBSTR */ EXEC SQL VALUES(SUBSTR(:resume, :deptInfoBeginLoc, :deptInfoEndLoc - :deptInfoBeginLoc)) INTO :deptBuffer; CHECKERR ("VALUES3"); /* Append the "Department Information" section to the :buffer var. */ EXEC SQL VALUES(:buffer || :deptBuffer) INTO :buffer; CHECKERR ("VALUES4"); } /* endif */ } while ( 1 ); #ifdef DB2MAC /* Need to convert the newline character for the Mac */ bufptr = &(buffer[0]); while ( *bufptr != '\0' ) { if ( *bufptr == 0x0A ) *bufptr = 0x0D; bufptr++; } #endif printf ("%s\n",buffer); EXEC SQL FREE LOCATOR :resume, :deptBuffer; 3

Chapter 8. Using the Object-Relational Capabilities

153

CHECKERR ("FREE LOCATOR"); EXEC SQL CLOSE c1; CHECKERR ("CLOSE CURSOR"); EXEC SQL CONNECT RESET; CHECKERR ("CONNECT RESET"); return 0;

} /* end of program : LOBLOC.SQC */

COBOL Sample: LOBLOC.SQB


Identification Division. Program-ID. "lobloc". Data Division. Working-Storage Section. copy "sqlenv.cbl". copy "sql.cbl". copy "sqlca.cbl". EXEC SQL BEGIN DECLARE SECTION END-EXEC. 1 01 userid pic x(8). 01 passwd. 49 passwd-length pic s9(4) comp-5 value 0. 49 passwd-name pic x(18). 01 empnum pic x(6). 01 di-begin-loc pic s9(9) comp-5. 01 di-end-loc pic s9(9) comp-5. 01 resume USAGE IS SQL TYPE IS CLOB-LOCATOR. 01 di-buffer USAGE IS SQL TYPE IS CLOB-LOCATOR. 01 lobind pic s9(4) comp-5. 01 buffer USAGE IS SQL TYPE IS CLOB(1K). EXEC SQL END DECLARE SECTION END-EXEC. 77 errloc pic x(80).

Procedure Division. Main Section. display "Sample COBOL program: LOBLOC". * Get database connection information. display "Enter your user id (default none): " with no advancing. accept userid. if userid = spaces EXEC SQL CONNECT TO sample END-EXEC else display "Enter your password : " with no advancing accept passwd-name. * Passwords in a CONNECT * format with the length inspect passwd-name before initial " statement must be entered in a VARCHAR of the input string. tallying passwd-length for characters ".

EXEC SQL CONNECT TO sample USER :userid USING :passwd END-EXEC. move "CONNECT TO" to errloc. call "checkerr" using SQLCA errloc. * Employee A10030 is not included in the following select, because * the lobeval program manipulates the record for A10030 so that it is * not compatible with lobloc EXEC SQL DECLARE c1 CURSOR FOR SELECT empno, resume FROM emp_resume WHERE resume_format = 'ascii' AND empno <> 'A00130' END-EXEC. EXEC SQL OPEN c1 END-EXEC. move "OPEN CURSOR" to errloc. call "checkerr" using SQLCA errloc. Move 0 to buffer-length. perform Fetch-Loop thru End-Fetch-Loop until SQLCODE not equal 0. * display contents of the buffer. display buffer-data(1:buffer-length). EXEC SQL FREE LOCATOR :resume, :di-buffer END-EXEC. move "FREE LOCATOR" to errloc. call "checkerr" using SQLCA errloc. EXEC SQL CLOSE c1 END-EXEC. move "CLOSE CURSOR" to errloc. call "checkerr" using SQLCA errloc. EXEC SQL CONNECT RESET END-EXEC. move "CONNECT RESET" to errloc. call "checkerr" using SQLCA errloc. End-Main. 3

154

DB2 UDB for AS/400 SQL Programming Concepts V4R5

go to End-Prog. Fetch-Loop Section. EXEC SQL FETCH c1 INTO :empnum, :resume :lobind END-EXEC. if SQLCODE not equal 0 go to End-Fetch-Loop. * check to see if the host variable indicator returns NULL. if lobind less than 0 go to NULL-lob-indicated. * Value exists. Evaluate the LOB locator. * Locate the beginning of "Department Information" section. EXEC SQL VALUES (POSSTR(:resume, 'Department Information')) INTO :di-begin-loc END-EXEC. move "VALUES1" to errloc. call "checkerr" using SQLCA errloc. * Locate the beginning of "Education" section (end of Dept.Info) EXEC SQL VALUES (POSSTR(:resume, 'Education')) INTO :di-end-loc END-EXEC. move "VALUES2" to errloc. call "checkerr" using SQLCA errloc. subtract di-begin-loc from di-end-loc. * Obtain ONLY the "Department Information" section by using SUBSTR EXEC SQL VALUES (SUBSTR(:resume, :di-begin-loc, :di-end-loc)) INTO :di-buffer END-EXEC. move "VALUES3" to errloc. call "checkerr" using SQLCA errloc. * Append the "Department Information" section to the :buffer var EXEC SQL VALUES (:buffer || :di-buffer) INTO :buffer END-EXEC. move "VALUES4" to errloc. call "checkerr" using SQLCA errloc. go to End-Fetch-Loop. NULL-lob-indicated. display "NULL LOB indicated". End-Fetch-Loop. exit. End-Prog. stop run. 2

Indicator variables and LOB locators


For normal host variables in an application program, when selecting a NULL value into a host variable, a negative value is assigned to the indicator variable signifying that the value is NULL. In the case of LOB locators, however, the meaning of indicator variables is slightly different. Since a locator host variable itself can never be NULL, a negative indicator variable value indicates that the LOB value represented by the LOB locator is NULL. The NULL information is kept local to the client using the indicator variable value the server does not track NULL values with valid locators.

LOB file reference variables


File reference variables are similar to host variables except they are used to transfer data to and from IFS files (not to and from memory buffers). A file reference variable represents (rather than contains) the file, just as a LOB locator represents (rather than contains) the LOB value. Database queries, updates, and inserts may use file reference variables to store, or to retrieve, single LOB values. For very large objects, files are natural containers. It is likely that most LOBs begin as data stored in files on the client before they are moved to the database on the server. The use of file reference variables assists in moving LOB data. Programs use file reference variables to transfer LOB data from the IFS file directly to the database engine. To carry out the movement of LOB data, the application does not have to write utility routines to read and write files using host variables.

Chapter 8. Using the Object-Relational Capabilities

155

Note: The file referenced by the file reference variable must be accessible from (but not necessarily resident on) the system on which the program runs. For a stored procedure, this would be the server. A file reference variable has a data type of BLOB, CLOB, or DBCLOB. It is used either as the source of data (input) or as the target of data (output). The file reference variable may have a relative file name or a complete path name of the file (the latter is advised). The file name length is specified within the application program. The data length portion of the file reference variable is unused during input. During output, the data length is set by the application requestor code to the length of the new data that is written to the file. When using file reference variables there are different options on both input and output. You must choose an action for the file by setting the file_options field in the file reference variable structure. Choices for assignment to the field covering both input and output values are shown below. Values (shown for C) and options when using input file reference variables are as follows: v SQL_FILE_READ (Regular file) This option has a value of 2. This is a file that can be open, read, and closed. DB2 determines the length of the data in the file (in bytes) when opening the file. DB2 then returns the length through the data_length field of the file reference variable structure. (The value for COBOL is SQL-FILE-READ.) Values and options when using output file reference variables are as follows: v SQL_FILE_CREATE (New file) This option has a value of 8. This option creates a new file. Should the file already exist, an error message is returned. (The value for COBOL is SQL-FILE-CREATE.) v SQL_FILE_OVERWRITE (Overwrite file) This option has a value of 16. This option creates a new file if none already exists. If the file already exists, the new data overwrites the data in the file. (The value for COBOL is SQL-FILE-OVERWRITE.) v SQL_FILE_APPEND (Append file) This option has a value of 32. This option has the output appended to the file, if it exists. Otherwise, it creates a new file. (The value for COBOL is SQL-FILE-APPEND.) Note: If a LOB file reference variable is used in an OPEN statement, do not delete the file associated with the LOB file reference variable until the cursor is closed. For more information about integrated file system, see Integrated File System.

Example: Extracting a document to a file


This program example shows how CLOB elements can be retrieved from a table into an external file.

How the sample LOBFILE program works


1. Declare host variables. The BEGIN DECLARE SECTION and END DECLARE SECTION statements delimit the host variable declarations. Host variables are prefixed with a colon (:) when referenced in an SQL statement. A CLOB FILE REFERENCE host variable is declared.

156

DB2 UDB for AS/400 SQL Programming Concepts V4R5

2. CLOB FILE REFERENCE host variable is set up. The attributes of the FILE REFERENCE are set up. A file name without a fully declared path is, by default, placed in the users current directory. If the pathname does not begin with the forward slash (/) character, it is not qualified. 3. Select into the CLOB FILE REFERENCE host variable. The data from the resume field is selected into the filename that is referenced by the host variable. The CHECKERR macro/function is an error checking utility which is external to the program. The location of this error checking utility depends upon the programming language used: C COBOL
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sql.h> #include "util.h" EXEC SQL INCLUDE SQLCA; #define CHECKERR(CE_STR) if (check_error (CE_STR, &sqlca) != 0) return 1;

check_error is redefined as CHECKERR and is located in the util.c file. CHECKERR is an external program named checkerr.cbl

C Sample: LOBFILE.SQC

int main(int argc, char *argv[]) { EXEC SQL BEGIN DECLARE SECTION; 1 SQL TYPE IS CLOB_FILE resume; short lobind; char userid[9]; char passwd[19]; EXEC SQL END DECLARE SECTION; printf( "Sample C program: LOBFILE\n" ); if (argc == 1) { EXEC SQL CONNECT TO sample; CHECKERR ("CONNECT TO SAMPLE"); } else if (argc == 3) { strcpy (userid, argv[1]); strcpy (passwd, argv[2]); EXEC SQL CONNECT TO sample USER :userid USING :passwd; CHECKERR ("CONNECT TO SAMPLE"); } else { printf ("\nUSAGE: lobfile [userid passwd]\n\n"); return 1; } /* endif */ strcpy (resume.name, "RESUME.TXT"); 2 resume.name_length = strlen("RESUME.TXT"); resume.file_options = SQL_FILE_OVERWRITE; EXEC SQL SELECT resume INTO :resume :lobind FROM emp_resume WHERE resume_format='ascii' AND empno='000130'; 3

if (lobind < 0) { printf ("NULL LOB indicated \n"); } else { printf ("Resume for EMPNO 000130 is in file : RESUME.TXT\n"); } /* endif */ EXEC SQL CONNECT RESET; CHECKERR ("CONNECT RESET"); return 0;

} /* end of program : LOBFILE.SQC */

COBOL Sample: LOBFILE.SQB


Identification Division. Program-ID. "lobfile". Data Division. Working-Storage Section. copy "sqlenv.cbl". copy "sql.cbl". copy "sqlca.cbl". EXEC SQL BEGIN DECLARE SECTION END-EXEC. 1

Chapter 8. Using the Object-Relational Capabilities

157

01 userid pic x(8). 01 passwd. 49 passwd-length pic s9(4) comp-5 value 0. 49 passwd-name pic x(18). 01 resume USAGE IS SQL TYPE IS CLOB-FILE. 01 lobind pic s9(4) comp-5. EXEC SQL END DECLARE SECTION END-EXEC. 77 errloc pic x(80).

Procedure Division. Main Section. display "Sample COBOL program: LOBFILE". * Get database connection information. display "Enter your user id (default none): " with no advancing. accept userid. if userid = spaces EXEC SQL CONNECT TO sample END-EXEC else display "Enter your password : " with no advancing accept passwd-name. * Passwords in a CONNECT * format with the length inspect passwd-name before initial " statement must be entered in a VARCHAR of the input string. tallying passwd-length for characters ".

EXEC SQL CONNECT TO sample USER :userid USING :passwd END-EXEC. move "CONNECT TO" to errloc. call "checkerr" using SQLCA errloc. move "RESUME.TXT" to resume-NAME. move 10 to resume-NAME-LENGTH. move SQL-FILE-OVERWRITE to resume-FILE-OPTIONS. EXEC SQL SELECT resume INTO :resume :lobind 3 FROM emp_resume WHERE resume_format = 'ascii' AND empno = '000130' END-EXEC. if lobind less than 0 go to NULL-LOB-indicated. display "Resume for EMPNO 000130 is in file : RESUME.TXT". go to End-Main. NULL-LOB-indicated. display "NULL LOB indicated". End-Main. EXEC SQL CONNECT RESET END-EXEC. move "CONNECT RESET" to errloc. call "checkerr" using SQLCA errloc. End-Prog. stop run. 2

Example: Inserting data into a CLOB column


In the path description of the following C program segment: v userid represents the directory for one of your users. v dirname represents a subdirectory name of userid. v filnam.1 can become the name of one of your documents that you wish to insert into the table. v clobtab is the name of the table with the CLOB data type. The following example shows how to insert data from a regular file referenced by :hv_text_file into a CLOB column:
strcpy(hv_text_file.name, "/home/userid/dirname/filnam.1"); hv_text_file.name_length = strlen("/home/userid/dirname/filnam.1"); hv_text_file.file_options = SQL_FILE_READ; /* this is a 'regular' file */ EXEC SQL INSERT INTO CLOBTAB VALUES(:hv_text_file);

Display layout of LOB columns


When a row of data from a table holding LOB columns is displayed using CL commands such as Display Physical File Member (DSPPFM), the LOB data stored

158

DB2 UDB for AS/400 SQL Programming Concepts V4R5

in that row will not be displayed. Instead, the Database will show a special value for the LOB columns. The layout of this special value is as follows: v 13 to 28 bytes of hex zeros. v 16 bytes beginning with *POINTER and followed by blanks. The number of bytes in the first portion of the value is set to the number needed to 16 byte boundary align the second part of the value. For example, say you have a table that holds three columns: ColumnOne Char(10), ColumnTwo CLOB(40K), and ColumnThree BLOB(10M). If you were to issue a DSPPFM of this table, each row of data would look as follows. v For ColumnOne: 10 bytes filled with character data. v For ColumnTwo: 22 bytes filled with hex zeros and 16 bytes filled with *POINTER . v For ColumnThree: 16 bytes filled with hex zeros and 16 bytes filled with *POINTER . The full set of commands that display LOB columns in this way is: v Display Physical File Member (DSPPFM) v v v v Copy File (CPYF) when the value *PRINT is specified for the TOFILE keyword Display Journal (DSPJRN) Retrieve Journal Entry (RTVJRNE) Receive Journal Entry (RCVJRNE) when the values *TYPE1, *TYPE2, *TYPE3 and *TYPE4 are specified for the ENTFMT keyword.

Journal entry layout of LOB columns


Two commands return a buffer that gives the user addressability to LOB data that had been journaled: v Receive Journal Entry (RCVJRNE) CL command, when the value *TYPEPTR is specified for the ENTFMT keyword v Retrieve Journal Entries (QjoRetrieveJournalEntries) API The layout of the LOB columns in these entries is as follows: v 0 to 15 bytes of hex zeros v 1 byte of system information set to 00x v 4 bytes holding the length of the LOB data addressed by the pointer, below v 8 bytes of hex zeros v 16 bytes holding a pointer to the LOB data stored in the Journal Entry. The first part of this layout is intended to 16 byte boundary align the pointer to the LOB data. The number of bytes in this area depends on the length of the columns that proceed the LOB column. Refer to the section above on the Display Layout of LOB Columns for an example of how the length of this first part is calculated. For more information on the Journal handling of LOB columns, refer to the Working with Journal Entries, Journals and Journal Receivers chapter of the Backup and Recovery book.

Chapter 8. Using the Object-Relational Capabilities

159

User-defined functions (UDF)


A user-defined function is a mechanism with which you can write your own extensions to SQL. The built-in functions supplied with DB2 are a useful set of functions, but they may not satisfy all of your requirements. Thus, you may need to extend SQL for the following reasons: v Customization. The function specific to your application does not exist in DB2. Whether the function is a simple transformation, a trivial calculation, or a complicated multivariate analysis, you can probably use a UDF to do the job. v Flexibility. The DB2 built-in function does not quite permit the variations that you wish to include in your application. v Standardization. Many of the programs at your site implement the same basic set of functions, but there are minor differences in all the implementations. Thus, you are unsure about the consistency of the results you receive. If you correctly implement these functions once, in a UDF, then all these programs can use the same implementation directly in SQL and provide consistent results. v Object-relational support. As discussed in User-defined distinct types (UDT) on page 173, UDTs can be very useful in extending the capability and increasing the safety of DB2. UDFs act as the methods for UDTs, by providing behavior and encapsulating the types. In addition, SQL UDFs provide the support to manipulate Large Objects and DataLink types. While the database provides several built-in functions which are useful in working with these datatypes, SQL UDFs provide a way for users to further manipulate and enhance the capabilities of the database (to the specialization required) in this area.

Why use UDFs?


In writing DB2 applications, you have a choice when implementing desired actions or operations: v As a UDF v As a subroutine or function in your application. Although it appears easier to implement new operations as subroutines or functions in your application, you should still consider: v Re-use. If the new operation is something of which other users or programs at your site can take advantage, then UDFs can help to reuse it. In addition, the function can be invoked directly in SQL wherever an expression can be used by any user of the database. The database will take care of many data type promotions of the function arguments automatically. For example, with DECIMAL to DOUBLE, the database will allow your function to be applied to different, but compatible data types. It may seem easier to implement your new function as a normal function. (You would not have to define the function to DB2.) If you did this, you would have to inform all other interested application developers, and package the function effectively for their use. However, this process ignores the interactive users like those who normally use the Command Line Processor (CLP) to access the

160

DB2 UDB for AS/400 SQL Programming Concepts V4R5

database. However, functions written for use only within programs ignores those (interactive) users who do not have associated programs. This includes commands such as STRSQL, STRQM, and RUNSQLSTM, in addition to many clients such as ODBC, JDBC, etc. CLP users cannot use your function unless it is a UDF in the database. This also applies to any other tools that use SQL (such as Visualizer), that do not get recompiled. v Performance. In certain cases, invoking the UDF directly from the database engine instead of from your application can have a considerable performance advantage. You willl notice this advantage when the function may be used in the qualification of data for further processing. These cases occur when the function is used in record selection processing. Consider a simple scenario where you want to process some data. You can meet some selection criteria which can be expressed as a function SELECTION_CRITERIA(). Your application could issue the following select statement:
SELECT A, B, C FROM T

When it receives each row, it runs SELECTION_CRITERIA against the data to decide if it is interested in processing the data further. Here, every row of table T must be passed back to the application. But, if SELECTION_CRITERIA() is implemented as a UDF, your application can issue the following statement:
SELECT C FROM T WHERE SELECTION_CRITERIA(A,B)=1

In this case, only the rows and column of interest are passed across the interface between the application and the database. Another case where a UDF can offer a performance benefit is when dealing with Large Objects (LOB). Suppose you have a function that extracts some information from a value of one of the LOB types. You can perform this extraction right on the database server and pass only the extracted value back to the application. This is more efficient than passing the entire LOB value back to the application and then performing the extraction. The performance value of packaging this function as a UDF could be enormous, depending on the particular situation. (Note that you can also extract a portion of a LOB by using a LOB locator. See Indicator variables and LOB locators on page 155 for an example of a similar scenario.) v Object Orientation. You can implement the behavior of a user-defined distinct type (UDT), also called distinct type, using a UDF. For more information on UDTs, see User-defined distinct types (UDT) on page 173. For additional details on UDTs and the important concept of castability discussed herein, see the CREATE DISTINCT TYPE statement in the SQL Reference. When you create a distinct type, you are automatically provided cast functions between the distinct type and its source type. You may also be provided comparison operators such as =, >, <, and so on, depending on the source type. You have to provide any additional behavior yourself. It is best to keep the behavior of a distinct type in the database where all of the users of the distinct type can easily access it. You can use UDFs, therefore, as the implementation mechanism. For example, suppose that you have a BOAT distinct type, defined over a one megabyte BLOB. The type create statement:
CREATE DISTINCT TYPE BOAT AS BLOB(1M)

The BLOB contains the various nautical specifications, and some drawings. You may wish to compare sizes of boats. However, with a distinct type defined over
Chapter 8. Using the Object-Relational Capabilities

161

a BLOB source type, you do not get the comparison operations automatically generated for you. You can implement a BOAT_COMPARE function which decides if one boat is bigger than another based on a measure that you choose. These could be: displacement, length over all, metric tonnage, or another calculation based on the BOAT object. You create the BOAT_COMPARE function as follows:
CREATE SQL FUNCTION BOAT_COMPARE (BOAT, BOAT) RETURNS INTEGER ...

If

your function returns: 1 the first BOAT is bigger 2 the second is bigger and 0 they are equal.

You could use this function in your SQL code to compare boats. Suppose you create the following tables:
CREATE TABLE BOATS_INVENTORY ( BOAT_ID CHAR(5), BOAT_TYPE VARCHAR(25), DESIGNER VARCHAR(40), OWNER VARCHAR(40), DESIGN_DATE DATE, SPEC BOAT, ... ) CREATE TABLE MY_BOATS ( BOAT_ID CHAR(5), BOAT_TYPE VARCHAR(25), DESIGNER VARCHAR(40), DESIGN_DATE DATE, ACQUIRE_DATE DATE, ACQUIRE_PRICE CANADIAN_DOLLAR, CURR_APPRAISL CANADIAN_DOLLAR, SPEC BOAT, ... )

You can execute the following SQL SELECT statement:


SELECT INV.BOAT_ID, INV.BOAT_TYPE, INV.DESIGNER, INV.OWNER, INV.DESIGN_DATE FROM BOATS_INVENTORY INV, MY_BOATS MY WHERE MY.BOAT_ID = '19GCC' AND BOAT_COMPARE(INV.SPEC, MY.SPEC) = 1 AND INV.DESIGNER = MY.DESIGNER

This simple example returns all the boats from BOATS_INVENTORY from the same designer that are bigger than a particular boat in MY_BOATS. Note that the example only passes the rows of interest back to the application because the comparison occurs in the database server. In fact, it completely avoids passing any values of data type BOAT. This is a significant improvement in storage and performance as BOAT is based on a one megabyte BLOB data type.

UDF concepts
The following is a discussion of the important concepts you need to know prior to coding UDFs:

Function Name
v Full name of a function. The full name of a function using *SQL naming is <schema-name>.<functionname>.

162

DB2 UDB for AS/400 SQL Programming Concepts V4R5

The full name of a function in *SYS naming is <schema-name>/<function-name>. Function names cannot be qualified using *SYS naming in DML statements. You can use this full name anywhere you refer to a function. For example:
QGPL.SNOWBLOWER_SIZE SMITH.FOO QSYS2.SUBSTR QSYS2.FLOOR

However, you may also omit the <schema-name>., in which case, DB2 must determine the function to which you are referring. For example:
SNOWBLOWER_SIZE FOO SUBSTR FLOOR

v Path The concept of path is central to DB2s resolution of unqualified references that occur when schema-name is not specified. For the use of path in DDL statements that refer to functions, see the description of the corresponding CREATE FUNCTION statement in the SQL Reference. The path is an ordered list of schema names. It provides a set of schemas for resolving unqualified references to UDFs as well as UDTs. In cases where a function reference matches functions in more than one schema in the path, the order of the schemas in the path is used to resolve this match. The path is established by means of the SQLPATH option on the precompile and bind commands for static SQL. The path is set by the SET PATH statement for dynamic SQL. When the first SQL statement that runs in an activation group runs with SQL naming, the path has the following default value:
"QSYS","QSYS2","<ID>"

This applies to both static and dynamic SQL, where <ID> represents the current statement authorization ID. When the first SQL statement in an activation group runs with system naming, the default path is *LIBL. v Overloaded function names. Function names can be overloaded, which means that multiple functions, even in the same schema, can have the same name. Two functions cannot, however, have the same signature, which can be defined to be the qualified function name concatenated with the defined data types of all the function parameters in the order in which they are defined. For an example of an overloaded function, see Example: BLOB string search on page 166. See the SQL Reference book for more information on signature and function resolution. v Function resolution. It is the function resolution algorithm that takes into account the facts of overloading and function path to choose the best fit for every function reference, whether it is a qualified or an unqualified reference. All functions, even built-in functions, are processed through the function selection algorithm. v Types of function. There are several types of functions: Built-in. These are functions provided by and shipped with the database. SUBSTR() is an example. System-generated. These are functions implicitly generated by the database engine when a DISTINCT TYPE is created. These functions provide casting operations between the DISTINCT TYPE and its base type. User-defined. These are functions created by users and registered to the database.

Chapter 8. Using the Object-Relational Capabilities

163

In addition, each function can be further classified as a scalar or column function. A scalar function returns a single value answer each time it is called. For example, the built-in function SUBSTR() is a scalar function, as are many built-in functions. System-generated functions are always scalar functions. Scalar UDFs can either be external (coded in a programming language such as C, or in SQLan SQL function), or sourced (using the implementation of an existing function). A column function receives a set of like values (a column of data) and returns a single value answer from this set of values. These are also called aggregating functions in DB2. Some built-in functions are column functions. An example of a column function is the built-in function AVG(). An external UDF cannot be defined as a column function. However, a sourced UDF is defined to be a column function if it is sourced on one of the built-in column functions. The latter is useful for distinct types. For example, if a distinct type SHOESIZE exists that is defined with base type INTEGER, you could define a UDF, AVG(SHOESIZE), as a column function sourced on the existing built-in column function, AVG(INTEGER). The concept of path, the SET PATH statement, and the function resolution algorithm are discussed in detail in the SQL Reference. The SQLPATH precompile option is discussed in the command appendix.

Implementing UDFs
There are three types of UDFs: sourced, external, and SQL. The implementation of each type is considerably different. v Sourced UDFs. These are simply functions registered to the database that themselves reference another function. They, in effect, map the sourced function. As such, nothing more is required in implementing these functions than registering them to the database using the CREATE FUNCTION statement. v External functions. These are references to programs and service programs written in a high level language such as C, COBOL, or RPG. Once the function is registered to the database, the database will invoke the program or service program whenever the function is referenced in a DML statement. As such, external UDFs require that the UDF writer, besides knowing the high level language and how to develop code in it, must understand the interface between the program and the database. See Chapter 9. Writing User-Defined Functions (UDFs) on page 189 for more information on writing external functions. v SQL UDFs. SQL UDFs are functions written entirely in the SQL language. Their code is actually SQL statements embedded within the CREATE FUNCTION statement itself. SQL UDFs provide several advantages: They are written in SQL, making them quite portable. Defining the interface between the database and the function is by use of SQL declares, with no need to worry about details of actual parameter passing. They allow the passing of large objects, datalinks, and UDTs as parameters, and subsequent manipulation of them in the function itself. More information about SQL functions can be found in Chapter 9. Writing User-Defined Functions (UDFs) on page 189. 1. Registering the UDF with DB2. Regardless of which type of UDF is being created, they all need to be registered to the database using the CREATE FUNCTION statement. In the case of source functions, this registration step does everything necessary to define the function to the database. For SQL UDFs, the CREATE FUNCTION statement contains everything necessary to

164

DB2 UDB for AS/400 SQL Programming Concepts V4R5

define the function as well, except that the syntax of the CREATE statement is much more complex (contains actual SQL executable code). For external UDFs, the CREATE FUNCTION statement only registers the function to the database; the supporting code that actually implements the function must be written separately. See Registering UDFs for more information. 2. Debugging the UDF. See Chapter 9. Writing User-Defined Functions (UDFs) on page 189. After these steps are successfully completed, your UDF is ready for use in data manipulation language (DML) or data definition language (DDL) statements such as CREATE VIEW.

Registering UDFs
A UDF must be registered in the database before the function can be recognized and used by the database. You can register a UDF using the CREATE FUNCTION statement. The statement allows you to specify the language and name of the program, along with options such as DETERMINISTIC, ALLOW PARALLEL, and RETURNS NULL ON NULL INPUT. These options help to more specifically identify to the database the intention of the function and how calls to the database can be optimized. You should register the UDF to DB2 after you have written and completely tested the actual code. It is possible to define the UDF prior to actually writing it. However, to avoid any problems with running your UDF, you are encouraged to write and test it extensively before registering it. For information on testing your UDF, see Chapter 9. Writing User-Defined Functions (UDFs) on page 189.

Examples: Registering UDFs


The examples which follow illustrate a variety of typical situations where UDFs can be registered. The examples include: v Example: Exponentiation v Example: String search v Example: String search over UDT v Example: External function with UDT parameter v Example: AVG over a UDT v Example: Counting

Example: Exponentiation
Suppose you have written an external UDF to perform exponentiation of floating point values, and wish to register it in the MATH schema.
CREATE FUNCTION MATH.EXPON (DOUBLE, DOUBLE) RETURNS DOUBLE EXTERNAL NAME 'MYLIB/MYPGM(MYENTRY)' LANGUAGE C PARAMETER STYLE DB2SQL NO SQL DETERMINISTIC NO EXTERNAL ACTION RETURNS NULL ON NULL INPUT ALLOW PARALLEL

Chapter 8. Using the Object-Relational Capabilities

165

In this example, the system uses the RETURNS NULL ON NULL INPUT default value. This is desirable since you want the result to be NULL if either argument is NULL. Since you do not require a scratchpad and no final call is necessary, the NO SCRATCHPAD and NO FINAL CALL default values are used. As there is no reason why EXPON cannot be parallel, the ALLOW PARALLEL value is specified.

Example: String search


Your associate, Willie, has written a UDF to look for the existence of a given short string, passed as an argument, within a given CLOB value, which is also passed as an argument. The UDF returns the position of the string within the CLOB if it finds the string, or zero if it does not. Additionally, Willie has written the function to return a FLOAT result. Suppose you know that when it is used in SQL, it should always return an INTEGER. You can create the following function:
CREATE FUNCTION FINDSTRING (CLOB(500K), VARCHAR(200)) RETURNS INTEGER CAST FROM FLOAT SPECIFIC "willie_find_feb95" EXTERNAL NAME 'MYLIB/MYPGM(FINDSTR)' LANGUAGE C PARAMETER STYLE DB2SQL NO SQL DETERMINISTIC NO EXTERNAL ACTION RETURNS NULL ON NULL INPUT

Note that a CAST FROM clause is used to specify that the UDF body really returns a FLOAT value but you want to cast this to INTEGER before returning the value to the statement which used the UDF. As discussed in the SQL Reference, the INTEGER built-in function can perform this cast for you. Also, you wish to provide your own specific name for the function and later reference it in DDL (see Example: String search over UDT on page 167). Because the UDF was not written to handle NULL values, you use the RETURNS NULL ON NULL INPUT. And because there is no scratchpad, you use the NO SCRATCHPAD and NO FINAL CALL default values. As there is no reason why FINDSTRING cannot be parallel, the ALLOW PARALLELISM default value is used.

Example: BLOB string search


Because you want this function to work on BLOBs as well as on CLOBs, you define another FINDSTRING taking BLOB as the first parameter:
CREATE FUNCTION FINDSTRING (BLOB(500K), VARCHAR(200)) RETURNS INTEGER CAST FROM FLOAT SPECIFIC "willie_fblob_feb95" EXTERNAL NAME 'MYLIB/MYPGM(FINDSTR)' LANGUAGE C PARAMETER STYLE DB2SQL NO SQL DETERMINISTIC NO EXTERNAL ACTION

This example illustrates overloading of the UDF name, and shows that multiple UDFs can share the same body. Note that although a BLOB cannot be assigned to a CLOB, the same source code can be used. There is no programming problem in the above example as the programming interface for BLOB and CLOB between DB2

166

DB2 UDB for AS/400 SQL Programming Concepts V4R5

and UDF is the same; length followed by data. DB2 does not check if the UDF using a particular function body is in any way consistent with any other UDF using the same body.

Example: String search over UDT


This example is a continuation of the previous example. Say you are satisfied with the FINDSTRING functions from Example: BLOB string search on page 166, but now you have defined a distinct type BOAT with source type BLOB. You also want FINDSTRING to operate on values having data type BOAT, so you create another FINDSTRING function. This function is sourced on the FINDSTRING which operates on BLOB values in Example: BLOB string search on page 166. Note the further overloading of FINDSTRING in this example:
CREATE FUNCTION FINDSTRING (BOAT, VARCHAR(200)) RETURNS INT SPECIFIC "slick_fboat_mar95" SOURCE SPECIFIC "willie_fblob_feb95"

Note that this FINDSTRING function has a different signature from the FINDSTRING functions in Example: BLOB string search on page 166, so there is no problem overloading the name. You wish to provide your own specific name for possible later reference in DDL. Because you are using the SOURCE clause, you cannot use the EXTERNAL NAME clause or any of the related keywords specifying function attributes. These attributes are taken from the source function. Finally, observe that in identifying the source function you are using the specific function name explicitly provided in Example: BLOB string search on page 166. Because this is an unqualified reference, the schema in which this source function resides must be in the function path, or the reference will not be resolved.

Example: External function with UDT parameter


You have written another UDF to take a BOAT and examine its design attributes and generate a cost for the boat in Canadian dollars. Even though internally, the labor cost may be priced in German marks, or Japanese yen, or US dollars, this function needs to generate the cost to build the boat in the required currency, Canadian dollars. This means it has to get current exchange rate information from the exchange_rate file, managed outside of DB2, and the answer depends on what it finds in this file. This makes the function NOT DETERMINISTIC.
CREATE FUNCTION BOAT_COST (BOAT) RETURNS INTEGER EXTERNAL NAME 'MYLIB/COSTS(BOATCOST)' LANGUAGE C PARAMETER STYLE DB2SQL NO SQL NOT DETERMINISTIC NO EXTERNAL ACTION

Observe that CAST FROM and SPECIFIC are not specified, but that NOT DETERMINISTIC is specified.

Example: AVG over a UDT


This example implements the AVG column function over the CANADIAN_DOLLAR distinct type. See Example: Money on page 175 for the definition of CANADIAN_DOLLAR. Strong typing prevents you from using the built-in AVG function on a distinct type. It turns out that the source type for CANADIAN_DOLLAR was DECIMAL, and so you implement the AVG by
Chapter 8. Using the Object-Relational Capabilities

167

sourcing it on the AVG(DECIMAL) built-in function. The ability to do this depends on being able to cast from DECIMAL to CANADIAN_DOLLAR and vice versa, but since DECIMAL is the source type for CANADIAN_DOLLAR you know these casts will work.
CREATE FUNCTION AVG (CANADIAN_DOLLAR) RETURNS CANADIAN_DOLLAR SOURCE "QSYS2".AVG(DECIMAL(9,2))

Note that in the SOURCE clause you have qualified the function name, just in case there might be some other AVG function lurking in your SQL path.

Example: Counting
Your simple counting function returns a 1 the first time and increments the result by one each time it is called. This function takes no SQL arguments, and by definition it is a NOT DETERMINISTIC function since its answer varies from call to call. It uses the scratchpad to save the last value returned, and each time it is invoked it increments this value and returns it.
CREATE FUNCTION COUNTER () RETURNS INT EXTERNAL NAME 'MYLIB/MYFUNCS(CTR)' LANGUAGE C PARAMETER STYLE DB2SQL NO SQL NOT DETERMINISTIC NOT FENCED SCRATCHPAD 4 DISALLOW PARALLEL

Note that no parameter definitions are provided, just empty parentheses. The above function specifies SCRATCHPAD, and uses the default specification of NO FINAL CALL. In this case, the size of the scratchpad is set to only 4 bytes, which is sufficient for a counter. Since the COUNTER function requires that a single scratchpad be used to operate properly, DISALLOW PARALLEL is added to prevent DB2 from operating it in parallel.

Using UDFs
Scalar and column UDFs can be invoked within an SQL statement almost everywhere that an expression is valid. There are a few restrictions of UDF usage, however: v UDFs and system generated functions cannot be specified in check constraints. Check constraints also cannot contain references to the built-in functions DLVALUE, DLURLPATH, DLURLPATHONLY, DLURLSCHEME, DLURLCOMPLETE, or DLURLSERVER. v External UDFs, SQL UDFS and the built-in functions DLVALUE, DLURLPATH, DLURLPATHONLY, DLURLSCHEME, DLURLCOMPLETE, and DLURLSERVER cannot be referenced in an ORDER BY or GROUP BY clause, unless the SQL statement is read-only and allows temporary processing (ALWCPYDTA(*YES) or (*OPTIMIZE). The SQL Reference discusses all these contexts in detail. The discussion and examples used in this section focus on relatively simple SELECT statement contexts, but note that their use is not restricted to these contexts. Refer to UDF concepts on page 162 for a summary of the use and importance of the path and the function resolution algorithm. You can find the details for both of

168

DB2 UDB for AS/400 SQL Programming Concepts V4R5

these concepts in the SQL Reference. The resolution of any Data Manipulation Language (DML) reference to a function uses the function resolution algorithm, so it is important to understand how it works.

Referring to functions
Each reference to a function, whether it is a UDF, or a built-in function, contains the following syntax:
function_name ( ALL DISTINCT , expression )

In the above, function_name can be either an unqualified or a qualified function name. Note that when using the *SYS naming convention, functions cannot be qualified. The arguments can number from 0 to 90, and are expressions which may contain: v A column name, qualified or unqualified v A constant v A host variable v A special register v A parameter marker with a CAST function v An expression v A function The position of the arguments is important and must conform to the function definition for the semantics to be correct. Both the position of the arguments and the function definition must conform to the function body itself. DB2 does not attempt to shuffle arguments to better match a function definition, and DB2 does not attempt to determine the semantics of the individual function parameters.

Examples of function invocations


Some valid examples of function invocations are:
AVG(FLOAT_COLUMN) BLOOP(COLUMN1) BLOOP(FLOAT_COLUMN + CAST(? AS INTEGER)) BLOOP(:hostvar :indicvar) BRIAN.PARSE(CONCAT(CHAR_COLUMN,USER, 1, 0, 0, 1) CTR() FLOOR(FLOAT_COLUMN) PABLO.BLOOP(A+B) PABLO.BLOOP(:hostvar) "search_schema"(CURRENT PATH, 'GENE') SUBSTR(COLUMN2,8,3) QSYS2.FLOOR(AVG(EMP.SALARY)) QSYS2.AVG(QSYS2.FLOOR(EMP.SALARY)) QSYS2.SUBSTR(COLUMN2,11,LENGTH(COLUMN3))

Using parameter markers in functions


An important restriction involves parameter markers; you cannot simply code the following:
BLOOP(?)

Chapter 8. Using the Object-Relational Capabilities

169

As the function selection logic does not know what data type the argument may turn out to be, it cannot resolve the reference. You can use the CAST specification to provide a type for the parameter marker, for example INTEGER, and then the function selection logic can proceed:
BLOOP(CAST(? AS INTEGER))

Using qualified function reference


If you use a qualified function reference, you restrict DB2s search for a matching function to that schema. For example, you have the following statement:
SELECT PABLO.BLOOP(COLUMN1) FROM T

Only the BLOOP functions in schema PABLO are considered. It does not matter that user SERGE has defined a BLOOP function, or whether or not there is a built-in BLOOP function. Now suppose that user PABLO has defined two BLOOP functions in his schema:
CREATE FUNCTION BLOOP (INTEGER) RETURNS ... CREATE FUNCTION BLOOP (DOUBLE) RETURNS ...

BLOOP is thus overloaded within the PABLO schema, and the function selection algorithm would choose the best BLOOP, depending on the data type of the argument, column1. In this case, both of the PABLO.BLOOPs take numeric arguments, and if column1 is not one of the numeric types, the statement will fail. On the other hand if column1 is either SMALLINT or INTEGER, function selection will resolve to the first BLOOP, while if column1 is DECIMAL or DOUBLE, the second BLOOP will be chosen. Several points about this example: 1. It illustrates argument promotion. The first BLOOP is defined with an INTEGER parameter, yet you can pass it a SMALLINT argument. The function selection algorithm supports promotions among the built-in data types (for details, see the SQL Reference) and DB2 performs the appropriate data value conversions. 2. If for some reason you want to invoke the second BLOOP with a SMALLINT or INTEGER argument, you have to take an explicit action in your statement as follows:
SELECT PABLO.BLOOP(DOUBLE(COLUMN1)) FROM T

3. Alternatively, if you want to invoke the first BLOOP with a DECIMAL or DOUBLE argument, you have your choice of explicit actions, depending on your exact intent:
SELECT PABLO.BLOOP(INTEGER(COLUMN1)) FROM T SELECT PABLO.BLOOP(FLOOR(COLUMN1)) FROM T

You should investigate these other functions in the SQL Reference. The INTEGER function is a built-in function in the QSYS2 schema.

Using unqualified function reference


If, instead of a qualified function reference, you use an unqualified function reference, DB2s search for a matching function normally uses the function path to qualify the reference. In the case of the DROP FUNCTION or COMMENT ON FUNCTION functions, the reference is qualified using the current authorization ID, if they are unqualified for *SQL naming, or *LIBL for *SYS naming. Thus, it is important that you know what your function path is, and what, if any, conflicting

170

DB2 UDB for AS/400 SQL Programming Concepts V4R5

functions exist in the schemas of your current function path. For example, suppose you are PABLO and your static SQL statement is as follows, where COLUMN1 is data type INTEGER:
SELECT BLOOP(COLUMN1) FROM T

You have created the two BLOOP functions cited in Using qualified function reference on page 170, and you want and expect one of them to be chosen. If the following default function path is used, the first BLOOP is chosen (since column1 is INTEGER), if there is no conflicting BLOOP in QSYS or QSYS2:
"QSYS","QSYS2","PABLO"

However, suppose you have forgotten that you are using a script for precompiling and binding which you previously wrote for another purpose. In this script, you explicitly coded your SQLPATH parameter to specify the following function path for another reason that does not apply to your current work:
"KATHY","QSYS","QSYS2","PABLO"

If Kathy has written a BLOOP function for her own purposes, the function selection could very well resolve to Kathys function, and your statement would execute without error. You are not notified because DB2 assumes that you know what you are doing. It becomes your responsibility to identify the incorrect output from your statement and make the required correction.

Summary of function references


For both qualified and unqualified function references, the function selection algorithm looks at all the applicable functions, both built-in and user-defined, that have: v The given name v The same number of defined parameters as arguments in the function reference v Each parameter identical to or promotable from the type of the corresponding argument. (Applicable functions means functions in the named schema for a qualified reference, or functions in the schemas of the function path for an unqualified reference.) The algorithm looks for an exact match, or failing that, a best match among these functions. The current function path is used, in the case of an unqualified reference only, as the deciding factor if two identically good matches are found in different schemas. The details of the algorithm can be found in the SQL Reference. An interesting feature, illustrated by the examples at the end of Using qualified function reference on page 170, is the fact that function references can be nested, even references to the same function. This is generally true for built-in functions as well as UDFs; however, there are some limitations when column functions are involved. Refining an earlier example:
CREATE FUNCTION BLOOP (INTEGER) RETURNS INTEGER ... CREATE FUNCTION BLOOP (DOUBLE) RETURNS INTEGER ...

Now consider the following DML statement:


SELECT BLOOP( BLOOP(COLUMN1)) FROM T

If column1 is a DECIMAL or DOUBLE column, the inner BLOOP reference resolves to the second BLOOP defined above. Because this BLOOP returns an INTEGER, the outer BLOOP resolves to the first BLOOP.
Chapter 8. Using the Object-Relational Capabilities

171

Alternatively, if column1 is a SMALLINT or INTEGER column, the inner bloop reference resolves to the first BLOOP defined above. Because this BLOOP returns an INTEGER, the outer BLOOP also resolves to the first BLOOP. In this case, you are seeing nested references to the same function. A few additional points important for function references are: v You can define a function with the name of one of the SQL operators. For example, suppose you can attach some meaning to the "+" operator for values which have distinct type BOAT. You can define the following UDF:
CREATE FUNCTION "+" (BOAT, BOAT) RETURNS ...

Then you can write the following valid SQL statement:


SELECT "+"(BOAT_COL1, BOAT_COL2) FROM BIG_BOATS WHERE BOAT_OWNER = 'Nelson Mattos'

Note that you are not permitted to overload the built-in conditional operators such as >, =, LIKE, IN, and so on, in this way. v The function selection algorithm does not consider the context of the reference in resolving to a particular function. Look at these BLOOP functions, modified a bit from before:
CREATE FUNCTION BLOOP (INTEGER) RETURNS INTEGER ... CREATE FUNCTION BLOOP (DOUBLE) RETURNS CHAR(10)...

Now suppose you write the following SELECT statement:


SELECT 'ABCDEFG' CONCAT BLOOP(SMALLINT_COL) FROM T

Because the best match, resolved using the SMALLINT argument, is the first BLOOP defined above, the second operand of the CONCAT resolves to data type INTEGER. The statement fails because CONCAT demands string arguments. If the first BLOOP was not present, the other BLOOP would be chosen and the statement execution would be successful. v UDFs can be defined with parameters or results having any of the LOB types: BLOB, CLOB, or DBCLOB. DB2 will materialize the entire LOB value in storage before invoking such a function, even if the source of the value is a LOB locator host variable. For example, consider the following fragment of a C language application:
EXEC SQL BEGIN DECLARE SECTION; SQL TYPE IS CLOB(150K) clob150K ; SQL TYPE IS CLOB_LOCATOR clob_locator1; char string[40]; EXEC SQL END DECLARE SECTION; /* LOB host var */ /* LOB locator host var */ /* string host var */

Either host variable :clob150K or :clob_locator1 is valid as an argument for a function whose corresponding parameter is defined as CLOB(500K). Thus, referring to the FINDSTRING defined in Example: String search on page 166, both of the following are valid in the program:
... SELECT FINDSTRING (:clob150K, :string) FROM ... ... SELECT FINDSTRING (:clob_locator1, :string) FROM ...

v Non-SQL UDF parameters or results which have one of the LOB types can be created with the AS LOCATOR modifier. In this case, the entire LOB value is not materialized prior to invocation. Instead, a LOB LOCATOR is passed to the UDF. You can also use this capability on UDF parameters or results which have a distinct type that is based on a LOB. This capability is limited to non-SQL UDFs. Note that the argument to such a function can be any LOB value of the defined

172

DB2 UDB for AS/400 SQL Programming Concepts V4R5

type; it does not have to be a host variable defined as one of the LOCATOR types. The use of host variable locators as arguments is completely unrelated to the use of AS LOCATOR in UDF parameters and result definitions. v UDFs can be defined with distinct types as parameters or as the result. (Earlier examples have illustrated this.) DB2 will pass the value to the UDF in the format of the source data type of the distinct type. Distinct type values which originate in a host variable and which are used as arguments to a UDF which has its corresponding parameter defined as a distinct type, must be explicitly cast to the distinct type by the user. There is no host language type for distinct types. DB2s strong typing necessitates this. Otherwise your results may be ambiguous. So, consider the BOAT distinct type which is defined over a BLOB, and consider the BOAT_COST UDF from Example: External function with UDT parameter on page 167, which takes an object of type BOAT as its argument. In the following fragment of a C language application, the host variable :ship holds the BLOB value that is to passed to the BOAT_COST function:
EXEC SQL BEGIN DECLARE SECTION; SQL TYPE IS BLOB(150K) ship; EXEC SQL END DECLARE SECTION;

Both of the following statements correctly resolve to the BOAT_COST function, because both cast the :ship host variable to type BOAT:
... SELECT BOAT_COST (BOAT(:ship)) FROM ... ... SELECT BOAT_COST (CAST(:ship AS BOAT)) FROM ...

If there are multiple BOAT distinct types in the database, or BOAT UDFs in other schema, you must exercise care with your function path. Otherwise your results may be ambiguous.

User-defined distinct types (UDT)


A user-defined distinct type is a mechanism that allows you to extend DB2 capabilities beyond the built-in data types available. User-defined distinct types enable you to define new data types to DB2 which gives you considerable power since you are no longer restricted to using the system-supplied built-in data types to model your business and capture the semantics of your data. Distinct data types allow you to map on a one-to-one basis to existing database types. The following topics describe UDTs in more detail: v v v v v Why use UDTs? Defining a UDT on page 174 Defining tables with UDTs on page 175 Manipulating UDTs on page 176 Synergy between UDTs, UDFs, and LOBs on page 181

Why use UDTs?


There are several benefits associated with UDTs: 1. Extensibility. By defining new types, you can indefinitely increase the set of types provided by DB2 to support your applications.
Chapter 8. Using the Object-Relational Capabilities

173

2. Flexibility. You can specify any semantics and behavior for your new type by using user-defined functions (UDFs) to augment the diversity of the types available in the system. 3. Consistent behavior. Strong typing insures that your UDTs will behave appropriately. It guarantees that only functions defined on your UDT can be applied to instances of the UDT. 4. Encapsulation. The behavior of your UDTs is restricted by the functions and operators that can be applied on them. This provides flexibility in the implementation since running applications do not depend on the internal representation that you chose for your type. 5. Extensible behavior. The definition of user-defined functions on types can augment the functionality provided to manipulate your UDT at any time. (See User-defined functions (UDF) on page 160) 6. Foundation for object-oriented extensions. UDTs are the foundation for most object-oriented features. They represent the most important step towards object-oriented extensions.

Defining a UDT
UDTs, like other objects such as tables, indexes, and UDFs, need to be defined with a CREATE statement. Use the CREATE DISTINCT TYPE statement to define your new UDT. Detailed explanations for the statement syntax and all its options are found in the SQL Reference. For the CREATE DISTINCT TYPE statement, note that: 1. The name of the new UDT can be a qualified or an unqualified name. 2. The source type of the UDT is the type used by DB2 to internally represent the UDT. For this reason, it must be a built-in data type. Previously defined UDTs cannot be used as source types of other UDTs. As part of a UDT definition, DB2 always generates cast functions to: v Cast from the UDT to the source type, using the standard name of the source type. For example, if you create a distinct type based on FLOAT, the cast function called DOUBLE is created. v Cast from the source type to the UDT. See the SQL Reference for a discussion of when additional casts to the UDTs are generated. These functions are important for the manipulation of UDTs in queries.

Resolving unqualified UDTs


The function path is used to resolve any references to an unqualified type name or function, except if the type name or function is v Created v Dropped v Commented on.

174

DB2 UDB for AS/400 SQL Programming Concepts V4R5

For information on how unqualified function references are resolved, see Using qualified function reference on page 170.

Examples: Using CREATE DISTINCT TYPE


The following are examples of using CREATE DISTINCT TYPE: v Example: Money v Example: Resume

Example: Money
Suppose you are writing applications that need to handle different currencies and wish to ensure that DB2 does not allow these currencies to be compared or manipulated directly with one another in queries. Remember that conversions are necessary whenever you want to compare values of different currencies. So you define as many UDTs as you need; one for each currency that you may need to represent:
CREATE DISTINCT TYPE US_DOLLAR AS DECIMAL (9,2) CREATE DISTINCT TYPE CANADIAN_DOLLAR AS DECIMAL (9,2) CREATE DISTINCT TYPE GERMAN_MARK AS DECIMAL (9,2)

Example: Resume
Suppose you would like to keep the form filled by applicants to your company in a DB2 table and you are going to use functions to extract the information from these forms. Because these functions cannot be applied to regular character strings (because they are certainly not able to find the information they are supposed to return), you define a UDT to represent the filled forms:
CREATE DISTINCT TYPE PERSONAL.APPLICATION_FORM AS CLOB(32K)

Defining tables with UDTs


After you have defined several UDTs, you can start defining tables with columns whose types are UDTs. Following are examples using CREATE TABLE: v Example: Sales v Example: Application forms

Example: Sales
Suppose you want to define tables to keep your companys sales in different countries as follows:
CREATE TABLE US_SALES (PRODUCT_ITEM INTEGER, MONTH INTEGER CHECK (MONTH BETWEEN 1 AND 12), YEAR INTEGER CHECK (YEAR > 1985), TOTAL US_DOLLAR) CREATE TABLE CANADIAN_SALES (PRODUCT_ITEM INTEGER, MONTH INTEGER CHECK (MONTH BETWEEN 1 AND 12), YEAR INTEGER CHECK (YEAR > 1985), TOTAL CANADIAN_DOLLAR) CREATE TABLE GERMAN_SALES (PRODUCT_ITEM INTEGER, MONTH INTEGER CHECK (MONTH BETWEEN 1 AND 12), YEAR INTEGER CHECK (YEAR > 1985), TOTAL GERMAN_MARK)
Chapter 8. Using the Object-Relational Capabilities

175

The UDTs in the above examples are created using the same CREATE DISTINCT TYPE statements in Example: Money on page 175. Note that the above examples use check constraints. For information on check constraints see the SQL Reference.

Example: Application forms


Suppose you need to define a table where you keep the forms filled out by applicants as follows:
CREATE TABLE APPLICATIONS (ID INTEGER, NAME VARCHAR (30), APPLICATION_DATE DATE, FORM PERSONAL.APPLICATION_FORM)

You have fully qualified the UDT name because its qualifier is not the same as your authorization ID and you have not changed the default function path. Remember that whenever type and function names are not fully qualified, DB2 searches through the schemas listed in the current function path and looks for a type or function name matching the given unqualified name. .

Manipulating UDTs
One of the most important concepts associated with UDTs is strong typing. Strong typing guarantees that only functions and operators defined on the UDT can be applied to its instances. Strong typing is important to ensure that the instances of your UDTs are correct. For example, if you have defined a function to convert US dollars to Canadian dollars according to the current exchange rate, you do not want this same function to be used to convert German marks to Canadian dollars because it will certainly return the wrong amount. As a consequence of strong typing, DB2 does not allow you to write queries that compare, for example, UDT instances with instances of the UDT source type. For the same reason, DB2 will not let you apply functions defined on other types to UDTs. If you want to compare instances of UDTs with instances of another type, you have to cast the instances of one or the other type. In the same sense, you have to cast the UDT instance to the type of the parameter of a function that is not defined on a UDT if you want to apply this function to a UDT instance.

Examples of manipulating UDTs


The following are examples of manipulating UDTs: v Example: Comparisons between UDTs and constants v Example: Casting between UDTs v Example: Comparisons involving UDTs v Example: Sourced UDFs involving UDTs v Example: Assignments involving UDTs v Example: Assignments in dynamic SQL v Example: Assignments involving different UDTs v Example: Use of UDTs in UNION

176

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Example: Comparisons between UDTs and constants


Suppose you want to know which products sold more than US $100 000.00 in the US in the month of July, 1992 (7/92).
SELECT PRODUCT_ITEM FROM US_SALES WHERE TOTAL > US_DOLLAR (100000) AND month = 7 AND year = 1992

Because you cannot compare US dollars with instances of the source type of US dollars (that is, DECIMAL) directly, you have used the cast function provided by DB2 to cast from DECIMAL to US dollars. You can also use the other cast function provided by DB2 (that is, the one to cast from US dollars to DECIMAL) and cast the column total to DECIMAL. Either way you decide to cast, from or to the UDT, you can use the cast specification notation to perform the casting, or the functional notation. That is, you could have written the above query as:
SELECT PRODUCT_ITEM FROM US_SALES WHERE TOTAL > CAST (100000 AS us_dollar) AND MONTH = 7 AND YEAR = 1992

Example: Casting between UDTs


Suppose you want to define a UDF that converts Canadian dollars to U.S. dollars. Suppose you can obtain the current exchange rate from a file managed outside of DB2. You would then define a UDF that obtains a value in Canadian dollars, accesses the exchange rate file, and returns the corresponding amount in U.S. dollars. At first glance, such a UDF may appear easy to write. However, not all C compilers support DECIMAL values. The UDTs representing different currencies have been defined as DECIMAL. Your UDF will need to receive and return DOUBLE values, since this is the only data type provided by C that allows the representation of a DECIMAL value without losing the decimal precision. Thus, your UDF should be defined as follows:
CREATE FUNCTION CDN_TO_US_DOUBLE(DOUBLE) RETURNS DOUBLE EXTERNAL NAME 'MYLIB/CURRENCIES(C_CDN_US)' LANGUAGE C PARAMETER STYLE DB2SQL NO SQL NOT DETERMINISTIC

The exchange rate between Canadian and U.S. dollars may change between two invocations of the UDF, so you declare it as NOT DETERMINISTIC. The question now is, how do you pass Canadian dollars to this UDF and get U.S. dollars from it? The Canadian dollars must be cast to DECIMAL values. The DECIMAL values must be cast to DOUBLE. You also need to have the returned DOUBLE value cast to DECIMAL and the DECIMAL value cast to U.S. dollars. Such casts are performed automatically by DB2 anytime you define sourced UDFs, whose parameter and return type do not exactly match the parameter and return type of the source function. Therefore, you need to define two sourced UDFs. The first brings the DOUBLE values to a DECIMAL representation. The second brings the DECIMAL values to the UDT. That is, you define the following:

Chapter 8. Using the Object-Relational Capabilities

177

CREATE FUNCTION CDN_TO_US_DEC (DECIMAL(9,2)) RETURNS DECIMAL(9,2) SOURCE CDN_TO_US_DOUBLE (DOUBLE) CREATE FUNCTION US_DOLLAR (CANADIAN_DOLLAR) RETURNS US_DOLLAR SOURCE CDN_TO_US_DEC (DECIMAL())

Note that an invocation of the US_DOLLAR function as in US_DOLLAR(C1), where C1 is a column whose type is Canadian dollars, has the same effect as invoking:
US_DOLLAR (DECIMAL(CDN_TO_US_DOUBLE (DOUBLE (DECIMAL (C1)))))

That is, C1 (in Canadian dollars) is cast to decimal which in turn is cast to a double value that is passed to the CDN_TO_US_DOUBLE function. This function accesses the exchange rate file and returns a double value (representing the amount in U.S. dollars) that is cast to decimal, and then to U.S. dollars. A function to convert German marks to U.S. dollars would be similar to the example above:
CREATE FUNCTION GERMAN_TO_US_DOUBLE(DOUBLE) RETURNS DOUBLE EXTERNAL NAME 'MYLIB/CURRENCIES(C_GER_US)' LANGUAGE C PARAMETER STYLE DB2SQL NO SQL NOT DETERMINISTIC CREATE FUNCTION GERMAN_TO_US_DEC (DECIMAL(9,2)) RETURNS DECIMAL(9,2) SOURCE GERMAN_TO_US_DOUBLE(DOUBLE) CREATE FUNCTION US_DOLLAR(GERMAN_MARK) RETURNS US_DOLLAR SOURCE GERMAN_TO_US_DEC (DECIMAL())

Example: Comparisons involving UDTs


Suppose you want to know which products sold more in the US than in Canada and Germany for the month of March, 1989 (3/89):
SELECT US.PRODUCT_ITEM, US.TOTAL FROM US_SALES AS US, CANADIAN_SALES AS CDN, GERMAN_SALES AS GERMAN WHERE US.PRODUCT_ITEM = CDN.PRODUCT_ITEM AND US.PRODUCT_ITEM = GERMAN.PRODUCT_ITEM AND US.TOTAL > US_DOLLAR (CDN.TOTAL) AND US.TOTAL > US_DOLLAR (GERMAN.TOTAL) AND US.MONTH = 3 AND US.YEAR = 1989 AND CDN.MONTH = 3 AND CDN.YEAR = 1989 AND GERMAN.MONTH = 3 AND GERMAN.YEAR = 1989

Because you cannot directly compare US dollars with Canadian dollars or German Marks, you use the UDF to cast the amount in Canadian dollars to US dollars, and the UDF to cast the amount in German Marks to US dollars. You cannot cast them all to DECIMAL and compare the converted DECIMAL values because the amounts are not monetarily comparable. That is, the amounts are not in the same currency.

Example: Sourced UDFs involving UDTs


Suppose you have defined a sourced UDF on the built-in SUM function to support SUM on German Marks:

178

DB2 UDB for AS/400 SQL Programming Concepts V4R5

CREATE FUNCTION SUM (GERMAN_MARKS) RETURNS GERMAN_MARKS SOURCE SYSIBM.SUM (DECIMAL())

You want to know the total of sales in Germany for each product in the year of 1994. You would like to obtain the total sales in US dollars:
SELECT PRODUCT_ITEM, US_DOLLAR (SUM (TOTAL)) FROM GERMAN_SALES WHERE YEAR = 1994 GROUP BY PRODUCT_ITEM

You could not write SUM (us_dollar (total)), unless you had defined a SUM function on US dollar in a manner similar to the above.

Example: Assignments involving UDTs


Suppose you want to store the form filled by a new applicant into the database. You have defined a host variable containing the character string value used to represent the filled form:
EXEC SQL BEGIN DECLARE SECTION; SQL TYPE IS CLOB(32K) hv_form; EXEC SQL END DECLARE SECTION; /* Code to fill hv_form */ INSERT INTO APPLICATIONS VALUES (134523, 'Peter Holland', CURRENT DATE, :hv_form)

You do not explicitly invoke the cast function to convert the character string to the UDT personal.application_form . This is because DB2 lets you assign instances of the source type of a UDT to targets having that UDT.

Example: Assignments in dynamic SQL


If you want to use the same statement given in Example: Assignments involving UDTs in dynamic SQL, you can use parameter markers as follows:
EXEC SQL BEGIN DECLARE SECTION; long id; char name[30]; SQL TYPE IS CLOB(32K) form; char command[80]; EXEC SQL END DECLARE SECTION; /* Code to fill host variables */ strcpy(command,"INSERT INTO APPLICATIONS VALUES"); strcat(command,"(?, ?, CURRENT DATE, ?)"); EXEC SQL PREPARE APP_INSERT FROM :command; EXEC SQL EXECUTE APP_INSERT USING :id, :name, :form;

You made use of DB2s cast specification to tell DB2 that the type of the parameter marker is CLOB(32K), a type that is assignable to the UDT column. Remember that you cannot declare a host variable of a UDT type, since host languages do not support UDTs. Therefore, you cannot specify that the type of a parameter marker is a UDT.

Chapter 8. Using the Object-Relational Capabilities

179

Example: Assignments involving different UDTs


Suppose you have defined two sourced UDFs on the built-in SUM function to support SUM on US and Canadian dollars, similar to the UDF sourced on German Marks in Example: Sourced UDFs involving UDTs on page 178:
CREATE FUNCTION SUM (CANADIAN_DOLLAR) RETURNS CANADIAN_DOLLAR SOURCE SYSIBM.SUM (DECIMAL()) CREATE FUNCTION SUM (US_DOLLAR) RETURNS US_DOLLAR SOURCE SYSIBM.SUM (DECIMAL())

Now suppose your supervisor requests that you maintain the annual total sales in US dollars of each product and in each country, in separate tables:
CREATE TABLE US_SALES_94 (PRODUCT_ITEM INTEGER, TOTAL US_DOLLAR) CREATE TABLE GERMAN_SALES_94 (PRODUCT_ITEM INTEGER, TOTAL US_DOLLAR) CREATE TABLE CANADIAN_SALES_94 (PRODUCT_ITEM INTEGER, TOTAL US_DOLLAR) INSERT INTO US_SALES_94 SELECT PRODUCT_ITEM, SUM (TOTAL) FROM US_SALES WHERE YEAR = 1994 GROUP BY PRODUCT_ITEM INSERT INTO GERMAN_SALES_94 SELECT PRODUCT_ITEM, US_DOLLAR (SUM (TOTAL)) FROM GERMAN_SALES WHERE YEAR = 1994 GROUP BY PRODUCT_ITEM INSERT INTO CANADIAN_SALES_94 SELECT PRODUCT_ITEM, US_DOLLAR (SUM (TOTAL)) FROM CANADIAN_SALES WHERE YEAR = 1994 GROUP BY PRODUCT_ITEM

You explicitly cast the amounts in Canadian dollars and German Marks to US dollars since different UDTs are not directly assignable to each other. You cannot use the cast specification syntax because UDTs can only be cast to their own source type.

Example: Use of UDTs in UNION


Suppose you would like to provide your American users with a view containing all the sales of every product of your company:
CREATE VIEW ALL_SALES AS SELECT PRODUCT_ITEM, MONTH, YEAR, TOTAL FROM US_SALES UNION SELECT PRODUCT_ITEM, MONTH, YEAR, US_DOLLAR (TOTAL)

180

DB2 UDB for AS/400 SQL Programming Concepts V4R5

FROM CANADIAN_SALES UNION SELECT PRODUCT_ITEM, MONTH, YEAR, US_DOLLAR (TOTAL) FROM GERMAN_SALES

You cast Canadian dollars to US dollars and German Marks to US dollars because UDTs are union compatible only with the same UDT. You must use the functional notation to cast between UDTs since the cast specification only lets you cast between UDTs and their source types.

Synergy between UDTs, UDFs, and LOBs


In previous sections, you learned how to define and use the individual DB2 object extensions (UDTs, UDFs, and LOBs). However, as you will see in this section, there is a lot of synergy between these three object extensions.

Combining UDTs, UDFs, and LOBs


According to the concept of object-orientation, similar objects in the application domain are grouped into related types. Each of these types have a name, an internal representation, and behavior. By using UDTs, you can tell DB2 the name of your new type and how it is internally represented. A LOB is one of the possible internal representations for your new type and is the most suitable representation for large, complex structures. By using UDFs, you can define the behavior of the new type. Consequently, there is an important synergy between UDTs, UDFs, and LOBs. An application type with a complex data structure and behavior is modeled as a UDT that is internally represented as a LOB, with its behavior implemented by UDFs. The rules governing the semantic integrity of your application type will be represented as constraints and triggers. To have better control and organization of your related UDTs and UDFs, you should keep them in the same schema.

Examples of complex applications


The following examples show how you can use UDTs, UDFs, and LOBs together in complex applications: Example: Defining the UDT and UDFs Example: Exploiting LOB function to populate the database Example: Exploiting UDFs to query instances of UDTs Example: Exploiting LOB locators to manipulate UDT instances

Example: Defining the UDT and UDFs


Suppose you would like to keep the electronic mail (e-mail) sent to your company in DB2 tables. Ignoring any issues of privacy, you plan to write queries over such e-mail to find out their subject, how often your e-mail service is used to receive customer orders, and so on. E-mail can be quite large, and it has a complex internal structure (a sender, a receiver, the subject, date, and the e-mail content). Therefore, you decide to represent the e-mail by means of a UDT whose source type is a large object. You define a set of UDFs on your e-mail type, such as functions to extract the subject of the e-mail, the sender, the date, and so on. You also define functions that can perform searches on the content of the e-mail. You do the above using the following CREATE statements:
CREATE DISTINCT TYPE E_MAIL AS BLOB (1M) CREATE FUNCTION SUBJECT (E_MAIL) RETURNS VARCHAR (200)
Chapter 8. Using the Object-Relational Capabilities

181

EXTERNAL NAME 'LIB/PGM(SUBJECT)' LANGUAGE C PARAMETER STYLE DB2SQL NO SQL DETERMINISTIC NO EXTERNAL ACTION CREATE FUNCTION SENDER (E_MAIL) RETURNS VARCHAR (200) EXTERNAL NAME 'LIB/PGM(SENDER)' LANGUAGE C PARAMETER STYLE DB2SQL NO SQL DETERMINISTIC NO EXTERNAL ACTION CREATE FUNCTION RECEIVER (E_MAIL) RETURNS VARCHAR (200) EXTERNAL NAME 'LIB/PGM(RECEIVER)' LANGUAGE C PARAMETER STYLE DB2SQL NO SQL DETERMINISTIC NO EXTERNAL ACTION CREATE FUNCTION SENDING_DATE (E_MAIL) RETURNS DATE CAST FROM VARCHAR(10) EXTERNAL NAME 'LIB/PGM(SENDING_DATE)' LANGUAGE C PARAMETER STYLE DB2SQL NO SQL DETERMINISTIC NO EXTERNAL ACTION CREATE FUNCTION CONTENTS (E_MAIL) RETURNS BLOB (1M) EXTERNAL NAME 'LIB/PGM(CONTENTS)' LANGUAGE C PARAMETER STYLE DB2SQL NO SQL DETERMINISTIC NO EXTERNAL ACTION CREATE FUNCTION CONTAINS (E_MAIL, VARCHAR (200)) RETURNS INTEGER EXTERNAL NAME 'LIB/PGM(CONTAINS)' LANGUAGE C PARAMETER STYLE DB2SQL NO SQL DETERMINISTIC NO EXTERNAL ACTION CREATE TABLE ELECTRONIC_MAIL (ARRIVAL_TIMESTAMP TIMESTAMP, MESSAGE E_MAIL)

Example: Exploiting LOB function to populate the database


Suppose you populate your table by transferring your e-mail that is maintained in files into DB2. You would execute the following INSERT statement multiple times with different values of the HV_EMAIL_FILE until you have stored all your e_mail into DB2:
EXEC SQL BEGIN DECLARE SECTION SQL TYPE IS BLOB_FILE HV_EMAIL_FILE; EXEC SQL END DECLARE SECTION

182

DB2 UDB for AS/400 SQL Programming Concepts V4R5

strcpy (HV_EMAIL_FILE.NAME, "/u/mail/email/mbox"); HV_EMAIL_FILE.NAME_LENGTH = strlen(HV_EMAIL_FILE.NAME); HV_EMAIL_FILE.FILE_OPTIONS = 2; EXEC SQL INSERT INTO ELECTRONIC_MAIL VALUES (CURRENT TIMESTAMP, :hv_email_file);

All the function provided by DB2 LOB support is applicable to UDTs whose source type are LOBs. Therefore, you have used LOB file reference variables to assign the contents of the file into the UDT column. You have not used the cast function to convert values of BLOB type into your e-mail type. This is because DB2 let you assign values of the source type of a distinct type to targets of the distinct type.

Example: Exploiting UDFs to query instances of UDTs


Suppose you need to know how much e-mail was sent by a specific customer regarding customer orders and you have the e-mail address of your customers in the customers table.
SELECT COUNT (*) FROM ELECTRONIC_MAIL AS EMAIL, CUSTOMERS WHERE SUBJECT (EMAIL.MESSAGE) = 'customer order' AND CUSTOMERS.EMAIL_ADDRESS = SENDER (EMAIL.MESSAGE) AND CUSTOMERS.NAME = 'Customer X'

You have used the UDFs defined on the UDT in this SQL query since they are the only means to manipulate the UDT. In this sense, your UDT e-mail is completely encapsulated. That is, its internal representation and structure are hidden and can only be manipulated by the defined UDFs. These UDFs know how to interpret the data without the need to expose its representation. Suppose you need to know the details of all the e-mail your company received in 1994 which had to do with the performance of your products in the marketplace.
SELECT SENDER (MESSAGE), SENDING_DATE (MESSAGE), SUBJECT (MESSAGE) FROM ELECTRONIC_MAIL WHERE CONTAINS (MESSAGE, '"performance" AND "products" AND "marketplace"') = 1

You have used the contains UDF which is capable of analyzing the contents of the message searching for relevant keywords or synonyms.

Example: Exploiting LOB locators to manipulate UDT instances


Suppose you would like to obtain information about a specific e-mail without having to transfer the entire e-mail into a host variable in your application program. (Remember that an e-mail can be quite large.) Since your UDT is defined on a LOB, you can use LOB locators for that purpose:
EXEC SQL BEGIN DECLARE SECTION long hv_len; char hv_subject[200]; char hv_sender[200]; char hv_buf[4096]; char hv_current_time[26]; SQL TYPE IS BLOB_LOCATOR hv_email_locator; EXEC SQL END DECLARE SECTION EXEC SQL SELECT MESSAGE INTO :hv_email_locator FROM ELECTRONIC MAIL
Chapter 8. Using the Object-Relational Capabilities

183

WHERE ARRIVAL_TIMESTAMP = :hv_current_time; EXEC SQL VALUES (SUBJECT (E_MAIL(:hv_email_locator)) INTO :hv_subject; .... code that checks if the subject of the e_mail is relevant .... .... if the e_mail is relevant, then............................... EXEC SQL VALUES (SENDER (CAST (:hv_email_locator AS E_MAIL))) INTO :hv_sender;

Because your host variable is of type BLOB locator (the source type of the UDT), you have explicitly converted the BLOB locator to your UDT, whenever it was used as an argument of a UDF defined on the UDT.

Using DataLinks
The DataLink data type is one of the basic building blocks for extending the types of data that can be stored in database files. The idea of a DataLink is that the actual data stored in the column is only a pointer to the object. This object can be anything, an image file, a voice recording, a text file, etc. The method used for resolving to the object is to store a Uniform Resource Locator (URL). This means that a row in a table can be used to contain information about the object in traditional data types, and the object itself can be referenced using the DataLink data type. The user can use new SQL scalar functions to get back the path to the object and the server on which the object is stored. With the DataLink data type, there is a fairly loose relationship between the row and the object. For instance, deleting a row will sever the relationship to the object referenced by the DataLink, but the object itself might not be deleted. An SQL table created with a DataLink column can be used to hold information about an object, without actually containing the object itself. This concept gives the user much more flexibility in the types of data that can be managed using an SQL table. If, for instance, the user has thousands of video clips stored in the integrated file system of their AS/400, they may want to use an SQL table to contain information about these video clips. But since the user already has the objects stored in a directory, they simply want the SQL table to contain references to the objects, not contain the actual bytes of storage. A good solution would be to use DataLinks. The SQL table would use traditional SQL data types to contain information about each clip, such as title, length, date, etc. But the clip itself would be referenced using a DataLink column. Each row in the table would store a URL for the object and an optional comment. Then an application that is working with the clips can retrieve the URL using SQL interfaces, and then use a browser or other playback software to work with the URL and display the video clip. There are several advantages to using this technique: v The integrated file system can store any type of stream file. v The integrated file system can store extremely large objects, that would not fit into a character column, or perhaps even a LOB column. v The hierarchical nature of the integrated file system is well-suited to organizing and working with the stream file objects. v By leaving the bytes of the object outside the database and in the integrated file system, applications can achieve better performance by allowing the SQL runtime engine to handle queries and reports, and allowing the file system to handle streaming of video, displaying images, text, etc.

184

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Using DataLinks also gives control over the objects while they are in linked status. A DataLink column can be created such that the referenced object cannot be deleted, moved, or renamed while there is a row in the SQL table that references that object. This object would be considered linked. Once the row containing that reference is deleted, the object is unlinked. To understand this concept fully, one should know the levels of control that can be specified when creating a DataLink column. Refer to the SQL Reference for the exact syntax used when creating DataLink columns.

NO LINK CONTROL
When a column is created with NO LINK CONTROL, there is no linking that takes place when rows are added to the SQL table. The URL is verified to be syntactically correct, but there is no check to make sure that the server is accessible, or that the file even exists.

FILE LINK CONTROL (with File System Permissions)


When the DataLink column is created as FILE LINK CONTROL with file system (FS) permissions, the system will verify that any DataLink value is a valid URL, with a valid server name and file name. The file must exist at the time that row is being inserted into the SQL table. When the object is found, it will be marked as linked. This means that the object cannot be moved, deleted, or renamed during the time that it is linked. Also, an object cannot be linked more than once. If the server name portion of the URL specifies a remote system, that system must be accessible. If a row containing a DataLink value is deleted, the object is unlinked. If a DataLink value is updated to a different value, the old object is unlinked, and the new object is linked. The integrated file system is still responsible for managing permissions for the linked object. The permissions are not modified during the link or unlink processes. This option provides control of the objects existence for the duration of time that it is linked.

FILE LINK CONTROL (with Database Permissions)


When the DataLink column is create as FILE LINK CONTROL with database permissions, the URL is verified, and all existing permissions to the object are removed. The ownership of the object is changed to a special system-supplied user profile. During the time that the object is linked, the only access to the object is by obtaining the URL from the SQL table that has the object linked. This is handled by using a special access token that is appended to the URL returned by SQL. Without the access token, all attempts to access the object will fail with an authority violation. If the URL with the access token is retrieved from the SQL table by normal means (FETCH, SELECT INTO, etc.) the file system filter will validate the access token and allow the access to the object. This option provides the control of preventing updates to the linked object for users trying to access the object by direct means. Since the only access to the object is by obtaining the access token from an SQL operation, an administrator can effectively control access to the linked objects by using the database permissions to the SQL table that contains the DataLink column.

Chapter 8. Using the Object-Relational Capabilities

185

Commands used for working with DataLinks


Support for the DataLink data type can be broken down into 3 different components: 1. The DB2 database support has a data type called DATALINK. This can be specified on SQL statements such as CREATE TABLE and ALTER TABLE. The column cannot have any default other than NULL. Access to the data must be using SQL interfaces. This is because the DATALINK itself is not compatible with any host variable type. SQL scalar functions can be used to retrieve the DATALINK value in character form. There is a DLVALUE scalar function that must be used in SQL to INSERT and UPDATE the values in the column. 2. The DataLink File Manager (DLFM) is the component that maintains the link status for the files on a server, and keeps track of meta-data for each file. This code handles linking, unlinking, and commitment control issues. An important aspect of DataLinks is that the DLFM need not be on the same physical system as the SQL table that contains the DataLink column. So an SQL table can link an object that resides in either the same systems integrated file system, or a remote AS/400s integrated file system. 3. The DataLink filter must be executed when the file system tries operations against files that are in directories designated as containing linked objects. This component determines if the file is linked, and optionally, if the user is authorized to access the file. If the file name includes an access token, the token will be verified. Since there is extra overhead in this filter process, it is only executed when the accessed object exists in one of the directories within a DataLink prefix. See the discussion below on prefixes. When working with DataLinks, there are several steps that must be taken to properly configure the system: v TCP/IP must be configured on any systems that are going to be used when working with DataLinks. This would include the systems on which the SQL tables with DataLink columns are going to be created, as well as the systems that will contain the objects to be linked. In most cases, this will be the same system. Since the URL that is used to reference the object contains a TCP/IP server name, this name must be recognized by the system that is going to contain the DataLink. The command CFGTCP can be used to configure the TCP/IP names, or to register a TCP/IP name server. v The system that contains the SQL tables must have the Relational Database Directory updated to reflect the local database system, and any optional remote systems. The command WRKRDBDIRE can be used to add or modify information in this directory. For consistency, it is recommended that the same names be used as the TCP/IP server name and the Relational Database name. v The DLFM server must be started on any systems that will contain objects to be linked. The command STRTCPSVR *DLFM can be used to start the DLFM server. The DLFM server can be ended by using the CL command ENDTCPSVR *DLFM. Once the DLFM has been started, there are some steps needed to configure the DLFM. These DLFM functions are available via an executable script that can be entered from the QShell interface. To get to the interactive shell interface, use the CL command QSH. This will bring up a command entry screen from which you can enter the DLFM script commands. The script command dfmadmin -help can be used to display help text and syntax diagrams. For the most commonly used functions, CL commands have also been provided. Using the CL commands, most or all of the DLFM configuration can be accomplished without using the script

186

DB2 UDB for AS/400 SQL Programming Concepts V4R5

interface. Depending on your preferences, you can choose to use either the script commands from the QSH command entry screen or the CL commands from the CL command entry screen. Since these functions are meant for a system administrator or a database administrator, they all require the *IOSYSCFG special authority. Adding a prefix - A prefix is a path or directory that will contain objects to be linked. When setting up the DLFM on a system, the administrator must add any prefixes that will be used for DataLinks. The script command dfmadmin -add_prefix is used to add prefixes. The CL command to add prefixes is ADDPFXDLFM. For instance, on server TESTSYS1, there is a directory called /mydir/datalinks/ that contains the objects that will be linked. The administrator uses the command ADDPFXDLFM PREFIX((/mydir/datalinks/)) to add the prefix. Now links for URLs such as:
http://TESTSYS1/mydir/datalinks/videos/file1.mpg or file://TESTSYS1/mydir/datalinks/text/story1.txt

would be valid since their path begins with a valid prefix. It is also possible to remove a prefix using the script command dfmadmin -del_prefix. This is not a commonly used function since it can only be executed if there are no linked objects anywhere in the directory structure contained within the prefix name. Adding a Host Database - A host database is a relational database system from which a link request originates. If the DLFM is on the same system as the SQL tables that will contain the DataLinks, then only the local database name needs to be added. If the DLFM will have link requests coming from remote systems, then all of their names must be registered with the DLFM. The script command to add a host database is dfmadmin -add_db and the CL command is ADDHDBDLFM. This function also requires that the libraries containing the SQL tables also be registered. For instance, on server TESTSYS1, where you have already added the /mydir/datalinks/ prefix, you want SQL tables on the local system in either library TESTDB or PRODDB to be allowed to link objects on this server. Use the following command: ADDHDBDLFM HOSTDBLIB((TESTDB) (PRODDB)) HOSTDB(TESTSYS1) Once the DLFM has been started, and the prefixes and host database names have been registered, you can begin linking objects in the file system.

Chapter 8. Using the Object-Relational Capabilities

187

188

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Chapter 9. Writing User-Defined Functions (UDFs)


User Defined Functions (UDFs) consist of three types: sourced, external, and SQL. Sourced function UDFs call other functions to perform the operation. SQL and external function UDFs require that you write and execute separate code. This chapter is about writing SQL and external functions. To write external and SQL functions, you need to do the following: v understand the UDF runtime environment v register the UDF, so that it is known to the database v write the function code to perform the function and pass the appropriate parameters v debug and test the function.

UDF runtime environment


There are several things to consider about the environment in which a UDF executes and the limitations of that environment. These factors should be considered carefully if you are contemplating writing complex function code for UDFs.

Length of time that the UDF runs


UDFs are invoked from within an SQL statement execution, which is normally a query operation that potentially runs against thousands of rows in a table. Because of this, the UDF needs to be invoked from a low level of the database. As a consequence of being invoked from such a low level, there are certain resources (locks and seizes) being held at the time the UDF is invoked and for the duration of the UDF execution. These resources are primarily locks on any tables and indexes involved in the SQL statement that is invoking the UDF. Due to these held resources, it is important that the UDF not perform operations that may take an extended period of time (minutes or hours). Because of the critical nature of holding resources for long periods of time, the database only waits for a certain period of time for the UDF to finish. If the UDF does not finish in the time allocated, the SQL statement will fail, which can be quite aggravating to the end user. The default UDF wait time used by the database should be more than sufficient to allow a normal UDF to run to completion. However, if you have a long running UDF and wish to increase the wait time, this can be done using the UDF_TIME_OUT option in the query INI file. See Query Options File QAQQINI in the Database Performance and Query Optimization information for details on the INI file. Note, however, that there is a maximum time limit that the database will not exceed, regardless of the value specified for UDF_TIME_OUT. Since resources are held while the UDF is run, it is important that the UDF not operate on the same tables or indexes allocated for the original SQL statement or, if it does, that it does not perform an operation that conflicts with the one being performed in the SQL statement. Specifically, the UDF should not try to perform any insert, update or delete record operation on those tables.

Copyright IBM Corp. 2000

189

Threads considerations
A UDF runs in the same job as the SQL statement that invoked it. However, the UDF runs in a system thread, separate from the thread that is running the SQL statement. For more information about threads, see Database considerations for multithreaded programming in the Programming category of the Information Center. Because the UDF runs in the same job as the SQL statement, it shares much of the same environment as the SQL statement. However, because it runs under a separate thread, the following threads considerations apply: v the UDF will conflict with thread level resources held by the SQL statements thread. Primarily, these are the table resources discussed above. v UDFs do not inherit any program adopted authority that may have been active at the time the SQL statement was invoked. UDF authority comes from either the authority associated with the UDF program itself or the authority of the user running the SQL statement. v the UDF cannot perform any operation that is blocked from being run in a secondary thread. v the UDF program must be created such that it either runs under a named activation group or in the activation group of its caller (ACTGRP parameter). Programs that specify ACTGRP(*NEW) will not be allowed to run as UDFs.

Parallel processing
A UDF can be defined to allow parallel processing. This means that the same UDF program can be running in multiple threads at the same time. Therefore, if ALLOW PARALLEL is specified for the UDF, ensure that it is thread safe. For more information about threads, see Database considerations for multithreaded programming in the Programming category of the Information Center.

Writing function code


Writing function code involves knowing how to write the SQL or external function to perform the function. It also involves understanding the interface between the database and the function code to define it correctly, and determining packaging options when creating the executable program.

Writing UDFs as SQL functions


SQL functions are UDFs that you have defined, written, and registered using the CREATE FUNCTION statement. As such, they are written using only the SQL language and their definition is completely contained within one (potentially large) CREATE FUNCTION statement. The CREATE FUNCTION statement for SQL functions follow the general flow of:
CREATE FUNCTION function name(parameters) RETURNS return value LANGUAGE SQL BEGIN sql statements END

For example, a function that returns a priority based on a date:

190

DB2 UDB for AS/400 SQL Programming Concepts V4R5

CREATE FUNCTION PRIORITY(indate date) RETURNS CHAR(7) LANGUAGE SQL BEGIN RETURN( CASE WHEN indate>CURRENT DATE-3 DAYS THEN 'HIGH' WHEN indate>CURRENT DATE-7 DAYS THEN 'MEDIUM' ELSE 'LOW' END ); END

The function could then be invoked as:


SELECT ORDERNBR, PRIORITY(ORDERDUEDATE) FROM ORDERS

The creation of an SQL function causes the registration of the UDF, generates the executable code for the function, and defines to the database the details of how parameters are actually passed. Therefore, writing these functions is quite clean and provides less chance of introducing errors into the function.

Writing UDFs as external functions


You can also write the executable code of a UDF in a language other than SQL. While this method is slightly more cumbersome than an SQL function, it provides the flexibility for you to use whatever language is most effective for you. The executable code can be contained in either a program or service program.

Passing arguments from DB2 to external functions


DB2 provides the storage for all parameters passed to a UDF. Therefore, parameters are passed to the external function by address. This is the normal parameter passing method for programs. For service programs, ensure that the parameters are defined correctly in the function code. When defining and using the parameters in the UDF, care should be taken to ensure that no more storage is referenced for a given parameter than is defined for that parameter. The parameters are all stored in the same space and exceeding a given parameters storage space can overwrite another parameters value. This, in turn, can cause the function to see invalid input data or cause the value returned to the database to be invalid. There are four supported parameter styles available to external UDFs. For the most part, the styles differ in how many parameters are passed to the external program or service program. Parameter style SQL: The parameter style SQL conforms to the industry standard Structured Query Language (SQL). With parameter style SQL, the parameters are passed into the external program as follows (in the order specified):
SQL-result SQL-result-ind SQL-state

SQL-argument

SQL-argument-ind

function-name specific-name diagnostic-message

Chapter 9. Writing User-Defined Functions (UDFs)

191

SQL-argument This argument is set by DB2 before calling the UDF. This value repeats n times, where n is the number of arguments specified in the function reference. The value of each of these arguments is taken from the expression specified in the function invocation. It is expressed in the data type of the defined parameter in the create function statement. Note: These parameters are treated as input only; any changes to the parameter values made by the UDF are ignored by DB2. SQL-result This argument is set by the UDF before returning to DB2. The database provides the storage for the return value. Since the parameter is passed by address, the address is of the storage where the return value should be placed. The database provides as much storage as needed for the return value as defined on the CREATE FUNCTION statement. If the CAST FROM clause is used in the CREATE FUNCTION statement, DB2 assumes the UDF returns the value as defined in the CAST FROM clause, otherwise DB2 assumes the UDF returns the value as defined in the RETURNS clause. SQL-argument-ind This argument is set by DB2 before calling the UDF. It can be used by the UDF to determine if the corresponding SQL-argument is null or not. The nth SQL-argument-ind corresponds to the nth SQL-argument, described previously. Each indicator is defined as a two-byte signed integer. It is set to one of the following values: 0 -1 The argument is present and not null. The argument is null.

If the function is defined with RETURNS NULL ON NULL INPUT, the UDF does not need to check for a null value. However, if it is defined with CALLS ON NULL INPUT, any argument can be NULL and the UDF should check for null input. Note: these parameters are treated as input only; any changes to the parameter values made by the UDF are ignored by DB2. SQL-result-ind This argument is set by the UDF before returning to DB2. The database provides the storage for the return value. The argument is defined as a two-byte signed integer. If set to a negative value, the database interprets the result of the function as null. If set to zero or a positive value, the database uses the value returned in SQL-result. The database provides the storage for the return value indicator. Since the parameter is passed by address, the address is of the storage where the indicator value should be placed. SQL-state This argument is a CHAR(5) value that represents the SQLSTATE. This parameter is passed in from the database set to '00000' and can be set by the function as a result state for the function. While normally the SQLSTATE is not set by the function, it can be used to signal an error or warning to the database as follows: 01Hxx The function code detected a warning situation. This results in an SQL warning, Here xx may be one of several possible strings.

192

DB2 UDB for AS/400 SQL Programming Concepts V4R5

38xxx

The function code detected an error situation. It results in a SQL error. Here xxx may be one of several possible strings.

See Appendix B for more information on valid SQLSTATEs that the function may use. function-name This argument is set by DB2 before calling the UDF. It is a VARCHAR(139) value that contains the name of the function on whose behalf the function code is being invoked. The form of the function name that is passed is:
<schema-name>.<function-name>

This parameter is useful when the function code is being used by multiple UDF definitions so that the code can distinguish which definition is being invoked. Note: This parameter is treated as input only; any changes to the parameter value made by the UDF are ignored by DB2. specific-name This argument is set by DB2 before calling the UDF. It is a VARCHAR(128) value that contains the specific name of the function on whose behalf the function code is being invoked. Like function-name, this parameter is useful when the function code is being used by multiple UDF definitions so that the code can distinguish which definition is being invoked. See the CREATE FUNCTION for more information about specific-name. Note: This parameter is treated as input only; any changes to the parameter value made by the UDF are ignored by DB2. diagnostic-message This argument is set by DB2 before calling the UDF. It is a VARCHAR(70) value that can be used by the UDF to send message text back when an SQLSTATE warning or error is signaled by the UDF. It is initialized by the database on input to the UDF and may be set by the UDF with descriptive information. Message text is ignored by DB2 unless the SQL-state parameter is set by the UDF. Parameter style DB2SQL: With the DB2SQL parameter style, the same parameters and same order of parameters are passed into the external program or service program as are passed in for parameter style SQL. However, DB2SQL allows additional optional parameters to be passed along as well. If more than one of the optional parameters below is specified in the UDF definition, they are passed to the UDF in the order defined below. Refer to parameter style SQL for the common parameters.
SQL-result SQL-result-ind SQL-state

SQL-argument

SQL-argument-ind

function-name specific-name diagnostic-message scratchpad call-type dbinfo

scratchpad This argument is set by DB2 before calling the UDF. It is only present if the
Chapter 9. Writing User-Defined Functions (UDFs)

193

CREATE FUNCTION statement for the UDF specified the SCRATCHPAD keyword. This argument is a structure with the following elements: v An INTEGER containing the length of the scratchpad. v The actual scratchpad, initialized to all binary 0s by DB2 before the first call to the UDF. The scratchpad can be used by the UDF either as working storage or as persistent storage, since it is maintained across UDF invocations. call-type This argument is set by DB2 before calling the UDF. It is only present if the CREATE FUNCTION statement for the UDF specified the FINAL CALL keyword. It is an INTEGER value that contains one of the following values: -1 0 1 This is the first call to the UDF for this statement. A first call is a normal call in that all SQL argument values are passed. This is a normal call. (All the normal input argument values are passed). This is a final call. No SQL-argument or SQL-argument-ind values are passed. A UDF should not return any answer using the SQL-result or SQL-result-ind arguments. Both of these are ignored by DB2 upon return from the UDF. However, the UDF may set the SQL-state and diagnostic-message arguments. These arguments are handled in a way similar to other calls to the UDF.

dbinfo

This argument is set by DB2 before calling the UDF. It is only present if the CREATE FUNCTION statement for the UDF specifies the DBINFO keyword. The argument is a structure whose definition is contained in the sqludf include.

Parameter Style GENERAL (or SIMPLE CALL): With parameter style GENERAL, the parameters are passed into the external service program just as they are specified in the CREATE FUNCTION statement. The format is:

SQL-result = func

( SQL-argument

SQL-argument This argument is set by DB2 before calling the UDF. This value repeats n times, where n is the number of arguments specified in the function reference. The value of each of these arguments is taken from the expression specified in the function invocation. It is expressed in the data type of the defined parameter in the CREATE FUNCTION statement. Note: These parameters are treated as input only; any changes to the parameter values made by the UDF are ignored by DB2. SQL-result This value is returned by the UDF. DB2 copies the value into database storage. In order to return the value correctly, the function code must be a value-returning function. The database copies only as much of the value as defined for the return value as specified on the CREATE FUNCTION statement. If the CAST FROM clause is used in the CREATE FUNCTION

194

DB2 UDB for AS/400 SQL Programming Concepts V4R5

statement, DB2 assumes the UDF returns the value as defined in the CAST FROM clause, otherwise DB2 assumes the UDF returns the value as defined in the RETURNS clause. Because of the requirement that the function code be a value-returning function, any function code used for parameter style GENERAL must be created into a service program. Parameter Style GENERAL WITH NULLS: With parameter style GENERAL WITH NULLS, the parameters are passed into the service program as follows (in the order specified):

SQL-result = funcname

( SQL-argument

SQL-result-ind SQL-argument-ind-array

SQL-argument This argument is set by DB2 before calling the UDF. This value repeats n times, where n is the number of arguments specified in the function reference. The value of each of these arguments is taken from the expression specified in the function invocation. It is expressed in the data type of the defined parameter in the CREATE FUNCTION statement. Note: These parameters are treated as input only; any changes to the parameter values made by the UDF are ignored by DB2. SQL-argument-ind-array This argument is set by DB2 before calling the UDF. It can be used by the UDF to determine if one or moreSQL-arguments are null or not. It is an array of two-byte signed integers (indicators). Thenth array argument corresponds corresponds to the nth SQL-argument. Each array entry is set to one of the following values: 0 -1 The argument is present and not null. The argument is null.

The UDF should check for null input. Note: This parameter is treated as input only; any changes to the parameter value made by the UDF is ignored by DB2. SQL-result-ind This argument is set by the UDF before returning to DB2. The database provides the storage for the return value. The argument is defined as a two-byte signed integer. If set to a negative value, the database interprets the result of the function as null. If set to zero or a positive value, the database uses the value returned in SQL-result. The database provides the storage for the return value indicator. Since the parameter is passed by address, the address is of the storage where the indicator value should be placed. SQL-result This value is returned by the UDF. DB2 copies the value into database storage. In order to return the value correctly, the function code must be a
Chapter 9. Writing User-Defined Functions (UDFs)

195

value-returning function. The database copies only as much of the value as defined for the return value as specified on the CREATE FUNCTION statement. If the CAST FROM clause is used in the CREATE FUNCTION statement, DB2 assumes the UDF returns the value as defined in the CAST FROM clause, otherwise DB2 assumes the UDF returns the value as defined in the RETURNS clause. Because of the requirement that the function code be a value-returning function, any function code used for parameter style GENERAL WITH NULLS must be created into a service program. Note: v The external name specified on the CREATE FUNCTION statement can be specified either with quotes or without quotes. If the name is not quoted, it is uppercased before it is stored; if it is quoted, it is stored as specified. This becomes important when naming the actual program, as the database searches for the program that has a name that exactly matches the name stored with the function definition. For example, if a function was created as:
CREATE FUNCTION X(INT) RETURNS INT LANGUAGE C EXTERNAL NAME 'MYLIB/MYPGM(MYENTRY)'

and the source for the program was:


void myentry( int*in int*out, . . . .

the database would not find the entry because it is in lower case myentry and the database was instructed to look for uppercase MYENTRY. v For service programs with C++ modules, make sure in the C++ source code to precede the program function definition with extern C. Otherwise, the C++ compiler will perform name mangling of the functions name and the database will not find it.

Examples of UDF code


These examples show how to implement UDF code by using SQL functions and external functions.

Example: Square of a number UDF


Suppose that you wanted a function that returns the square of a number. The query statement is:
SELECT SQUARE(myint) FROM mytable

The following examples show how to define the UDF several different ways. v Using an SQL function

196

DB2 UDB for AS/400 SQL Programming Concepts V4R5

CREATE FUNCTION SQUARE( inval INT) RETURNS INT LANGUAGE SQL BEGIN RETURN(inval*inval); END

v Using an external function, parameter style SQL: The CREATE FUNCTION statement:
CREATE FUNCTION SQUARE(INT) RETURNS INT CAST FROM FLOAT LANGUAGE C EXTERNAL NAME 'MYLIB/MATH(SQUARE)' DETERMINISTIC NO SQL NO EXTERNAL ACTION PARAMETER STYLE SQL ALLOW PARALLEL

The code:
void SQUARE(int *inval, double *outval, short *inind, short *outind, char *sqlstate, char *funcname, char *specname, char *msgtext) { if (*inind<0) *outind=-1; else { *outval=*inval; *outval=(*outval)*(*outval); *outind=0; } return; }

To create the external service program so it can be debugged:


CRTCMOD MODULE(mylib/square) DBGVIEW(*SOURCE) CRTSRVPGM SRVPGM(mylib/math) MODULE(mylib/square) EXPORT(*ALL) ACTGRP(*CALLER)

v Using an external function, parameter style GENERAL: The CREATE FUNCTION statement:
CREATE FUNCTION SQUARE(INT) RETURNS INT CAST FROM FLOAT LANGUAGE C EXTERNAL NAME 'MYLIB/MATH(SQUARE)' DETERMINISTIC NO SQL NO EXTERNAL ACTION PARAMETER STYLE GENERAL ALLOW PARALLEL

The code:
double SQUARE(int *inval) { double outval; outval=*inval; outval=outval*outval; return(outval); }

To create the external service program so it can be debugged:


Chapter 9. Writing User-Defined Functions (UDFs)

197

CRTCMOD MODULE(mylib/square) DBGVIEW(*SOURCE) CRTSRVPGM SRVPGM(mylib/math) MODULE(mylib/square) EXPORT(*ALL) ACTGRP(*CALLER)

Example: Counter
Suppose you want to simply number the rows in your SELECT statement. So you write a UDF which increments and returns a counter. This example uses an external function with DB2 SQL parameter style and a scratchpad.
CREATE FUNCTION COUNTER() RETURNS INT SCRATCHPAD NOT DETERMINISTIC NO SQL NO EXTERNAL ACTION LANGUAGE C PARAMETER STYLE DB2SQL EXTERNAL NAME 'MYLIB/MATH(ctr)' DISALLOW PARALLELISM; /* structure scr defines the passed scratchpad for the function "ctr" */ struct scr { long len; long countr; char not_used[96]; }; void ctr ( long *out, short *outnull, char *sqlstate, char *funcname, char *specname, char *mesgtext, struct scr *scratchptr) { *out = ++scratchptr->countr; *outnull = 0; return; /* /* /* /* /* /* /* output answer (counter) */ output NULL indicator */ SQL STATE */ function name */ specific function name */ message text insert */ scratch pad */

/* increment counter & copy out */

} /* end of UDF : ctr */

For this UDF, observe that: v It has no input SQL arguments defined, but returns a value. v It appends the scratchpad input argument after the four standard trailing arguments, namely SQL-state, function-name, specific-name, and message-text. v It includes a structure definition to map the scratchpad which is passed. v No input parameters are defined. This agrees with the code. v SCRATCHPAD is coded, causing DB2 to allocate, properly initialize and pass the scratchpad argument. v You have specified it to be NOT DETERMINISTIC, because it depends on more than the SQL input arguments, (none in this case). v You have correctly specified DISALLOW PARALLELISM, because correct functioning of the UDF depends on a single scratchpad.

198

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Chapter 10. Dynamic SQL Applications


Dynamic SQL allows an application to define and run SQL statements at program run time. An application that provides for dynamic SQL accepts as input (or builds) an SQL statement in the form of a character string. The application does not need to know what type of SQL statement it will run. The application: v Builds or accepts as input an SQL statement v Prepares the SQL statement for running v Runs the statement v Handles SQL return codes Interactive SQL (described in Chapter 12. Using Interactive SQL) is an example of a dynamic SQL program. SQL statements are processed and run dynamically by interactive SQL. Notes: 1. The run-time overhead is greater for statements processed using dynamic SQL than for static SQL statements. The additional process is similar to that required for precompiling, binding, and then running a program, instead of only running it. Therefore, only applications requiring the flexibility of dynamic SQL should use it. Other applications should access data from the database using normal (static) SQL statements. 2. Programs that contain an EXECUTE or EXECUTE IMMEDIATE statement and that use a FOR READ ONLY clause to make a cursor read-only experience better performance because blocking is used to retrieve rows for the cursor. The ALWBLK(*ALLREAD) CRTSQLxxx option will imply a FOR READ ONLY declaration for all cursors that do not explicitly code FOR UPDATE OF or have positioned deletes or updates that refer to the cursor. Cursors with an implied FOR READ ONLY will benefit from the second item in this list. Some dynamic SQL statements require use of address variables. RPG for AS/400 programs require the aid of PL/I, COBOL, C, or ILE RPG for AS/400 programs to manage the address variables. The examples in this chapter are PL/I examples. The following table shows all the statements supported by DB2 UDB for AS/400 and indicates if they can be used in a dynamic application. Note: In the following table, the numbers in the Dynamic SQL column correspond to the notes on the next page.
Table 22. List of SQL Statements Allowed in Dynamic Applications SQL Statement ALTER TABLE BEGIN DECLARE SECTION CALL CLOSE COMMENT ON COMMIT Static SQL Y Y Y Y Y Y Dynamic SQL Y N Y N Y Y

Copyright IBM Corp. 2000

199

Table 22. List of SQL Statements Allowed in Dynamic Applications (continued) SQL Statement CONNECT CREATE ALIAS CREATE COLLECTION CREATE DISTINCT TYPE CREATE FUNCTION CREATE INDEX CREATE PROCEDURE CREATE SCHEMA CREATE TABLE CREATE VIEW DECLARE CURSOR DECLARE PROCEDURE DECLARE STATEMENT DECLARE VARIABLE DELETE DESCRIBE DESCRIBE TABLE DISCONNECT DROP END DECLARE SECTION EXECUTE EXECUTE IMMEDIATE FETCH FREE LOCATOR GRANT INCLUDE INSERT LABEL ON LOCK TABLE OPEN PREPARE RELEASE RENAME REVOKE ROLLBACK SELECT INTO SELECT statement SET CONNECTION SET OPTION SET PATH Static SQL Y Y Y Y Y Y Y N Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Y Dynamic SQL N Y Y Y Y Y Y See Note 8. Y Y See Note 4. N N N Y See Note 7. N N Y N See Note 1. See Note 2. N Y Y N Y Y Y N See Note 3. N Y Y Y See Note 5. See Note 6. N See Note 9. Y

200

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Table 22. List of SQL Statements Allowed in Dynamic Applications (continued) SQL Statement SET RESULT SETS SET TRANSACTION SET variable UPDATE VALUES INTO WHENEVER Static SQL Y Y Y Y Y Y Dynamic SQL N Y N Y N N

Notes: 1. Cannot be prepared, but used to run prepared SQL statements. The SQL statement must be previously prepared by the PREPARE statement prior to using the EXECUTE statement. See example for PREPARE under Using the PREPARE and EXECUTE statements on page 202. 2. Cannot be prepared, but used with dynamic statement strings that do not have any ? parameter markers. The EXECUTE IMMEDIATE statement causes the statement strings to be prepared and run dynamically at program run time. See example for EXECUTE IMMEDIATE under Processing non-SELECT statements on page 202. 3. Cannot be prepared, but used to parse, optimize, and set up dynamic SELECT statements prior to running. See example for PREPARE under Processing non-SELECT statements on page 202. 4. Cannot be prepared, but used to define the cursor for the associated dynamic SELECT statement prior to running. 5. A SELECT INTO statement cannot be prepared or used in EXECUTE IMMEDIATE. 6. Cannot be used with EXECUTE or EXECUTE IMMEDIATE but can be prepared and used with OPEN. 7. Cannot be prepared, but used to return a description of a prepared statement. 8. Can only be run using the Run SQL Statements (RUNSQLSTM) command. 9. Can only be used when running a REXX procedure.

Designing and running a dynamic SQL application


To issue a dynamic SQL statement, you must use the statement with either an EXECUTE statement or an EXECUTE IMMEDIATE statement, because dynamic SQL statements are not prepared at precompile time and therefore must be prepared at run time. The EXECUTE IMMEDIATE statement causes the SQL statement to be prepared and run dynamically at program run time. There are two basic types of dynamic SQL statements: SELECT statements and non-SELECT statements. Non-SELECT statements include such statements as DELETE, INSERT, and UPDATE. Client server applications that use interfaces such as ODBC typically use dynamic SQL to access the database. For more information on developing client server applications that use Client Access, see the Client Access for Windows 3.1 ODBC Users Guide.

Chapter 10. Dynamic SQL Applications

201

Processing non-SELECT statements


To build a dynamic SQL non-SELECT statement: 1. Verify that the SQL statement you want to build is one that can be run dynamically (see Table 22 on page 199). 2. Build the SQL statement. (Use Interactive SQL for an easy way to build, verify, and run your SQL statement. See Chapter 12. Using Interactive SQL for more information.) To run a dynamic SQL non-SELECT statement: 1. Run the SQL statement using EXECUTE IMMEDIATE, or PREPARE the SQL statement, then EXECUTE the prepared statement. 2. Handle any SQL return codes that might result. The following is an example of an application running a dynamic SQL non-SELECT statement (stmtstrg):
EXEC SQL EXECUTE IMMEDIATE :stmtstrg;

CCSID of dynamic SQL statements


The SQL statement is normally a host variable. The CCSID of the host variable is used as the CCSID of the statement text. In PL/I, it also can be a string expression. In this case, the job CCSID is used as the CCSID of the statement text. Dynamic SQL statements are processed using the CCSID of the statement text. This affects variant characters the most. For example, the not sign () is located at 'BA'X in CCSID 500. This means that if the CCSID of your statement text is 500, SQL expects the not sign () to be located at 'BA'X. If the statement text CCSID is 65535, SQL processes variant characters as if they had a CCSID of 37. This means that SQL looks for the not sign () at '5F'X.

Using the PREPARE and EXECUTE statements


If non-SELECT statements contain no parameter markers, they can be run dynamically using the EXECUTE IMMEDIATE statement. However, if the non-SELECT statements have parameter markers, they must be run using PREPARE and EXECUTE. The PREPARE statement prepares the non-SELECT statement (for example, the DELETE statement) and gives it a name of your choosing. If DLYPRP (*YES) is specified on the CRTSQLxxx command, the preparation is delayed until the first time the statement is used in an EXECUTE or DESCRIBE statement, unless the USING clause is specified on the PREPARE statement. In this instance, let us call it S1. After the statement has been prepared, it can be run many times within the same program, using different values for the parameter markers. The following example is of a prepared statement being run multiple times:
DSTRING = 'DELETE FROM CORPDATA.EMPLOYEE WHERE EMPNO = ?'; /*The ? is a parameter marker which denotes that this value is a host variable that is to be substituted each time the statement is run.*/

202

DB2 UDB for AS/400 SQL Programming Concepts V4R5

EXEC SQL PREPARE S1 FROM :DSTRING; /*DSTRING is the delete statement that the PREPARE statement is naming S1.*/ DO UNTIL (EMP =0); /*The application program reads a value for EMP from the display station.*/ EXEC SQL EXECUTE S1 USING :EMP; END;

In routines similar to the example above, you must know the number of parameter markers and their data types, because the host variables that provide the input data are declared when the program is being written. Note: All prepared statements that are associated with an application server are destroyed whenever the connection to the application server ends. Connections are ended by a CONNECT (Type 1) statement, a DISCONNECT statement, or a RELEASE followed by a successful COMMIT.

Processing SELECT statements and using an SQLDA


There are two basic types of SELECT statements: fixed-list and varying-list. To process a fixed-list SELECT statement, an SQLDA is not necessary. To process a varying-list SELECT statement, you must first declare an SQLDA structure. The SQLDA is a control block used to pass host variable input values from an application program to SQL and to receive output values from SQL. In addition, information about SELECT list expressions can be returned in a PREPARE or DESCRIBE statement.

Fixed-list SELECT statements


In dynamic SQL, fixed-list SELECT statements are those statements designed to retrieve data of a predictable number and type. When using these statements, you can anticipate and define host variables to accommodate the retrieved data, so that an SQLDA is not necessary. Each successive FETCH returns the same number of values as the last, and these values have the same data formats as those returned for the last FETCH. You can specify host variables the same as you would for any SQL application. You can use fixed-list dynamic SELECT statements with any SQL-supported application program. To run fixed-list SELECT statements dynamically, your application must: 1. Place the input SQL statement into a host variable. 2. Issue a PREPARE statement to validate the dynamic SQL statement and put it into a form that can be run. If DLYPRP (*YES) is specified on the CRTSQLxxx command, the preparation is delayed until the first time the statement is used in an EXECUTE or DESCRIBE statement, unless the USING clause is specified on the PREPARE statement. 3. Declare a cursor for the statement name.
Chapter 10. Dynamic SQL Applications

203

4. Open the cursor. 5. FETCH a row into a fixed list of variables (rather than into a descriptor area, as you would if you were using a varying-list SELECT statement, described in the following section, Varying-list Select-statements). 6. When end of data occurs, close the cursor. 7. Handle any SQL return codes that result. For example:
MOVE 'SELECT EMPNO, LASTNAME FROM CORPDATA.EMPLOYEE WHERE EMPNO>?' TO DSTRING. EXEC SQL PREPARE S2 FROM :DSTRING END-EXEC. EXEC SQL DECLARE C2 CURSOR FOR S2 END-EXEC. EXEC SQL OPEN C2 USING :EMP END-EXEC. PERFORM FETCH-ROW UNTIL SQLCODE NOT=0. EXEC SQL CLOSE C2 END-EXEC. STOP-RUN. FETCH-ROW. EXEC SQL FETCH C2 INTO :EMP, :EMPNAME END-EXEC.

Note: Remember that because the SELECT statement, in this case, always returns the same number and type of data items as previously run fixed-list SELECT statements, you do not have to use the SQL descriptor area (SQLDA).

Varying-list Select-statements
In dynamic SQL, varying-list SELECT statements are ones for which the number and format of result columns to be returned are not predictable; that is, you do not know how many variables you need, or what the data types are. Therefore, you cannot define host variables in advance to accommodate the result columns returned. Note: In REXX, steps 5b on page 205, 6 on page 205, and 7 on page 205 are not applicable. If your application accepts varying-list SELECT statements, your program has to: 1. Place the input SQL statement into a host variable. 2. Issue a PREPARE statement to validate the dynamic SQL statement and put it into a form that can be run. If DLYPRP (*YES) is specified on the CRTSQLxxx command, the preparation is delayed until the first time the statement is used in an EXECUTE or DESCRIBE statement, unless the USING clause is specified on the PREPARE statement. 3. Declare a cursor for the statement name. 4. Open the cursor (declared in step 3) that includes the name of the dynamic SELECT statement. 5. Issue a DESCRIBE statement to request information from SQL about the type and size of each column of the result table.

204

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Notes: a. You can also code the PREPARE statement with an INTO clause to perform the functions of PREPARE and DESCRIBE with a single statement. b. If the SQLDA is not large enough to contain column descriptions for each retrieved column, the program must determine how much space is needed, get storage for that amount of space, build a new SQLDA, and reissue the DESCRIBE statement. 6. Allocate the amount of storage needed to contain a row of retrieved data. 7. Put storage addresses into the SQLDA (SQL descriptor area) to tell SQL where to put each item of retrieved data. 8. FETCH a row. 9. When end of data occurs, close the cursor. 10. Handle any SQL return codes that might result.

SQL Descriptor Area (SQLDA)


You can use the SQLDA to pass information about an SQL statement between SQL and your application. The SQLDA is a collection of variables required for running the DESCRIBE and DESCRIBE TABLE statements. It also can be used on the PREPARE, OPEN, FETCH, CALL, and EXECUTE statements. An SQLDA is used with dynamic SQL. It can be used in a DESCRIBE statement, changed with the addresses of host variables, and then reused in a FETCH statement. The meaning of the information in an SQLDA depends on its use. In PREPARE and DESCRIBE, an SQLDA provides information to an application program about a prepared statement. In DESCRIBE TABLE, the SQLDA provides information to an application program about the columns in a table or view. In OPEN, EXECUTE, CALL, and FETCH, an SQLDA provides information about host variables. SQLDA is required for: v DESCRIBE v DESCRIBE TABLE SQLDA is an option for: v EXECUTE v FETCH v OPEN v PREPARE v CALL If your application lets you have several cursors open at the same time, you can code several SQLDAs, one for each dynamic SELECT statement. For more information on SQLDA and SQLCA, see the SQL Reference book. SQLDAs can be used in C, COBOL, PL/I, REXX, and RPG. Because RPG for AS/400 does not provide a way to set pointers, pointers must be set outside the RPG for AS/400 program by a PL/I, C, COBOL, or ILE RPG for AS/400 program. Since the area used must be declared by the PL/I, C, COBOL, or ILE RPG for AS/400 program, that program must call the RPG for AS/400 program.

Chapter 10. Dynamic SQL Applications

205

SQLDA format
The SQLDA consists of four variables followed by an arbitrary number of occurrences of a sequence of six variables collectively named SQLVAR. Note: The SQLDA in REXX is different. For more information, see the topic Coding SQL Statements in REXX Applications in the SQL Programming with Host Languages information. When an SQLDA is used in OPEN, FETCH, CALL, and EXECUTE, each occurrence of SQLVAR describes a host variable. The variables of SQLDA are as follows (variable names are in lowercase for C): SQLDAID SQLDAID is used for storage dumps. Byte 7 of SQLDAID is used to indicate if there are extension SQL VARs used for LOBs or UDTs. It is a string of 8 characters that have the value 'SQLDA' after the SQLDA that is used in a PREPARE or DESCRIBE statement. It is not used for FETCH, OPEN, CALL or EXECUTE. Byte 7 can be used to determine if more than one SQLVAR entry is needed for each column. This flag is set to a blank if there are not any LOBs or distinct types. SQLDAID is not applicable in REXX. SQLDABC SQLDABC indicates the length of the SQLDA. It is a 4-byte integer that has the value SQLN*LENGTH(SQLVAR) + 16 after the SQLDA is used in a PREPARE or DESCRIBE statement. SQLDABC must have a value equal to or greater than SQLN*LENGTH(SQLVAR) + 16 prior to use by FETCH, OPEN, CALL, or EXECUTE. SQLABC is not applicable in REXX. SQLN SQLN is a 2-byte integer that specifies the total number of occurrences of SQLVAR. It must be set prior to use by any SQL statement to a value greater than or equal to 0. SQLN is not applicable in REXX. SQLD SQLD is a 2-byte integer that specifies the pertinent number of occurrences of SQLVAR; that is, the number of host variables described by the SQLDA. This field is set by SQL on a DESCRIBE or PREPARE statement. In other statements, this field must be set prior to use to a value greater than or equal to 0 and less than or equal to SQLN. SQLVAR The variables of SQLVAR are SQLTYPE, SQLLEN, SQLRES, SQLDATA, SQLIND, and SQLNAME. These variables are set by SQL on a DESCRIBE or PREPARE statement. In other statements, they must be set prior to use. These variables are defined as follows: SQLTYPE SQLTYPE is a 2-byte integer that specifies the data type of the host variable as shown in the table below. Odd values for SQLTYPE show that the host variable has an associated indicator variable addressed by SQLIND.

206

DB2 UDB for AS/400 SQL Programming Concepts V4R5

SQLLEN SQLLEN is a 2-byte integer variable that specifies the length attributes of the host variables shown in Figure 10-2.
Table 23. SQLTYPE and SQLLEN Values for PREPARE, DESCRIBE, FETCH, OPEN, CALL, or EXECUTE For PREPARE and DESCRIBE SQLTYPE 384/385 COLUMN DATA TYPE Date SQLLEN 10 For FETCH, OPEN, CALL, and EXECUTE HOST VARIABLE DATA TYPE Fixed-length character string representation of a date Fixed-length character string representation of a time Fixed-length character string representation of a timestamp N/A NUL-terminated graphic string Fixed-length character string representation of a timestamp BLOB CLOB DBCLOB Fixed-length character string Long varying-length character string NUL-terminated character string Varying-length graphic string SQLLEN Length attribute of the host variable Length attribute of the host variable Length attribute of the host variable N/A Length attribute of the host variable Length attribute of the host variable Not used.7 Not used.7 Not used.7 Length attribute of the host variable Length attribute of the host variable Length attribute of the host variable Length attribute of the host variable

388/389

Time

392/393

Timestamp

26

396/397 400/401

DataLink6 N/A

Length attribute of the column N/A

392/393

Timestamp

26

404/405 408/409 412/413 452/453

BLOB CLOB DBCLOB Fixed-length character string Long varying-length character string N/A

07 07 07 Length attribute of the column Length attribute of the column N/A

456/457

460/461

464/465

Varying-length graphic string

Length attribute of the column

468/469

Fixed-length graphic string Length attribute of the column Long varying-length graphic string N/A Length attribute of the column N/A

Fixed-length graphic string Length attribute of the host variable Long graphic string Length attribute of the host variable Length attribute of the host variable 4 for single precision, 8 for double precision

472/473

476/477

PASCAL L-string

480/481

Floating point

4 for single precision, 8 for double precision

Floating point

Chapter 10. Dynamic SQL Applications

207

Table 23. SQLTYPE and SQLLEN Values for PREPARE, DESCRIBE, FETCH, OPEN, CALL, or EXECUTE (continued) For PREPARE and DESCRIBE SQLTYPE 484/485 488/489 COLUMN DATA TYPE Packed decimal Zoned decimal Big integer Large integer Small integer N/A N/A N/A N/A N/A N/A N/A SQLLEN Precision in byte 1; scale in byte 2 Precision in byte 1; scale in byte 2 8 4 2
5 5

For FETCH, OPEN, CALL, and EXECUTE HOST VARIABLE DATA TYPE Packed decimal Zoned decimal Big integer Large integer Small integer DISPLAY SIGN LEADING SEPARATE BLOB file reference variable CLOB file reference variable DBCLOB file reference variable BLOB locator CLOB locator DBCLOB locator SQLLEN Precision in byte 1; scale in byte 2 Precision in byte 1; scale in byte 2 8 4 2 Precision in byte 1; scale in byte 2 267 267 267 4 4 4

492/493 496/497 500/501 504/505 916/917 920/921 924/925 960/961 964/965 968/969

N/A N/A N/A N/A N/A N/A N/A

SQLRES SQLRES is a 12-byte reserved area for boundary alignment purposes. Note that, in OS/400, pointers must be on a quad-word boundary. SQLRES is not applicable in REXX. SQLDATA SQLDATA is a 16-byte pointer variable that specifies the address of the host variables when the SQLDA is used on OPEN, FETCH, CALL, and EXECUTE. When the SQLDA is used on PREPARE and DESCRIBE, this area is overlaid with the following information: The CCSID of a character, date, time, timestamp, and graphic field is stored in the third and fourth bytes of SQLDATA. For BIT data, the CCSID is 65535. In REXX, the CCSID is returned in the variable SQLCCSID. SQLIND SQLIND is a 16-byte pointer that specifies the address of a small integer host variable that is used as an indication of null or not null when the SQLDA is used on OPEN, FETCH, CALL, and EXECUTE. A negative value indicates null and a non-negative indicates not null. This pointer is only used if SQLTYPE contains an odd value.

5. Large and small binary numbers can be represented in the SQL descriptor area (SQLDA) as either lengths 2 or 4. They can also be represented with the precision in byte 1 and the scale in byte 2. If the first byte is greater than X00, it indicates precision and scale. Big integer numbers do not allow a precision and scale. The SQLDA defines them as length 8. 6. The DataLink datatype is only returned on DESCRIBE TABLE. 7. The len.sqllonglen field in the secondary SQLVAR contains the length attribute of the column.

208

DB2 UDB for AS/400 SQL Programming Concepts V4R5

When the SQLDA is used on PREPARE and DESCRIBE, this area is reserved for future use. SQLNAME SQLNAME is a variable-length character variable with a maximum length of 30, which contains the name of selected column, label, or system column name after a PREPARE or DESCRIBE. In OPEN, FETCH, EXECUTE, or CALL, it can be used to pass the CCSID of character strings. CCSIDs can be passed for character, graphic, date, time, and timestamp host variables. The SQLNAME field in an SQLVAR array entry of an input SQLDA can be set to specify the CCSID:
Data Type Character Character Character GRAPHIC Any other data type Sub-type SBCS MIXED BIT not applicable not applicable Length of SQLNAME 8 8 8 8 not applicable SQLNAME Bytes 1 & 2 X0000 X0000 X0000 X0000 not applicable SQLNAME Bytes 3 & 4 CCSID CCSID XFFFF CCSID not applicable

Note: It is important to remember that the SQLNAME field is only for overriding the CCSID. Applications that use the defaults do not need to pass CCSID information. If a CCSID is not passed, the default CCSID for the job is used. The default for graphic host variables is the associated double-byte CCSID for the job CCSID. If an associated double-byte CCSID does not exist, 65535 is used. SQLVAR2 The Extended SQLVAR structure. Extended SQLVARs are only needed (for all columns of the result) if the result includes any LOB or distinct type columns. For distinct types, they contain the distinct type name. For LOBs, they contain the length attribute of the host variable and a pointer to the buffer that contains the actual length. If locators are used to represent LOBs, these entries are not necessary. The number of Extended SQLVAR occurrences needed depends on the statement that the SQLDA was provided for and the data types of the columns or parameters being described. Byte 7 of SQLDAID is always set to the number of sets of SQLVARs necessary. If SQLD is not set to a sufficient number of SQLVAR occurrences: v SQLD is set to the total number of SQLVAR occurrences needed for all sets. v A +237 warning is returned in the SQLCODE field of the SQLCA if at least enough were specified for the Base SQLVAR Entries. The Base SQLVAR entries are returned, but no Extended SQLVARs are returned. v A +239 warning is returned in the SQLCODE field of the SQLCA if enough SQLVARs were not specified for even the Base SQLVAR Entries. No SQLVAR entries are returned. SQLLONGLEN SQLLONGLEN is part of the Extended SQLVAR. It is a 4-byte integer variable that specifies the length attributes of a LOB (BLOB, CLOB, or DBCLOB) host variable.

Chapter 10. Dynamic SQL Applications

209

SQLDATALEN SQLDATALEN is part of the Extended SQLVAR. It is a 16-byte pointer variable that specifies the address of the length of the host variable. It is used for LOB (BLOB, CLOB, and DBCLOB) host variables only. If this field is NULL, then the actual length is stored in the 4 bytes immediately before the start of the data, and SQLDATA points to the first byte of the field length. The actual length indicates the number of bytes for a BLOB or CLOB, and the number of characters for a DBCLOB. If this field is not NULL, it contains a pointer to a 4-byte long buffer that contains the actual length in bytes (even for DBCLOB) of the data in the buffer pointed to from the SQLDATA field in the matching base SQLVAR. SQLDATATYPE_NAME SQLDATATYPE_NAME is part of the Extended SQLVAR. It is a variable-length character variable with a maximum length of 30. It is set to one of the following: v For a distinct type column, the database manager sets this to the fully qualified distinct type name. v If the qualified name is longer than 30 bytes, it is truncated. v For a label, the database manager sets this to the first 20 bytes of the label. For a column name, the database manager sets this to the column name.

Example: Select-statement for allocating storage for SQLDA


The SELECT statement can be read from a display station or from a host variable, or it can be developed within an application program. The following example shows a SELECT statement read from a display station:
SELECT WORKDEPT, PHONENO FROM CORPDATA.EMPLOYEE WHERE LASTNAME = 'PARKER'

Note: The SELECT statement has no INTO clause. Dynamic SELECT statements must not have an INTO clause, even if they return only one row. When the statement is read, it is assigned to a host variable. The host variable (for example, named DSTRING) is then processed, using the PREPARE statement, as shown:
EXEC SQL PREPARE S1 FROM :DSTRING;

Allocating SQLDA Storage


You can allocate storage for the SQLDA. (Allocating storage is not necessary in REXX.) The techniques for acquiring storage are language dependent. The SQLDA must be allocated on a 16-byte boundary. The SQLDA consists of a fixed-length header, 16 bytes long. The header is followed by a varying-length array section (SQLVAR), each element of which is 80 bytes in length. The amount of storage you need to allocate depends on how many elements you want to have in the SQLVAR array. Each column you select must have a corresponding SQLVAR array element. Therefore, the number of columns listed in your SELECT statement determines how many SQLVAR array elements you should allocate. Because SELECT statements are specified at run time, however, it is impossible to know how many columns will be accessed. Consequently, you must estimate the number of columns. Suppose, in this example, that no more than 20 columns are ever expected to be accessed by a single SELECT statement. This means that the

210

DB2 UDB for AS/400 SQL Programming Concepts V4R5

SQLVAR array should have a dimension of 20 (for an SQLDA size 20 x 80, or 1600, plus 16 for a total of 1616 bytes), because each item in the select-list must have a corresponding entry in SQLVAR. Having allocated what you estimated to be enough space for your SQLDA in the SQLN field of the SQLDA, set an initial value equal to the number of SQLVAR array elements. In the following example, set SQLN to 20:
Allocate space for an SQLDA of 1616 bytes on a quadword boundary SQLN = 20;

Note: In PL/I the ALLOCATE statement is the only way to ensure the allocation of a quadword boundary. Having allocated storage, you can now issue a DESCRIBE statement.
EXEC SQL DESCRIBE S1 INTO :SQLDA;

When the DESCRIBE statement is run, SQL places values in the SQLDA that provide information about the select-list. The following Figure 8 shows the contents of the SQLDA after the DESCRIBE is run:
SQLDA Size SQLDA (8 bytes) 453 37 SQLVAR Element 1 (80 bytes) 8 0 WORKDEPT 3 1616 SQLDA (4 bytes) (reserved) 20 SQLN (2 bytes) 2 SQLD (2 bytes)

453 37 SQLVAR Element 2 (80 bytes) 7 0

(reserved)

P H O N E N O

RV3W188-0

Figure 8. Contents of SQLDA after a DESCRIBE Is Run

SQLDAID is an identifier field initialized by SQL when a DESCRIBE is run. SQLDABC is the byte count or size of the SQLDA. You can ignore these for now. The example for running the SELECT statement for S1 is:
SELECT WORKDEPT, PHONENO FROM CORPDATA.EMPLOYEE WHERE LASTNAME = 'PARKER'

Your program might have to alter the SQLN value if the SQLDA is not large enough to contain the described SQLVAR elements. For example, let the SELECT statement contain 27 select-list expressions instead of the 20 or less that you estimated. Because the SQLDA was only allocated with an SQLVAR dimension of 20 elements, SQL cannot describe the select-list, because the SQLVAR has too many elements. SQL sets the SQLD to the actual number of columns specified by the
Chapter 10. Dynamic SQL Applications

211

SELECT statement, and the remainder of the structure is ignored. Therefore, after a DESCRIBE, you should compare the SQLN to the SQLD. If the value of SQLD is greater than the value of SQLN, allocate a larger SQLDA based on the value in SQLD, as follows:
EXEC SQL DESCRIBE S1 INTO :SQLDA; IF SQLN <= SQLD THEN DO; /*Allocate a larger SQLDA using the value of SQLD.*/ /*Reset SQLN to the larger value.*/ EXEC SQL DESCRIBE S1 INTO :SQLDA; END;

If you use DESCRIBE on a non SELECT statement, SQL sets SQLD to 0. Therefore, if your program is designed to process both SELECT and non SELECT statements, you can describe each statement (after it is prepared) to determine whether it is a SELECT statement. This sample routine is designed to process only SELECT statements; the SQLD is not checked. Your program must now analyze the elements of SQLVAR. Remember that each element describes a single select-list expression. Consider again the SELECT statement that is being processed:
SELECT WORKDEPT, PHONENO FROM CORPDATA.EMPLOYEE WHERE LASTNAME = 'PARKER'

The first item in the select-list is WORKDEPT. At the beginning of this section, we identified that each SQLVAR element contains the fields SQLTYPE, SQLLEN, SQLRES, SQLDATA, SQLIND, and SQLNAME. SQL returns, in the SQLTYPE field, a code that describes the data type of the expressions and whether nulls are applicable or not. For example, SQL sets SQLTYPE to 453 in SQLVAR element 1 (see Figure 8 on page 211). This specifies that WORKDEPT is a fixed-length character string (CHAR) column and that nulls are permitted in the column. SQL sets SQLLEN to the length of the column. Because the data type of WORKDEPT is CHAR, SQL sets SQLLEN equal to the length of the character string. For WORKDEPT, that length is 3. Therefore, when the SELECT statement is later run, a storage area large enough to hold a CHAR(3) string is needed. Because the data type of WORKDEPT is CHAR FOR SBCS DATA, the first 4 bytes of SQLDATA were set to the CCSID of the character column (see Figure 8 on page 211). The last field in an SQLVAR element is a varying-length character string called SQLNAME. The first 2 bytes of SQLNAME contain the length of the character data. The character data itself is usually the name of a column used in the SELECT statement (WORKDEPT in the above example.) The exceptions to this are select-list items that are unnamed, such as functions (for example, SUM(SALARY)), expressions (for example, A+BC), and constants. In these cases, SQLNAME is an empty string. SQLNAME can also contain a label rather than a name. One of the parameters associated with the PREPARE and DESCRIBE statements is the USING clause. You can specify it this way:
EXEC SQL DESCRIBE S1 INTO:SQLDA USING LABELS;

212

DB2 UDB for AS/400 SQL Programming Concepts V4R5

If you specify NAMES (or omit the USING parameter entirely), only column names are placed in the SQLNAME field. If you specify SYSTEM NAMES, only the system column names are placed in the SQLNAME field. If you specify LABELS, only labels associated with the columns listed in your SQL statement are entered here. If you specify ANY, labels are placed in the SQLNAME field for those columns that have labels; otherwise, the column names are entered. If you specify BOTH, names and labels are both placed in the field with their corresponding lengths. If you specify BOTH, however, you must remember to double the size of the SQLVAR array because you are including twice the number of elements. If you specify ALL, column names, labels, and system column names are placed in the field with their corresponding lengths. If you specify ALL, remember to triple the size of the SQLVAR array. If you specify ALL: v Names, and labels are placed in the field with their corresponding lengths. v The size of the SQLVAR array must triple because you are including the number of elements. For more information on the USING option and on column labels, see the SQL Reference book. In the example, the second SQLVAR element contains the information for the second column used in the select: PHONENO. The 453 code in SQLTYPE specifies that PHONENO is a CHAR column. For a CHAR data type of length 4, SQL sets SQLLEN to 4. After analyzing the result of the DESCRIBE, you can allocate storage for variables containing the result of the SELECT statement. For WORKDEPT, a character field of length 3 must be allocated; for PHONENO, a character field of length 4 must be allocated. After the storage is allocated, you must set SQLDATA and SQLIND to point to the appropriate areas. For each element of the SQLVAR array, SQLDATA points to the place where the results are to be put. SQLIND points to the place where the null indicator is to be put. The following figure shows what the structure looks like now:
SQLDA Size S 453 Q 3 L D A (reserved) 1616 20 2 FLDA: (CHAR(3))

Address of FLDA SQLVAR Element 1 (80 bytes) Address of FLDAI 8 WORKDEPT FLDB: (CHAR(4))

453 SQLVAR Element 2 (80 bytes)

(reserved)

Address of FLDB Address of FLDBI 7 P H O N E N O

Indicator Variables: (halfword) FLDAI: FLDBI:

RV3W189-0

This is what was done so far:


Chapter 10. Dynamic SQL Applications

213

EXEC SQL INCLUDE SQLDA; /*Read a statement into the DSTRING varying-length character string host variable.*/ EXEC SQL PREPARE S1 FROM :DSTRING; /*Allocate an SQLDA of 1616 bytes.*/ SQLN =20; EXEC SQL DESCRIBE S1 INTO :SQLDA; /*Analyze the results of the DESCRIBE.*/ /*Allocate storage to hold one row of the result table.*/ /*Set SQLDATA and SQLIND for each column of the result table.*/

Using a cursor
You are now ready to retrieve the SELECT statements results. Dynamically defined SELECT statements must not have an INTO statement. Therefore, all dynamically defined SELECT statements must use a cursor. Special forms of the DECLARE, OPEN, and FETCH are used for dynamically defined SELECT statements. The DECLARE statement for the example statement is:
EXEC SQL DECLARE C1 CURSOR FOR S1;

As you can see, the only difference is that the name of the prepared SELECT statement (S1) is used instead of the SELECT statement itself. The actual retrieval of result rows is made as follows:
EXEC SQL OPEN C1; EXEC SQL FETCH C1 USING DESCRIPTOR :SQLDA; DO WHILE (SQLCODE = 0); /*Display ... the results pointed to by SQLDATA*/ END; /*Display ('END OF LIST')*/ EXEC SQL CLOSE C1;

The cursor is opened, and the result table is evaluated. Notice that there are no input host variables needed for the example SELECT statement. The SELECT result rows are then returned using FETCH. On the FETCH statement, there is no list of output host variables. Rather, the FETCH statement tells SQL to return results into areas described by the descriptor called SQLDA. The same SQLDA that was set up by DESCRIBE is now being used for the output of the SELECT statement. In particular, the results are returned into the storage areas pointed to by the SQLDATA and SQLIND fields of the SQLVAR elements. The following figure shows what the structure looks like after the FETCH statement has been processed.

214

DB2 UDB for AS/400 SQL Programming Concepts V4R5

SQLDA Size S 453 Q 3 L D A (reserved) 1616 20 2 FLDA: (CHAR(3)) E11

Address of FLDA SQLVAR Element 1 (80 bytes) Address of FLDAI 8 WORKDEPT FLDB: (CHAR(4)) 4502

453 SQLVAR Element 2 (80 bytes)

(reserved)

Address of FLDB Address of FLDBI 7 P H O N E N O

Indicator Variables: (halfword) FLDAI: FLDBI: 0 0

RV3W190-0

The meaning of the SMALLINT pointed to by SQLIND is the same as any other indicator variable:
0 <0 >0 Denotes that the returned value is not null. Denotes that the returned value is null. Denotes that the returned value was truncated because the storage area furnished was not large enough. The indicator variable contains the length before truncation.

Note: Unless HOLD is specified, dynamic cursors are closed during COMMIT or ROLLBACK.

Parameter markers
In the example we are using, the SELECT statement that was dynamically run had predictable parameters (input host variables) in the WHERE clause. In the example, it was:
WHERE LASTNAME = 'PARKER'

If you want to run the same SELECT statement several times, using different values for LASTNAME, you can use an SQL statement such as PREPARE or EXECUTE (as described in Using the PREPARE and EXECUTE statements on page 202) like this:
SELECT WORKDEPT, PHONENO FROM CORPDATA.EMPLOYEE WHERE LASTNAME = ?

When your parameters are not predictable, your application cannot know the number or types of the parameters until run time. You can arrange to receive this information at the time your application is run, and by using a USING DESCRIPTOR on the OPEN statement, you can substitute the values contained in specific host variables for the parameter markers included in the WHERE clause of the SELECT statement. To code such a program, you need to use the OPEN statement with the USING DESCRIPTOR clause. This SQL statement is used to not only open a cursor, but to replace each parameter marker with the value of the corresponding host variable. The descriptor name that you specify with this statement must identify an SQLDA that contains a valid description of those host variables. This SQLDA, unlike those
Chapter 10. Dynamic SQL Applications

215

previously described, is not used to return information on data items that are part of a SELECT list. That is, it is not used as output from a DESCRIBE statement, but as input to the OPEN statement. It provides information on host variables that are used to replace parameter markers in the WHERE clause of the SELECT statement. It gets this information from the application, which must be designed to place appropriate values into the necessary fields of the SQLDA. The SQLDA is then ready to be used as a source of information for SQL in the process of replacing parameter markers with host variable data. When you use the SQLDA for input to the OPEN statement with the USING DESCRIPTOR clause, not all of its fields have to be filled in. Specifically, SQLDAID, SQLRES, and SQLNAME can be left blank (SQLNAME (SQLCCSID in REXX) can be set if a specific CCSID is needed.) Therefore, when you use this method for replacing parameter markers with host variable values, you need to determine: v How many ? parameter markers are there? v What are the data types and attributes of these parameters markers (SQLTYPE, SQLLEN, and SQLNAME)? v Do you want an indicator variable? In addition, if the routine is to handle both SELECT and non SELECT statements, you may want to determine what category of statement it is. (Alternatively, you can write code to look for the SELECT keyword.) If your application uses parameter markers, your program has to: 1. Read a statement into the DSTRING varying-length character string host variable. 2. Determine the number of ? parameter markers. 3. Allocate an SQLDA of that size. This is not applicable in REXX. 4. Set SQLN and SQLD to the number of ? parameter markers. SQLN is not applicable in REXX. 5. Set SQLDABC equal to SQLN*LENGTH(SQLVAR) + 16. This is not applicable in REXX. 6. For each ? parameter marker: a. Determine the data types, lengths, and indicators. b. Set SQLTYPE and SQLLEN. Allocate storage to hold the input values (the ? values). Set these values. Set SQLDATA and SQLIND (if applicable) for each ? parameter marker. If character variables are used, and they are in a CCSID other than the job default CCSID, set SQLNAME (SQLCCSID in REXX) accordingly. g. If graphic variables are used and they have a CCSID other than the associated DBCS CCSID for the job CCSID, set the SQLNAME (SQLCCSID in REXX) to that CCSID. h. Issue the OPEN statement with a USING DESCRIPTOR clause to open your cursor and substitute a host variable value for each of the parameter markers. c. d. e. f. | The statement can then be processed normally.

216

DB2 UDB for AS/400 SQL Programming Concepts V4R5

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

Chapter 11. Use of dynamic SQL through client interfaces


You can access DB2 UDB for AS/400 data through client interfaces on AS/400. The following topics help you get started with required tasks: v Accessing data with Java v Accessing data with Domino v Accessing data with Open Database Connectivity (ODBC)

Accessing data with Java


You can access DB2 UDB for AS/400 data in your Java programs with the AS/400 Developer Kit for Java Java Database Connectivity (JDBC) driver. The driver lets you perform the following tasks. v Access AS/400 database files v Access JDBC database functions with embedded Structured Query Language (SQL) for Java v Run SQL statements and process results. See the topic Accessing your AS/400 database with the AS/400 Developer Kit for Java JDBC driver in the AS/400 Information Center for details on how you can use the JDBC driver.

Accessing data with Domino


Domino for AS/400 is a Domino server product that lets you integrate data from DB2 UDB for AS/400 databases and Domino databases in both directions. To take advantage of this integration, you need to understand and manage how authorizations work between the two types of databases. For details, see the Planning authority for Domino database integration topic in the Domino for AS/400 category of the AS/400 Information Center.

Accessing data with Open Database Connectivity (ODBC)


You use the Client Access Express ODBC Driver to enable your ODBC client applications to effectively share data with each other and with the AS/400. See Setting up the Express ODBC driver in the Client Access Express category of the AS/400 Information Center. See the Database Programming topic in the same category for additional details.

Copyright IBM Corp. 2000

217

218

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Chapter 12. Using Interactive SQL


This chapter describes how to use interactive SQL to run SQL statements and use the prompt function. Overview information and tips on using interactive SQL are provided. If you want to learn how to use SQL, you should see Chapter 2. Getting Started with SQL. Special considerations for using interactive SQL with a remote connection are covered in Accessing remote databases with interactive SQL on page 229.

Basic functions of interactive SQL


Interactive SQL allows the programmer or database administrator to quickly and easily define, update, delete, or look at data for testing, problem analysis, and database maintenance. A programmer, using interactive SQL, can insert rows into a table and test the SQL statements before running them in an application program. A database administrator can use interactive SQL to grant or revoke privileges, create or drop collections, tables, or views, or select information from system catalog tables. After an interactive SQL statement is run, a completion message or an error message is displayed. In addition, status messages are normally displayed during long-running statements. You can see help on a message by positioning the cursor on the message and pressing F1=Help. The basic functions supplied by interactive SQL are: v The statement entry function allows you to: Type in an interactive SQL statement and run it. Retrieve and edit statements. Prompt for SQL statements. Page through previous statements and messages. Call session services. Invoke list selection function.

Exit interactive SQL. v The prompt function allows you to type either a complete SQL statement or a partial SQL statement, press F4=Prompt, and then be prompted for the syntax of the statement. It also allows you to press F4 to get a menu of all SQL statements. From this menu, you can select a statement and be prompted for the syntax of the statement. v The list selection function allows you to select from lists of your authorized relational databases, collections, tables, views, columns, constraints, or SQL packages. The selections you make from the lists can be inserted into the SQL statement at the cursor position. v The session services function allows you to: Change session attributes. Print the current session.
Copyright IBM Corp. 2000

219

Remove all entries from the current session. Save the session in a source file.

Starting interactive SQL


You can start using interactive SQL by typing STRSQL on an AS/400 command line. For a complete description of the command and its parameters, see Appendix C. DB2 UDB for AS/400 CL Command Descriptions. The Enter SQL Statements display appears. This is the main interactive SQL display. From this display, you can enter SQL statements and use: v v v v v F4=prompt F13=Session services F16=Select collections F17=Select tables F18=Select columns
Enter SQL Statements Type SQL statement, press Enter. Current connection is to relational database rdjacque. ===>_____________________________________________________________________ _____________________________________________________________________ _____________________________________________________________________ _____________________________________________________________________ _____________________________________________________________________ _____________________________________________________________________ _____________________________________________________________________ _____________________________________________________________________ _____________________________________________________________________ _____________________________________________________________________ _____________________________________________________________________ _____________________________________________________________________ _____________________________________________________________________ _____________________________________________________________________ _____________________________________________________________________ F3=Exit F4=Prompt F12=Cancel F6=Insert line F13=Services F9=Retrieve F10=Copy line F24=More keys Bottom

Press F24=More keys to view the remaining function keys.


_____________________________________________________________________ _____________________________________________________________________ _____________________________________________________________________ _____________________________________________________________________ Bottom F14=Delete line F15=Split line F17=Select tables (files) F16=Select collections (libraries) F18=Select columns F24=More keys (fields)

Note: If you are using the system naming convention, the names in parentheses appear instead of the names shown above. An interactive session consists of: v Parameter values you specified for the STRSQL command .

220

DB2 UDB for AS/400 SQL Programming Concepts V4R5

v SQL statements you entered in the session along with corresponding messages that follow each SQL statement v Values of any parameters you changed using the session services function v List selections you have made Interactive SQL supplies a unique session-ID consisting of your user ID and the current work station ID. This session-ID concept allows multiple users with the same user ID to use interactive SQL from more than one work station at the same time. Also, more than one interactive SQL session can be run from the same work station at the same time from the same user ID. If an SQL session exists and is being re-entered, any parameters specified on the STRSQL command are ignored. The parameters from the existing SQL session are used.

Using statement entry function


The statement entry function is the function you first enter when selecting interactive SQL. You return to the statement entry function after processing each interactive SQL statement. In the statement entry function, you type or prompt for the entire SQL statement and then submit it for processing by pressing the Enter key.

Typing statements
The statement you type on the command line can be one or more lines long. You cannot type comments for the SQL statement in interactive SQL. When the statement has been processed, the statement and the resulting message are moved upward on the display. You can then enter another statement. If a statement is recognized by SQL but contains a syntax error, the statement and the resulting text message (syntax error) are moved upward on the display. In the input area, a copy of the statement is shown with the cursor positioned at the syntax error. You can place the cursor on the message and press F1=Help for more information about the error. You can page through previous statements, commands, and messages. Press F9=Retrieve with your cursor on a previous statement to place a copy of that statement in the input area. If you need more room to type an SQL statement, page down on the display.

Prompting
The prompt function helps you supply the necessary information for the syntax of the statement you want to use. The prompt function can be used in any of the three statement processing modes: *RUN, *VLD, and *SYN. You have two options when using the prompter: v Type the verb of the statement before pressing F4=Prompt. The statement is parsed and the clauses that are completed are filled in on the prompt displays. If you type SELECT and press F4=Prompt, the following display appears:

Chapter 12. Using Interactive SQL

221

Specify SELECT Statement Type SELECT statement information. FROM tables . . . . . SELECT columns . . . WHERE conditions . . GROUP BY columns . . HAVING conditions . . ORDER BY columns . . FOR UPDATE OF columns . . . . . . . . . . . . . . . . . . . . . Press F4 for a list.

_____________________________________________ _____________________________________________ _____________________________________________ _____________________________________________ _____________________________________________ _____________________________________________ _____________________________________________ Bottom Y=Yes, N=No Y=Yes, N=No Y=Yes, N=No

Type choices, press Enter. DISTINCT rows in result table . . . . . . . . . N UNION with another SELECT . . . . . . . . . . . N Specify additional options . . . . . . . . . . . N

F3=Exit F10=Copy line

F4=Prompt F5=Refresh F6=Insert line F9=Specify subquery F12=Cancel F14=Delete line F15=Split line F24=More keys

v Press F4=Prompt before typing anything on the Enter SQL Statements display. You are shown a list of statements. The list of statements varies and depends on the current interactive SQL statement processing mode. For syntax check mode with a language other than *NONE, the list includes all SQL statements. For run and validate modes, only statements that can be run in interactive SQL are shown. You can select the number of the statement you want to use. The system prompts you for the statement you selected. If you press F4=Prompt without typing anything, the following display appears:
Select SQL Statement Select one of the following: 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. ALTER TABLE CALL COMMENT ON COMMIT CONNECT CREATE ALIAS CREATE COLLECTION CREATE INDEX CREATE PROCEDURE CREATE TABLE CREATE VIEW DELETE DISCONNECT DROP ALIAS

Selection __ F3=Exit F12=Cancel

More...

If you press F21=Display Statement on a prompt display, the prompter displays the formatted SQL statement as it was filled in to that point. When Enter is pressed within prompting, the statement that was built through the prompt screens is inserted into the session. If the statement processing mode is *RUN, the statement is run. The prompter remains in control if an error is encountered.

222

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Syntax checking
The syntax of the SQL statement is checked when it enters the prompter. The prompter does not accept a syntactically incorrect statement. You must correct the syntax or remove the incorrect part of the statement or prompting will not be allowed.

Statement processing mode


The statement processing mode can be selected on the Change Session Attributes display. In *RUN (run) or *VLD (validate) mode, only statements that are allowed to run in interactive SQL can be prompted. In *SYN (syntax check) mode, all SQL statements are allowed. The statement is not actually run in *SYN or *VLD modes; only the syntax and existence of objects are checked.

Subqueries
Subqueries can be selected on any display that has a WHERE or HAVING clause. To see the subquery display, press F9=Specify subquery when the cursor is on a WHERE or HAVING input line. A display appears that allows you to type in subselect information. If the cursor is within the parentheses of the subquery when F9 is pressed, the subquery information is filled in on the next display. If the cursor is outside the parentheses of the subquery, the next display is blank. For more information on subqueries, see Subqueries in SELECT statements on page 84.

CREATE TABLE prompting


When prompting for CREATE TABLE, support is available for entering column definitions individually. Place your cursor in the column definition section of the display, and press F4=Prompt. A display that provides room for entering all the information for one column definition is shown. To enter a column name longer than 18 characters, press F20=Display entire name. A window with enough space for a 30 character name will be displayed. The editing keys, F6=Insert line, F10=Copy line, and F14=Delete line, can be used to add and delete entries in the column definition list.

Entering DBCS Data


The rules for processing DBCS data across multiple lines are the same on the Enter SQL Statements display and in the SQL prompter. Each line must contain the same number of shift-in and shift-out characters. When processing a DBCS data string that requires more than one line for entering, the extra shift-in and shift-out characters are removed. If the last column on a line contains a shift-in and the first column of the next line contains a shift-out, the shift-in and shift-out characters are removed by the prompter when the two lines are assembled. If the last two columns of a line contain a shift-in followed by a single-byte blank and the first column of the next line contains a shift-out, the shift-in, blank, shift-out sequence is removed when the two lines are assembled. This removal allows DBCS information to be read as one continuous character string. As an example, suppose the following WHERE condition were entered. The shift characters are shown here at the beginning and end of the string sections on each of the two lines.
Chapter 12. Using Interactive SQL

223

Specify SELECT Statement Type SELECT statement information. Press F4 for a list.

FROM tables . . . . . . . . TABLE1_______________________________________ SELECT columns . . . . . . *____________________________________________ WHERE conditions . . . . . COL1 = '<AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPPQQ> <RRSS>'______________________________________ GROUP BY columns . . . . . _____________________________________________ HAVING conditions . . . . . _____________________________________________ ORDER BY columns . . . . . _____________________________________________ FOR UPDATE OF columns . . . _____________________________________________

When Enter is pressed, the character string is put together, removing the extra shift characters. The statement would look like this on the Enter SQL Statements display:
SELECT * FROM TABLE1 WHERE COL1 = '<AABBCCDDEEFFGGHHIIJJKKLLMMNNOOPPQQRRSS>'

Using the list selection function


The list selection function is available by pressing F4 on certain prompt displays, or F16, F17, or F18 on the Enter SQL Statements display. After pressing the function key, you are given a list of authorized relational databases, collections, tables, views, aliases, columns, constraints, procedures, parameters, or packages from which to choose. If you request a list of tables, but you have not previously selected a collection, you are asked to select a collection first. On a list, you can select one or more items, numerically specifying the order in which you want them to appear in the statement. When the list function is exited, the selections you made are inserted at the position of the cursor on the display you came from. Always select the list you are primarily interested in. For example, if you want a list of columns, but you believe that the columns you want are in a table not currently selected, press F18=Select columns. Then, from the column list, press F17 to change the table. If the table list were selected first, the table name would be inserted into your statement. You would not have a choice for selecting columns. You can request a list at any time while typing an SQL statement on the Enter SQL Statements display. The selections you make from the lists are inserted on the Enter SQL Statements display. They are inserted where the cursor is located in the numeric order that you specified on the list display. Although the selected list information is added for you, you must type the keywords for the statement. The list function tries to provide qualifications that are necessary for the selected columns, tables, and SQL packages. However, sometimes the list function cannot determine the intent of the SQL statement. You need to review the SQL statement and verify that the selected columns, tables, and SQL packages are properly qualified.

Example: Using the list selection function


The following example shows you how to use the list function to build a SELECT statement. Assume you have: v Just entered interactive SQL by typing STRSQL on an AS/400 command line.

224

DB2 UDB for AS/400 SQL Programming Concepts V4R5

v Made no list selections or entries. v Selected *SQL for the naming convention. Note: The example shows lists that are not on your AS/400 system. They are used as an example only. Begin using SQL statements: 1. Type SELECT on the first statement entry line. 2. Type FROM on the second statement entry line. 3. Leave the cursor positioned after FROM.
Enter SQL Statements Type SQL statement, press Enter. ===> SELECT FROM _

4. Press F17=Select tables to obtain a list of tables, because you want the table name to follow FROM. Instead of a list of tables appearing as you expected, a list of collections appears (the Select and Sequence Collections display). You have just entered the SQL session and have not selected a collection to work with. 5. Type a 1 in the Seq column next to YOURCOLL2 collection.
Select and Sequence Collections Type sequence numbers (1-999) to select collections, press Enter. Seq 1 Collection YOURCOLL1 YOURCOLL2 YOURCOLL3 YOURCOLL4 Type SYS SYS SYS SYS Text Company benefits Employee personal data Job classifications/requirements Company insurances

6. Press Enter. The Select and Sequence Tables display appears, showing the tables existing in the YOURCOLL2 collection. 7. Type a 1 in the Seq column next to PEOPLE table.
Select and Sequence Tables Type sequence numbers (1-999) to select tables, press Enter. Seq 1 Table EMPLCO PEOPLE EMPLEXP EMPLEVL EMPLBEN EMPLMED EMPLINVST Collection YOURCOLL2 YOURCOLL2 YOURCOLL2 YOURCOLL2 YOURCOLL2 YOURCOLL2 YOURCOLL2 Type TAB TAB TAB TAB TAB TAB TAB Text Employee Employee Employee Employee Employee Employee Employee company data personal data experience evaluation reports benefits record medical record investments record

8. Press Enter.

Chapter 12. Using Interactive SQL

225

The Enter SQL Statements display appears again with the table name, YOURCOLL2.PEOPLE, inserted after FROM. The table name is qualified by the collection name in the *SQL naming convention.
Enter SQL Statements Type SQL statement, press Enter. ===> SELECT FROM YOURCOLL2.PEOPLE _

9. Position the cursor after SELECT. 10. Press F18=Select columns to obtain a list of columns, because you want the column name to follow SELECT. The Select and Sequence Columns display appears, showing the columns in the PEOPLE table. 11. Type a 2 in the Seq column next to the NAME column. 12. Type a 1 in the Seq column next to the SOCSEC column.
Select and Sequence Columns Type sequence numbers (1-999) to select columns, press Enter. Seq 2 1 Column NAME EMPLNO SOCSEC STRADDR CITY ZIP PHONE Table PEOPLE PEOPLE PEOPLE PEOPLE PEOPLE PEOPLE PEOPLE Type CHARACTER CHARACTER CHARACTER CHARACTER CHARACTER CHARACTER CHARACTER Digits Length 6 30 11 30 20 9 20

13. Press Enter. The Enter SQL Statements display appears again with SOCSEC, NAME appearing after SELECT.
Enter SQL Statements Type SQL statement, press Enter. ===> SELECT SOCSEC, NAME FROM YOURCOLL2.PEOPLE

14. Press Enter. The statement you created is now run. Once you have used the list function, the values you selected remain in effect until you change them or until you change the list of collections on the Change Session Attributes display.

Session services description


The interactive SQL Session Services display is requested by pressing F13 on the Enter SQL Statements display.

226

DB2 UDB for AS/400 SQL Programming Concepts V4R5

From this display you can change session attributes and print, clear, or save the session to a source file. Option 1 (Change session attributes) displays the Change Session Attributes display, which allows you to select the current values that are in effect for your interactive SQL session. The options shown on this display change based on the statement processing option selected. The following session attributes can be changed: v Commitment control attributes. v The statement processing control. v The SELECT output device. v The list of collections. v The list type to select either all your system and SQL objects, or only your SQL objects. v The data refresh option when displaying data. v The allow copy data option. v The naming option. v The programming language. v The date format. v The time format. v The date separator. v The time separator. v The decimal point representation. v The SQL string delimiter. v The sort sequence. v The language identifier. Option 2 (Print current session) accesses the Change Printer display, which lets you print the current session immediately and then continue working. You are prompted for printer information. All the SQL statements you entered and all the messages displayed are printed just as they appear on the Enter SQL Statements display. Option 3 (Remove all entries from current session) lets you remove all the SQL statements and messages from the Enter SQL Statements display and the session history. You are prompted to ensure that you really want to delete the information. Option 4 (Save session in source file) accesses the Change Source File display, which lets you save the session in a source file. You are prompted for the source file name. This function lets you embed the source file into a host language program by using the source entry utility (SEU). Note: Option 4 allows you to embed prototyped SQL statements in a high-level language (HLL) program that uses SQL. The source file created by option 4 may be edited and used as the input source file for the Run SQL Statements (RUNSQLSTM) command.

Chapter 12. Using Interactive SQL

227

Exiting interactive SQL


Pressing F3=Exit on the Enter SQL Statements display allows you to exit the interactive SQL environment and do one of the following: 1. Save and exit session. Leave interactive SQL. Your current session will be saved and used the next time you start interactive SQL. 2. Exit without saving session. Leave interactive SQL without saving your session. 3. Resume session. Remain in interactive SQL and return to the Enter SQL Statements display. The current session parameters remain in effect. 4. Save session in source file. Save the current session in a source file. The Change Source File display is shown to allow you to select where to save the session. You cannot recover and work with this session again in interactive SQL. Notes: 1. Option 4 allows you to embed prototype SQL statements in a high-level language (HLL) program that uses SQL. Use the source entry utility (SEU) to copy the statements into your program. The source file can also be edited and used as the input source file for the Run SQL Statements (RUNSQLSTM) command. 2. If rows have been changed and locks are currently being held for this unit of work and you attempt to exit interactive SQL, a warning message is displayed.

Using an existing SQL session


If you saved only one interactive SQL session by using option 1 (Save and exit session) on the Exit Interactive SQL display, you may resume that session at any workstation. However, if you use option 1 to save two or more sessions on different workstations, interactive SQL will first attempt to resume a session that matches your work station. If no matching sessions are available, then interactive SQL will increase the scope of the search to include all sessions that belong to your user ID. If no sessions for your user ID are available, the system will create a new session for your user ID and current workstation. For example, you saved a session on workstation 1 and saved another session on workstation 2 and you are currently working at workstation 1. Interactive SQL will first attempt to resume the session saved for workstation 1. If that session is currently in use, interactive SQL will then attempt to resume the session that was saved for workstation 2. If that session is also in use, then the system will create a second session for workstation 1. However, suppose you are working at workstation 3 and want to use the ISQL session associated with workstation 2. You then may need to first delete the session from workstation 1 by using option 2 (Exit without saving session) on the Exit Interactive SQL display.

Recovering an SQL session


If the previous SQL session ended abnormally, interactive SQL presents the Recover SQL Session display at the start of the next session (when the next STRSQL command is entered). From this display, you can either: v Recover the old session by selecting option 1 (Attempt to resume existing SQL session).

228

DB2 UDB for AS/400 SQL Programming Concepts V4R5

v Delete the old session and start a new session by selecting option 2 (Delete existing SQL session and start a new session). If you choose to delete the old session and continue with the new session, the parameters you specified when you entered STRSQL are used. If you choose to recover the old session, or are entering a previously saved session, the parameters you specified when you entered STRSQL are ignored and the parameters from the old session are used. A message is returned to indicate which parameters were changed from the specified value to the old session value.

Accessing remote databases with interactive SQL


In interactive SQL, you can communicate with a remote relational database by using the SQL CONNECT statement. Interactive SQL uses the CONNECT (Type 2) semantics (distributed unit of work) for CONNECT statements. Interactive SQL does an implicit connect to the local RDB when starting an SQL session. When the CONNECT statement is completed, a message shows the relational database connection that was established. If starting a new session and COMMIT(*NONE) was not specified, or if restoring a saved session and the commit level saved with the session was not *NONE, the connection will be registered with commitment control. This implicit connect and possible commitment control registration may influence subsequent connections to remote databases. For further information, see Determining connection type on page 269. It is recommended that prior to connecting to the remote system: v When connecting to an application server that does not support distributed unit of work, a RELEASE ALL followed by a COMMIT be issued to end previous connections, including the implicit connection to local. v When connecting to a non-DB2 UDB for AS/400 application server, a RELEASE ALL followed by a COMMIT be issued to end previous connections, including the implicit connection to local, and change the commitment control level to at least *CHG. When you are connecting to a non-DB2 UDB for AS/400 application server, some session attributes are changed to attributes that are supported by that application server. The following table shows the attributes that change.
Table 24. Values Table Session Attribute Date Format Original Value *YMD *DMY *MDY *JUL Time Format *HMS with a : separator *HMS with any other separator *CHG, *NONE *ALL *SYS *NO, *YES *ALWAYS *JIS *EUR *CS Repeatable Read New Value *ISO *EUR *USA *USA

Commitment Control

Naming Convention Allow Copy Data Data Refresh

*SQL *OPTIMIZE *FORWARD

Chapter 12. Using Interactive SQL

229

Table 24. Values Table (continued) Session Attribute Decimal Point Sort Sequence Original Value *SYSVAL Any value other than *HEX New Value *PERIOD *HEX

Notes: 1. If connecting to an AS/400 system that is running a release prior to Version 2 Release 3, the sort sequence value changes to *HEX. 2. When connecting to a DB2/2 or DB2/6000 application server, the date and time formats specified must be the same format. After the connection is completed, a message is sent stating that the session attributes have been changed. The changed session attributes can be displayed by using the session services display. While interactive SQL is running, no other connection can be established for the default activation group. When connected to a remote system with interactive SQL, a statement processing mode of syntax-only checks the syntax of the statement against the syntax supported by the local system instead of the remote system. Similarly, the SQL prompter and list support use the statement syntax and naming conventions supported by the local system. The statement is run, however, on the remote system. Because of differences in the level of SQL support between the two systems, syntax errors may be found in the statement on the remote system at run time. Lists of collections and tables are available when you are connected to the local relational database. Lists of columns are available only when you are connected to a relational database manager that supports the DESCRIBE TABLE statement. When you exit interactive SQL with connections that have pending changes or connections that use protected conversations, the connections remain. If you do not perform additional work over the connections, the connections are ended during the next COMMIT or ROLLBACK operation. You can also end the connections by doing a RELEASE ALL and a COMMIT before exiting interactive SQL. Using interactive SQL for remote access to non-DB2 UDB for AS/400 application servers can require some setup. For more information, see the Distributed Database Programming book. Note: In the output of a communications trace, there may be a reference to a CREATE TABLE XXX statement. This is used to determine package existence; it is part of normal processing, and can be ignored.

230

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Chapter 13. Using the SQL Statement Processor


This section describes the SQL Statement processor. This processor is available when you use the Run SQL Statements (RUNSQLSTM) command. The SQL statement processor allows SQL statements to be executed from a source member. The statements in the source member can be run repeatedly, or changed, without compiling the source. This makes the setup of a database environment easier. The statements that can be used with the SQL statement processor are: v ALTER TABLE v CALL v v v v v v v v v v v v COMMENT ON COMMIT CREATE ALIAS CREATE COLLECTION CREATE DISTINCT TYPE CREATE FUNCTION CREATE INDEX CREATE SCHEMA CREATE TABLE CREATE VIEW DELETE DROP

v CREATE PROCEDURE

v GRANT (Function or Procedure Privileges) v GRANT (Package Privileges) v v v v GRANT (Table Privileges) GRANT (User-Defined Type Privileges) INSERT LABEL ON

v LOCK TABLE v RENAME v v v v v REVOKE (Function or Procedure Privileges) REVOKE (Package Privileges) REVOKE (Table Privileges) REVOKE (User-Defined Type Privileges) ROLLBACK

v SET PATH v SET TRANSACTION v UPDATE In the source member, statements end with a semicolon and do not begin with EXEC SQL. If the record length of the source member is longer than 80, only the first 80 characters will be read. Comments in the source member can be either line comments or block comments. Line comments begin with a double hyphen ()
Copyright IBM Corp. 2000

231

and end at the end of the line. Block comments start with /* and can continue across many lines until the next */ is reached. Block comments can be nested. Only SQL statements and comments are allowed in the source file. The output listing and the resulting messages for the SQL statements are sent to a print file. The default print file is QSYSPRT. To perform syntax checking only on all statements in the source member, specify the PROCESS(*SYN) parameter on the RUNSQLSTM command.

Execution of statements after errors occur


When a statement returns an error with a severity higher than the value specified for the error level (ERRLVL) parameter of the RUNSQLSTM command, the statement has failed. The rest of the statements in the source will be parsed to check for syntax errors, but those statements will not be executed. Most SQL errors have a severity of 30. If you want to continue processing after an SQL statement fails, set the ERRLVL parameter of the RUNSQLSTM command to 30 or higher.

Commitment control in the SQL statement processor


A commitment-control level is specified on the RUNSQLSTM command. If a commitment-control level other than *NONE is specified, the SQL statements are run under commitment control. If all of the statements successfully execute, a COMMIT is done at the completion of the SQL statement processor. Otherwise, a ROLLBACK is done. A statement is considered successful if its return code severity is less than or equal to the value specified on the ERRLVL parameter of the RUNSQLSTM command. The SET TRANSACTION statement can be used within the source member to override the level of commitment control specified on the RUNSQLSTM command. Note: The job must be at a unit of work boundary to use the SQL statement processor with commitment control.

Schemas in the SQL Statement Processor


The SQL statement processor supports the CREATE SCHEMA statement. This is a complex statement that can be thought of as having two distinct sections. The first section defines the collection for the schema. The second section contains DDL statements that define the objects in the collection. The first section can be written in one of two ways: v CREATE SCHEMA collection-name A collection is created using the specified collection name. v CREATE SCHEMA AUTHORIZATION authorization-name A collection is created using the authorization name as the collection name. When the schema is run, the user must have authority to the user profile that is named authorization-name. The privileges held by the authorization-name of the statement must include: Authority to run the CREATE COLLECTION statement Authority to run each SQL statement within the CREATE SCHEMA

232

DB2 UDB for AS/400 SQL Programming Concepts V4R5

The second section of the CREATE SCHEMA statement can contain from zero to any number of the following statements: v COMMENT ON v CREATE ALIAS v CREATE DISTINCT TYPE v CREATE INDEX v CREATE TABLE v CREATE VIEW v GRANT (Table Privileges) v GRANT (User-Defined Type Privileges) v LABEL ON These statements follow directly after the first section of the statement. The statements and sections are not separated by semicolons. If other SQL statements follow this schema definition, the last statement in the schema must be ended by a semicolon. All objects created or referenced in the second part of the schema statement must be in the collection that was created for the schema. All unqualified references are implicitly qualified by the collection that was created. All qualified references must be qualified by the created collection.

Source member listing for the SQL statement processor


5769ST1 V4R5M0 000225 Run SQL Statements Source file...............CORPDATA/SRC Member....................SCHEMA Commit....................*NONE Naming....................*SYS Generation level..........10 Date format...............*JOB Date separator............*JOB Time format...............*HMS Time separator ...........*JOB Default Collection........*NONE IBM SQL flagging..........*NOFLAG ANS flagging..............*NONE Decimal point.............*JOB Sort Sequence.............*JOB Language ID...............*JOB Printer file..............*LIBL/QSYSPRT Source file CCSID.........65535 Job CCSID.................0 Statement processing......*RUN Allow copy of data........*OPTIMIZE Allow blocking............*READ Source member changed on 04/01/98 11:54:10 SCHEMA 06/06/00 15:35:18 Page 1

Figure 9. QSYSPRT listing for SQL statement processor (Part 1 of 3)

Chapter 13. Using the SQL Statement Processor

233

5769ST1 V4R45M0 000225 Run SQL Statements SCHEMA Record *...+... 1 ...+... 2 ...+... 3 ...+... 4 ...+... 5 ...+... 6 ...+... 7 ...+... 8 1 2 DROP COLLECTION DEPT; 3 DROP COLLECTION MANAGER; 4 5 CREATE SCHEMA DEPT 6 CREATE TABLE EMP (EMPNAME CHAR(50), EMPNBR INT) 7 -- EMP will be created in collection DEPT 8 CREATE INDEX EMPIND ON EMP(EMPNBR) 9 -- EMPIND will be created in DEPT 10 GRANT SELECT ON EMP TO PUBLIC; -- grant authority 11 12 INSERT INTO DEPT/EMP VALUES('JOHN SMITH', 1234); 13 /* table must be qualified since no 14 longer in the schema */ 15 16 CREATE SCHEMA AUTHORIZATION MANAGER 17 -- this schema will use MANAGER's 18 -- user profile 19 CREATE TABLE EMP_SALARY (EMPNBR INT, SALARY DECIMAL(7,2), 20 LEVEL CHAR(10)) 21 CREATE VIEW LEVEL AS SELECT EMPNBR, LEVEL 22 FROM EMP_SALARY 23 CREATE INDEX SALARYIND ON EMP_SALARY(EMPNBR,SALARY) 24 25 GRANT ALL ON LEVEL TO JONES GRANT SELECT ON EMP_SALARY TO CLERK 26 -- Two statements can be on the same line * * * * * E N D O F S O U R C E * * * * *

SEQNBR

06/06/00 15:35:18 Last change

Page

Figure 9. QSYSPRT listing for SQL statement processor (Part 2 of 3)

5769ST1 V4R5M0 000225 Run SQL Statements SCHEMA Record *...+... 1 ...+... 2 ...+... 3 ...+... 4 ...+... 5 ...+... 6 ...+... 7 ...+... 8 MSG ID SEV RECORD TEXT SQL7953 0 1 Position 1 Drop of DEPT in QSYS complete. SQL7953 0 3 Position 3 Drop of MANAGER in QSYS complete. SQL7952 0 5 Position 3 Collection DEPT created. SQL7950 0 6 Position 8 Table EMP created in collection DEPT. SQL7954 0 8 Position 8 Index EMPIND created on table EMP in DEPT. SQL7966 0 10 Position 8 GRANT of authority to EMP in DEPT completed. SQL7956 0 10 Position 40 1 rows inserted in EMP in DEPT. SQL7952 0 13 Position 28 Collection MANAGER created. SQL7950 0 19 Position 9 Table EMP_SALARY created in collection MANAGER. SQL7951 0 21 Position 9 View LEVEL created in collection MANAGER. SQL7954 0 23 Position 9 Index SALARYIND created on table EMP_SALARY in MANAGER. SQL7966 0 25 Position 9 GRANT of authority to LEVEL in MANAGER completed. SQL7966 0 25 Position 37 GRANT of authority to EMP_SALARY in MANAGER completed. Message Summary Total Info Warning Error Severe Terminal 13 13 0 0 0 0 00 level severity errors found in source * * * * * E N D O F L I S T I N G * * * * *

SEQNBR

06/06/00 15:35:18 Last change

Page

Figure 9. QSYSPRT listing for SQL statement processor (Part 3 of 3)

234

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Chapter 14. DB2 UDB for AS/400 Data Protection


This chapter describes the security plan for protecting SQL data from unauthorized users and the methods for ensuring data integrity.

Security for SQL objects


All objects on the AS/400 system, including SQL objects, are managed by the system security function. Users may authorize SQL objects through either the SQL GRANT and REVOKE statements or the CL commands Edit Object Authority (EDTOBJAUT), Grant Object Authority (GRTOBJAUT), and Revoke Object Authority (RVKOBJAUT). For more information on system security and the use of the GRTOBJAUT and RVKOBJAUT commands, see the Security - Reference book. The SQL GRANT and REVOKE statements operate on SQL packages, SQL procedures, tables, views, and the individual columns of tables and views. Furthermore, SQL GRANT and REVOKE statements only grant private and public authorities. In some cases, it is necessary to use EDTOBJAUT, GRTOBJAUT, and RVKOBJAUT to authorize users to other objects, such as commands and programs. For more information on the GRANT and REVOKE statements, see the SQL Reference book. The authority checked for SQL statements depends on whether the statement is static, dynamic, or being run interactively. For static SQL statements: v If the USRPRF value is *USER, the authority to run the SQL statement locally is checked using the user profile of the user running the program. The authority to run the SQL statement remotely is checked using the user profile at the application server. *USER is the default for system (*SYS) naming. v If the USRPRF value is *OWNER, the authority to run the SQL statement locally is checked using the user profiles of the user running the program and of the owner of the program. The authority to run the SQL statement remotely is checked using the user profiles of the application server job and the owner of the SQL package. The higher authority is the authority that is used. *OWNER is the default for SQL (*SQL) naming. For dynamic SQL statements: v If the USRPRF value is *USER, the authority to run the SQL statement locally is checked using the user profile of the person running the program. The authority to run the SQL statement remotely is checked using the user profile of the application server job. v If the USRPRF value is *OWNER and DYNUSRPRF is *USER, the authority to run the SQL statement locally is checked using the user profile of the person running the program. The authority to run the SQL statement remotely is checked using the user profile of the application server job. v If the USRPRF value is *OWNER and DYNUSRPRF is *OWNER, the authority to run the SQL statement locally is checked using the user profiles of the user running the program and the owner of the program. The authority to run the SQL statement remotely is checked using the user profiles of the application
Copyright IBM Corp. 2000

235

server job and the owner of the SQL package. The highest authority is the authority that is used. Because of security concerns, you should use the *OWNER parameter value for DYNUSRPRF carefully. This option gives the access authority of the owner program or package to those who run the program. For interactive SQL statements, authority is checked against the authority of the person processing the statement. Adopted authority is not used for interactive SQL statements.

Authorization ID
The authorization ID identifies a unique user and is a user profile object on the AS/400 system. Authorization IDs can be created using the system Create User Profile (CRTUSRPRF) command.

Views
A view can prevent unauthorized users from having access to sensitive data. The application program can access the data it needs in a table, without having access to sensitive or restricted data in the table. A view can restrict access to particular columns by not specifying those columns in the SELECT list (for example, employee salaries). A view can also restrict access to particular rows in a table by specifying a WHERE clause (for example, allowing access only to the rows associated with a particular department number).

Auditing
DB2 UDB for AS/400 is designed to comply with the U.S. government C2 security level. A key feature of that level is the ability to audit actions on the system. DB2 UDB for AS/400 uses the audit facilities managed by the system security function. Auditing can be performed on an object level, user, or system level. The system value QAUDCTL controls whether auditing is performed at the object or user level. The Change User Audit (CHGUSRAUD) command and Change Object Audit (CHGOBJAUD) command specify which users and objects are audited. The system value QAUDLVL controls what types of actions are audited (for example, authorization failures, creates, deletes, grants, revokes, etc.) For more information on auditing see the Security - Reference book. DB2 UDB for AS/400 can also audit row changes by using the DB2 UDB for AS/400 journal support. In some cases, entries in the auditing journal will not be in the same order as they occured. For example, a job that is running under commitment control deletes a table, creates a new table with the same name as the one that was deleted, then does a commit. This will be recorded in the auditing journal as a create followed by a delete. This is because objects that are created are journalled immediately. An object that is deleted under commitment control is hidden and not actually deleted until a commit is done. Once the commit is done, the action is journaled.

236

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Data integrity
Data integrity protects data from being destroyed or changed by unauthorized persons, system operation or hardware failures (such as physical damage to a disk), programming errors, interruptions before a job is completed (such as a power failure), or interference from running applications at the same time (such as serialization problems). Data integrity is ensured by the following functions: v Concurrency v Journaling v Commitment control v Atomic operations v Constraints v Save/restore v Damage tolerance v Index recovery The Database Programming book and the Backup and Recovery book contain more information about each of these functions.

Concurrency
Concurrency is the ability for multiple users to access and change data in the same table or view at the same time without risk of losing data integrity. This ability is automatically supplied by the DB2 UDB for AS/400 database manager. Locks are implicitly acquired on tables and rows to protect concurrent users from changing the same data at precisely the same time. Typically, DB2 UDB for AS/400 will acquire locks on rows to ensure integrity. However, some situations require DB2 UDB for AS/400 to acquire a more exclusive table level lock instead of row locks. For more information see Commitment control on page 239. For example, an update (exclusive) lock on a row currently held by one cursor can be acquired by another cursor in the same program (or in a DELETE or UPDATE statement not associated with the cursor). This will prevent a positioned UPDATE or positioned DELETE statement that references the first cursor until another FETCH is performed. A read (shared no-update) lock on a row currently held by one cursor will not prevent another cursor in the same program (or DELETE or UPDATE statement) from acquiring a lock on the same row. Default and user-specifiable lock-wait time-out values are supported. DB2 UDB for AS/400 creates tables, views, and indexes with the default record wait time (60 seconds) and the default file wait time (*IMMED). This lock wait time is used for DML statements. You can change these values by using the CL commands Change Physical File (CHGPF), Change Logical File (CHGLF), and Override Database File (OVRDBF). The lock wait time used for all DDL statements and the LOCK TABLE statement, is the job default wait time (DFTWAIT). You can change this value by using the CL commands Change Job (CHGJOB) or Change Class (CHGCLS). In the event that a large record wait time is specified, deadlock detection is provided. For example, assume one job has an exclusive lock on row 1 and another
Chapter 14. DB2 UDB for AS/400 Data Protection

237

job has an exclusive lock on row 2. If the first job attempts to lock row 2, it will wait because the second job is holding the lock. If the second job then attempts to lock row 1, DB2 UDB for AS/400 will detect that the two jobs are in a deadlock and an error will be returned to the second job. You can explicitly prevent other users from using a table at the same time by using the SQL LOCK TABLE statement, which is described in the SQL Reference book. Using COMMIT(*RR) will also prevent other users from using a table during a unit of work. In order to improve performance, DB2 UDB for AS/400 will frequently leave the open data path (ODP) open (for details see the Database Performance and Query Optimization information). This performance feature also leaves a lock on tables referenced by the ODP, but does not leave any locks on rows. A lock left on a table may prevent another job from performing an operation on that table. In most cases, however, DB2 UDB for AS/400 will detect that other jobs are holding locks and events will be signalled to those jobs. The event causes DB2 UDB for AS/400 to close any ODPs (and release the table locks) that are associated with that table and are currently only open for performance reasons. Note that the lock wait time out must be large enough for the events to be signalled and the other jobs to close the ODPs or an error will be returned. Unless the LOCK TABLE statement is used to acquire table locks, or either COMMIT(*ALL) or COMMIT(*RR) is used, data which has been read by one job can be immediately changed by another job. Usually, the data that is read at the time the SQL statement is executed and therefore it is very current (for example, during FETCH). In the following cases, however, data is read prior to the execution of the SQL statement and therefore the data may not be current (for example, during OPEN). v ALWCPYDTA(*OPTIMIZE) was specified and the optimizer determined that making a copy of the data would perform better than not making a copy. v Some queries require the database manager to create a temporary result table. The data in the temporary result table will not reflect changes made after the cursor was opened. A temporary result table is required when: The total length in bytes of storage for the columns specified in an ORDER BY clause exceeds 2000 bytes. ORDER BY and GROUP BY clauses specify different columns or columns in a different order. UNION or DISTINCT clauses are specified. ORDER BY or GROUP BY clauses specify columns which are not all from the same table. Joining a logical file defined by the JOINDFT data definition specifications (DDS) keyword with another file. Joining or specifying GROUP BY on a logical file which is based on multiple database file members. The query contains a join in which at least one of the files is a view which contains a GROUP BY clause. The query contains a GROUP BY clause which references a view that contains a GROUP BY clause. v A basic subquery is evaluated when the query is opened.

238

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Journaling
The DB2 UDB for AS/400 journal support supplies an audit trail and forward and backward recovery. Forward recovery can be used to take an older version of a table and apply the changes logged on the journal to the table. Backward recovery can be used to remove changes logged on the journal from the table. When an SQL collection is created, a journal and journal receiver are created in the collection. When SQL creates the journal and journal receiver, they are only created on a user auxiliary storage pool (ASP) if the ASP clause is specified on the CREATE COLLECTION or the CREATE SCHEMA statement. However, because placing journal receivers on their own ASPs can improve performance, the person managing the journal might want to create all future journal receivers on a separate ASP. When a table is created into the collection, it is automatically journaled to the journal DB2 UDB for AS/400 created in the collection (QSQJRN). A table created in a non-collection will also have journaling started if a journal named QSQJRN exists in that library. After this point, it is your responsibility to use the journal functions to manage the journal, the journal receivers, and the journaling of tables to the journal. For example, if a table is moved into a collection, no automatic change to the journaling status occurs. If a table is restored, the normal journal rules apply. That is, if the table was journaled at the time of the save, it is journaled to the same journal at restore time. If the table was not journaled at the time of the save, it is not journaled at restore time. The journal created in the SQL collection is normally the journal used for logging all changes to SQL tables. You can, however, use the system journal functions to journal SQL tables to a different journal. This may be necessary if a table in one collection is a parent to a table in another collection. This is because DB2 UDB for AS/400 requires that the parent and dependent file in a referential constraint be journaled to the same journal when updates or deletes are performed to the parent table. A user can stop journaling on any table using the journal functions, but doing so prevents an application from running under commitment control. If journaling is stopped on a parent table of a referential constraint with a delete rule of NO ACTION, CASCADE, SET NULL, or SET DEFAULT, all update and delete operations will be prevented. Otherwise, an application is still able to function if you have specified COMMIT(*NONE); however, this does not provide the same level of integrity that journaling and commitment control provide.

Commitment control
The DB2 UDB for AS/400 commitment control support provides a means to process a group of database changes (updates, inserts, DDL operations, or deletes) as a single unit of work (transaction). A commit operation guarantees that the group of operations is completed. A rollback operation guarantees that the group of operations is backed out. A commit operation can be issued through several different interfaces. For example, v An SQL COMMIT statement v A CL COMMIT command v A language commit statement (such as an RPG COMMIT statement)

Chapter 14. DB2 UDB for AS/400 Data Protection

239

A rollback operation can be issued through several different interfaces. For example, v An SQL ROLLBACK statement v A CL ROLLBACK command v A language rollback statement (such as an RPG ROLBK statement) The only SQL statements that cannot be committed or rolled back are: v DROP COLLECTION v GRANT or REVOKE if an authority holder exists for the specified object If commitment control was not already started when either an SQL statement is executed with an isolation level other than COMMIT(*NONE) or a RELEASE statement is executed, then DB2 UDB for AS/400 sets up the commitment control environment by implicitly calling the CL command Start Commitment Control (STRCMTCTL). DB2 UDB for AS/400 specifies NFYOBJ(*NONE) and CMTSCOPE(*ACTGRP) parameters along with LCKLVL on the STRCMTCTL command. The LCKLVL specified is the lock level on the COMMIT parameter on the CRTSQLxxx, STRSQL, or RUNSQLSTM commands. In REXX, the LCKLVL specified is the lock level on the SET OPTION statement. 8 You may use the STRCMTCTL command to specify a different CMTSCOPE, NFYOBJ, or LCKLVL. If you specify CMTSCOPE(*JOB) to start the job level commitment definition, DB2 UDB for AS/400 uses the job level commitment definition for programs in that activation group. Note: When using commitment control, the tables referred to in the application program by Data Manipulation Language statements must be journaled. For cursors that use column functions, GROUP BY, or HAVING, and are running under commitment control, a ROLLBACK HOLD has no effect on the cursors position. In addition, the following occurs under commitment control: v If COMMIT(*CHG) and (ALWBLK(*NO) or (ALWBLK(*READ)) is specified for one of these cursors, a message (CPI430B) is sent that says COMMIT(*CHG) requested but not allowed. v If COMMIT(*ALL), COMMIT(*RR), or COMMIT(*CS) with the KEEP LOCKS clause is specified for one of the cursors, DB2 UDB for AS/400 will lock all referenced tables in shared mode (*SHRNUP). The lock prevents concurrent application processes from executing any but read-only operations on the named table. A message (either SQL7902 or CPI430A) is sent that says COMMIT(*ALL), COMMIT(*RR), or COMMIT(*CS) with the KEEP LOCKS clause is specified for one of the cursors requested but not allowed. Message SQL0595 may also be sent. For cursors where either COMMIT(*ALL), COMMIT(*RR), or COMMIT(*CS) with the KEEP LOCKS clause is specified and either catalog files are used or a temporary result table is required, DB2 UDB for AS/400 will lock all referenced tables in shared mode (*SHRNUP). This will prevent concurrent processes from executing anything but read-only operations on the table(s). A message (either SQL7902 or CPI430A) is sent that says COMMIT(*ALL) is requested but not allowed. Message SQL0595 may also be sent.

8. Note that the LCKLVL specified is only the default lock level. After commitment control is started, the SET TRANSACTION SQL statement and the lock level specified on the COMMIT parameter on the CRTSQLxxx, STRSQL, or RUNSQLSTM commands will override the default lock level.

240

DB2 UDB for AS/400 SQL Programming Concepts V4R5

If ALWBLK(*ALLREAD) and COMMIT(*CHG) were specified, when the program was precompiled, all read only cursors will allow blocking of rows and a ROLLBACK HOLD will not roll the cursor position back. If COMMIT(*RR) is requested, the tables will be locked until the query is closed. If the cursor is read only, the table will be locked (*SHRNUP). If the cursor is in update mode, the table will be locked (*EXCLRD). Since other users will be locked out of the table, running with repeatable read will prevent concurrent access of the table. If an isolation level other then COMMIT(*NONE) was specified and the application issues a ROLLBACK or the activation group ends normally (and the commitment definition is not *JOB), all updates, inserts, deletes, and DDL operations made within the unit of work are backed out. If the application issues a COMMIT or the activation group ends normally, all updates, inserts, deletes, and DDL operations made within the unit of work are committed. DB2 UDB for AS/400 uses locks on rows to keep other jobs from accessing changed data before a unit of work completes. If COMMIT(*ALL) is specified, read locks on rows fetched are also used to prevent other jobs from changing data that was read before a unit of work completes. This will not prevent other jobs from reading the unchanged records. This ensures that, if the same unit of work rereads a record, it gets the same result. Read locks do not prevent other jobs from fetching the same rows. Commitment control handles up to 4 million distinct row changes in a unit of work. If COMMIT(*ALL) or COMMIT(*RR) is specified, all rows read are also included in the limit. (If a row is changed or read more than once in a unit of work, it is only counted once toward the limit.) Holding a large number of locks adversely affects system performance and does not allow concurrent users to access rows locked in the unit of work until the end of the unit of work. It is in your best interest to keep the number of rows processed in a unit of work small. Commitment control will allow up to 512 files for each journal to be open under commitment control or closed with pending changes in a unit of work. COMMIT HOLD and ROLLBACK HOLD allows you to keep the cursor open and start another unit of work without issuing an OPEN again. The HOLD value is not available when you are connected to a remote database that is not on an AS/400 system. However, the WITH HOLD option on DECLARE CURSOR may be used to keep the cursor open after a COMMIT. This type of cursor is supported when you are connected to a remote database that is not on an AS/400 system. Such a cursor is closed on a rollback.
Table 25. Record Lock Duration SQL Statement SELECT INTO SET variable VALUES INTO FETCH (read-only cursor) COMMIT Parameter (See note 6) *NONE *CHG *CS (See note 8) *ALL (See note 2) *NONE *CHG *CS (See note 8) *ALL (See note 2) Duration of Record Locks No locks No locks Row locked when read and released From read until ROLLBACK or COMMIT No locks No locks From read until the next FETCH From read until ROLLBACK or COMMIT Lock Type

READ READ

READ READ

Chapter 14. DB2 UDB for AS/400 Data Protection

241

Table 25. Record Lock Duration (continued) SQL Statement FETCH (update or delete capable cursor) (See note 1) COMMIT Parameter (See note 6) *NONE Duration of Record Locks When record not updated or deleted from read until next FETCH When record is updated or deleted from read until UPDATE or DELETE When record not updated or deleted from read until next FETCH When record is updated or deleted from read until COMMIT or ROLLBACK When record not updated or deleted from read until next FETCH When record is updated or deleted from read until COMMIT or ROLLBACK From read until ROLLBACK or COMMIT No locks From insert until ROLLBACK or COMMIT From insert until ROLLBACK or COMMIT From insert until ROLLBACK or COMMIT No locks No locks Each record locked while being read From read until ROLLBACK or COMMIT Each record locked while being From read until ROLLBACK or From read until ROLLBACK or From read until ROLLBACK or Each record locked while being From read until ROLLBACK or From read until ROLLBACK or From read until ROLLBACK or updated COMMIT COMMIT COMMIT deleted COMMIT COMMIT COMMIT Lock Type UPDATE

*CHG

UPDATE

*CS

UPDATE

*ALL INSERT (target table) *NONE *CHG *CS *ALL *NONE *CHG *CS *ALL *NONE *CHG *CS *ALL *NONE *CHG *CS *ALL *NONE *CHG *CS *ALL *NONE *CHG *CS *ALL *NONE *CHG *CS *ALL (see note 2) *NONE *CHG *CS *ALL

UPDATE3 UPDATE UPDATE UPDATE4

INSERT (tables in subselect)

READ READ UPDATE UPDATE UPDATE UPDATE UPDATE UPDATE UPDATE UPDATE UPDATE UPDATE UPDATE UPDATE UPDATE UPDATE UPDATE UPDATE READ READ READ READ

UPDATE (non-cursor)

DELETE (non-cursor)

UPDATE (with cursor)

Lock released when record updated From read until ROLLBACK or COMMIT From read until ROLLBACK or COMMIT From read until ROLLBACK or COMMIT Lock released when record deleted From read until ROLLBACK or COMMIT From read until ROLLBACK or COMMIT From read until ROLLBACK or COMMIT From From From From read read read read until until until until next FETCH next FETCH next FETCH ROLLBACK or COMMIT

DELETE (with cursor)

Subqueries (update or delete capable cursor or UPDATE or DELETE non-cursor) Subqueries (read-only cursor or SELECT INTO)

No locks No locks Each record locked while being read From read until ROLLBACK or COMMIT

READ READ

242

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Table 25. Record Lock Duration (continued) SQL Statement Notes: 1. A cursor is open with UPDATE or DELETE capabilities if the result table is not read-only (see description of DECLARE CURSOR in SQL Reference book) and if one of the following is true: v The cursor is defined with a FOR UPDATE clause. v The cursor is defined without a FOR UPDATE, FOR READ ONLY, or ORDER BY clause and the program contains at least one of the following: Cursor UPDATE referring to the same cursor-name Cursor DELETE referring to the same cursor-name An EXECUTE or EXECUTE IMMEDIATE statement and ALWBLK(*READ) or ALWBLK(*NONE) was specified on the CRTSQLxxx command. 2. A table or view can be locked exclusively in order to satisfy COMMIT(*ALL). If a subselect is processed that includes a UNION, or if the processing of the query requires the use of a temporary result, an exclusive lock is acquired to protect you from seeing uncommitted changes. 3. If the row is not updated or deleted, the lock is reduced to *READ. 4. An UPDATE lock on rows of the target table and a READ lock on the rows of the subselect table. 5. A table or view can be locked exclusively in order to satisfy repeatable read. Row locking is still done under repeatable read. The locks acquired and their duration are identical to *ALL. 6. Repeatable read (*RR) record locks will be the same as the locks indicated for *ALL. 7. For a detailed explanation of isolation levels and locking, see the section entitled Isolation Level in Chapter 1 of the SQL Reference book. 8. If the KEEP LOCKS clause is specified with *CS, any read locks are held until the cursor is closed or until a COMMIT or ROLLBACK is done. If no cursors are associated with the isolation clause, then locks are held until the completion of the SQL statement. COMMIT Parameter (See note 6) Duration of Record Locks Lock Type

Atomic operations
When running under COMMIT(*CHG), COMMIT(*CS), or COMMIT(*ALL), all operations are guaranteed to be atomic. That is, they will complete or they will appear not to have started. This is true regardless of when or how the function was ended or interrupted (such as power failure, abnormal job end, or job cancel). If COMMIT (*NONE) is specified, however, some underlying database data definition functions are not atomic. The following SQL data definition statements are guaranteed to be atomic: ALTER TABLE (See note 1) COMMENT ON (See note 2) LABEL ON (See note 2) GRANT (See note 3) REVOKE (See note 3) DROP TABLE (See note 4) DROP VIEW (See note 4) DROP INDEX DROP PACKAGE

Chapter 14. DB2 UDB for AS/400 Data Protection

243

Notes: 1. If constraints need to be added or removed, as well as column definitions changed, the operations are processed one at a time, so the entire SQL statement is not atomic. The order of operation is: v remove constraints v drop columns for which the RESTRICT option was specified v all other column definition changes (DROP COLUMN CASCADE, ALTER COLUMN, ADD COLUMN) v add constraints 2. If multiple columns are specified for a COMMENT ON or LABEL ON statement, the columns are processed one at a time, so the entire SQL statement is not atomic, but the COMMENT ON or LABEL ON to each individual column or object will be atomic. 3. If multiple tables, SQL packages, or users are specified for a GRANT or REVOKE statement, the tables are processed one at a time, so the entire SQL statement is not atomic, but the GRANT or REVOKE to each individual table will be atomic. 4. If dependent views need to be dropped during DROP TABLE or DROP VIEW, each dependent view is processed one at a time, so the entire SQL statement is not atomic. The following data definition statements are not atomic because they involve more than one DB2 UDB for AS/400 database operation: CREATE ALIAS CREATE COLLECTION CREATE DISTINCT TYPE CREATE FUNCTION CREATE PROCEDURE CREATE TABLE CREATE VIEW CREATE INDEX CREATE SCHEMA DROP ALIAS DROP COLLECTION DROP DISTINCT TYPE DROP FUNCTION DROP PROCEDURE DROP SCHEMA RENAME (See note 1) Notes: 1. RENAME is atomic only if the name or the system name is changed. When both are changed, the RENAME is not atomic. For example, a CREATE TABLE can be interrupted after the DB2 UDB for AS/400 physical file has been created, but before the member has been added. Therefore, in the case of create statements, if an operation ends abnormally, you may have to drop the object and then create it again. In the case of a DROP COLLECTION statement, you may have to drop the collection again or use the CL command Delete Library (DLTLIB) to remove the remaining parts of the collection.

244

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Constraints
DB2 UDB for AS/400 supports unique, referential, and check constraints. A unique constraint is a rule that guarantees that the values of a key are unique. A referential constraint is a rule that all non-null values of foreign keys in a dependent table have a corresponding parent key in a parent table. A check constraint is a rule that limits the values allowed in a column or group of columns. DB2 UDB for AS/400 will enforce the validity of the constraint during any DML (data manipulation language) statement. Certain operations (such as restore of the dependent table), however, cause the validity of the constraint to be unknown. In this case, DML statements may be prevented until DB2 UDB for AS/400 has verified the validity of the constraint. v Unique constraints are implemented with indexes. If an index that implements a unique constraint is invalid, the Edit Rebuild of Access Paths (EDTRBDAP) command can be used to display any indexes that currently require rebuild. v If DB2 UDB for AS/400 does not currently know whether a referential constraint or check constraint is valid, the constraint is considered to be in a check pending state. The Edit Check Pending Constraints (EDTCPCST) command can be used to display any indexes that currently require rebuild. For more information on constraints see the Database Programming book.

Save/Restore
The AS/400 save/restore functions are used to save tables, views, indexes, journals, journal receivers, SQL packages, SQL procedures, user-defined functions, user-defined types, and collections on disk (save file) or to some external media (tape or diskette). The saved versions can be restored onto any AS/400 system at some later time. The save/restore function allows an entire collection, selected objects, or only objects changed since a given date and time to be saved. All information needed to restore an object to its previous state is saved. This function can be used to recover from damage to individual tables by restoring the data with a previous version of the table or the entire collection. When a program that was created for an SQL procedure or a service program that was created for an SQL function or a sourced function is restored, it is automatically added to the SYSROUTINES and SYSPARMS catalogs, as long as the procedure or function does not already exist with the same signature. SQL programs created in QSYS will not be created as SQL procedures when restored. Additionally, external programs or service programs that were referenced on a CREATE PROCEDURE or CREATE FUNCTION statement may contain the information required to register the routine in SYSROUTINES. If the information exists and the signature is unique, the functions or procedures will also be added to SYSROUTINES and SYSPARMS when restored. When an *SQLUDT object is restored for a user-defined type, the user-defined type is automatically added to the SYSTYPES catalog. The appropriate functions needed to cast between the user-defined type and the source type are also created, as long as the type and functions do not already exist. Either a distributed SQL program or its associated SQL package can be saved and restored to any number of AS/400 systems. This allows any number of copies of the SQL programs on different systems to access the same SQL package on the same application server. This also allows a single distributed SQL program to
Chapter 14. DB2 UDB for AS/400 Data Protection

245

connect to any number of application servers that have the SQL package restored (CRTSQLPKG can also be used). SQL packages cannot be restored to a different library. Attention: Restoring a collection to an existing library or to a collection that has a different name does not restore the journal, journal receivers, or IDDU dictionary (if one exists). If the collection is restored to a collection with a different name, the catalog views in that collection will only reflect objects in the old collection. The catalog views in QSYS2, however, will appropriately reflect all objects.

Damage tolerance
The AS/400 system provides several mechanisms to reduce or eliminate damage caused by disk errors. For example, mirroring, checksums, and RAID disks can all reduce the possibility of disk problems. The DB2 UDB for AS/400 functions also have a certain amount of tolerance to damage caused by disk errors or system errors. A DROP operation always succeeds, regardless of the damage. This ensures that should damage occur, at least the table, view, SQL package, or index can be deleted and restored or created again. In the event that a disk error has damaged a small portion of the rows in a table, the DB2 UDB for AS/400 database manager allows you to read rows still accessible.

Index recovery
DB2 UDB for AS/400 supplies several functions to deal with index recovery. v System managed index protection The EDTRCYAP CL command allows a user to instruct DB2 UDB for AS/400 to guarantee that in the event of a system or power failure, the amount of time required to recover all indexes on the system is kept below a specified time. The system automatically journals enough information in a system journal to limit the recovery time to the specified amount. v Journaling of indexes DB2 UDB for AS/400 supplies an index journaling function that makes it unnecessary to rebuild an entire index due to a power or system failure. If the index is journaled, the system database support automatically makes sure the index is in synchronization with the data in the tables without having to rebuild it from scratch. SQL indexes are not journaled automatically. You can, however, use the CL command Start Journal Access Path (STRJRNAP) to journal any index created by DB2 UDB for AS/400. v Index rebuild All indexes on the system have a maintenance option that specifies when an index is maintained. SQL indexes are created with an attribute of *IMMED maintenance. In the event of a power failure or abnormal system failure, if indexes were not protected by one of the previously described techniques, those indexes in the process of change may need to be rebuilt by the database manager to make sure they agree with the actual data. All indexes on the system have a recovery option that specifies when an index should be rebuilt if necessary. All SQL indexes with an attribute of UNIQUE are created with a recovery attribute of *IPL (this means that these indexes are rebuilt before the OS/400 has been

246

DB2 UDB for AS/400 SQL Programming Concepts V4R5

started). All other SQL indexes are created with the *AFTIPL recovery option (this means that after the operating system has been started, indexes are asynchronously rebuilt). During an IPL, the operator can see a display showing indexes needing to be rebuilt and their recovery option. The operator can override the recovery options. v Save and restore of indexes The save/restore function allows you to save indexes when a table is saved by using ACCPTH(*YES) on the Save Object (SAVOBJ) or Save Library (SAVLIB) CL commands. In the event of a restore when the indexes have also been saved, there is no need to rebuild the indexes. Any indexes not previously saved and restored are automatically and asynchronously rebuilt by the database manager.

Catalog integrity
Catalogs contain information about tables, views, SQL packages, indexes, procedures, and parameters in a collection. The database manager ensures that the information in the catalog is accurate at all times. This is accomplished by preventing end users from explicitly changing any information in the catalog and by implicitly maintaining the information in the catalog when changes occur to the tables, views, SQL packages, indexes, procedures, and parameters described in the catalog. The integrity of the catalog is maintained whether objects in the collection are changed by SQL statements, OS/400 CL commands, System/38 Environment CL commands, System/36 Environment functions, or any other product or utility on an AS/400 system. For example, deleting a table can be done by running an SQL DROP statement, issuing an OS/400 DLTF CL command, issuing a System/38 DLTF CL command or entering option 4 on a WRKF or WRKOBJ display. Regardless of the interface used to delete the table, the database manager will remove the description of the table from the catalog at the time the delete is performed. The following is a list of functions and the associated effect on the catalog:
Table 26. Effect of Various Functions on Catalogs Function Add constraint to table Remove of constraint from table Create object into collection Delete of object from collection Restore of object into collection Change of object long comment Change of object label (text) Change of object owner Move of object from a collection Move of object into collection Rename of object Effect on the Catalog Information added to catalog Related information removed from catalog Information added to catalog Related information removed from catalog Information added to catalog Comment updated in catalog Label updated in catalog Owner updated in catalog Related information removed from catalog Information added to catalog Name of object updated in catalog

User auxiliary storage pool (ASP)


An SQL collection can be created in a user ASP by using the ASP clause on the CREATE COLLECTION and CREATE SCHEMA statements. The CRTLIB command
Chapter 14. DB2 UDB for AS/400 Data Protection

247

can also be used to create a library in a user ASP. That library can then be used to receive SQL tables, views, and indexes. See the Backup and Recovery book and the Backup and Recovery book for more information on auxiliary storage pools.

248

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Chapter 15. Testing SQL Statements in Application Programs


This chapter describes how to establish a test environment for SQL statements in an application program and how to debug this program.

Establishing a test environment


Some things you need to test your program are: v Authorization. You need to be authorized to create tables and views, access SQL data, and create and run programs. v A test data structure. If your program updates, inserts, or deletes data from tables and views, you should use test data to verify the running of the program. If your program only retrieves data from tables and views, you might consider using production-level data when testing your program. It is recommended, however, that you use the CL command Start Debug (STRDBG) with UPDPROD(*NO) to assure that the production level data does not accidentally get changed. See the chapter on testing in the CL Programmingbook for more information on debugging. v Test input data. The input data your program uses during testing should be valid data that represents as many possible input conditions as you can think of. You cannot be sure that your output data is valid unless you use valid input data. If your program verifies that input data is valid, include both valid and not valid data to verify that the valid data is processed and the not valid data is detected. You might have to refresh the data for subsequent tests. To test the program thoroughly, test as many of the paths through the program as possible. For example: v Use input data that forces the program to run each of its branches. v Check the results. For example, if the program updates a row, select the row to see if it was updated correctly. v Be sure to test the program error routines. Again, use input data that forces the program to encounter as many of the anticipated error conditions as possible. v Test the editing and validation routines your program uses. Give the program as many different combinations of input data as possible to verify that it correctly edits or validates that data.

Designing a test data structure


To test an application that accesses SQL data, you might have to create test tables and views: v Test views of existing tables. If your application does not change data and the data exists in one or more production-level tables, you might consider using a view of the existing tables. It is also recommended that you use STRDBG command with UPDPROD(*NO) to assure that the production level data does not accidentally get changed. See the chapter on testing in the CL Programming for more information on debugging.

Copyright IBM Corp. 2000

249

v Test tables. When your application creates, changes, or deletes data, you will probably want to test the application by using tables that contain test data. See Chapter 2. Getting Started with SQL for a description of how to create tables and views. Also, you might want to use the CL command Create Duplicate Object (CRTDUPOBJ) to create a duplicate test table, view, or index.

Authorization
Before you can create a table, you must be authorized to create tables and to use the collection in which the table is to reside. In addition, you must have authority to create and run the programs you want to test. If you intend to use existing tables and views (either directly or as the basis for a view), you must be authorized to access those tables and views. If you want to create a view, you must be authorized to create views and must have authorization to each table and view on which the view is based. For more information on specific authorities required for any specific SQL statement, see the SQL Reference book.

Testing your SQL application programs


There are two phases for testing DB2 UDB for AS/400 SQL applications: the program debug phase and the performance verification phase.

Program debug phase


This test phase is done to ensure that the SQL queries are specified correctly and that the program is producing the correct results. Debugging your program with SQL statements is much the same as debugging your program without SQL statements. However, when SQL statements are run in a job in the debug mode, the database manager puts messages in the job log about how each SQL statement ran. This message is an indication of the SQLCODE for the SQL statement. If the statement ran successfully, the SQLCODE value is zero, and a completion message is issued. A negative SQLCODE results in a diagnostic message. A positive SQLCODE results in an informational message. The message is either a 4-digit code prefixed by SQL or a 5-digit code prefixed by SQ. For example, an SQLCODE of 204 results in a message of SQL0204, and an SQLCODE of 30000 results in a message of SQ30000. Associated with a SQLCODE is a SQLSTATE. The SQLSTATE is an additional return code provided in the SQLCA that identifies common error conditions among the different IBM relational database products. The same error condition on different relational database products will produce the same SQLSTATE. The same error conditions will not produce the same SQLCODE. This return code is particularly useful when determining the cause of errors returned from the relational database operations performed on non-DB2 UDB for AS/400 system. For non-ILE program debugging, references to high-level language statement numbers in debug mode must be taken from the compile listing. For ILE program debugging, precompile the program specifying DBGVIEW(*SOURCE) and then use the source-level debugger.

250

DB2 UDB for AS/400 SQL Programming Concepts V4R5

SQL will always put messages in the job log for negative SQLCODEs and positive codes other than +100 regardless of whether it is in debug mode or not.

Performance verification phase


This test phase verifies that the appropriate indexes are available and that the queries are coded in a manner that allows the database manager to resolve the queries in the expected response time. The performance of an SQL application is dependent on the attributes of the tables being accessed. If you use small tables, the response time of the query is not affected by the availability of indexes. However, when you run that same query on a database with large tables and appropriate indexes do not exist, the response time for the queries can be very long. The test environment should resemble the production environment as closely as possible. The test collection should have tables with the same names and composition as the production collection. The same indexes need to be available over the tables in both collections. The number of rows and the distribution of values in the tables should be similar. See the Database Performance and Query Optimization book for a description of the tools and commands you can use to verify performance.

Chapter 15. Testing SQL Statements in Application Programs

251

252

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Chapter 16. Solving Common Database Problems


This chapter describes techniques for solving some common database problems. Techniques are provided to help you do the following tasks: v Page through retrieved data v Retrieve data in reverse order v Establish position at the end of a table v Add data to the end of a table v Update data as it is retrieved from a table v Update data previously retrieved v Change the table definition

Paging through retrieved data


When a program retrieves data from the database, the FETCH statement allows the program to page forward through the data. If you are using a scrollable cursor, then the program can page anywhere in the file, based on the scroll option specified on the FETCH statement. This allows the program to retrieve the data more than once. Several options that can be used to page through the data are listed in 56.

Retrieving in reverse order


If there is only one row for each value of DEPTNO, then the following statement specifies a unique ordering of rows:
SELECT * FROM DEPARTMENT WHERE LOCATION = 'MINNESOTA' ORDER BY DEPTNO

To retrieve the same rows in reverse order, simply specify that the order is descending, as in this statement:
SELECT * FROM DEPARTMENT WHERE LOCATION = 'MINNESOTA' ORDER BY DEPTNO DESC

A cursor on the second statement would retrieve rows in exactly the opposite order from a cursor on the first statement. But that is guaranteed only if the first statement specifies a unique ordering. If both statements are required in the same program, it might be useful to have two indexes on the DEPTNO column, one in ascending order and one in descending order.

Establishing position at the end of a table


For a scrollable cursor, the end of the table can be determined by the following:
FETCH AFTER FROM C1

Copyright IBM Corp. 2000

253

Once the cursor is positioned at the end of the table, the program can use the PRIOR or RELATIVE scroll options to position and fetch data starting from the end of the table.

Adding data to the end of a table


The order in which rows are returned to your program depends on the ORDER BY clause in the SQL statement. To get the effect of adding data to the end of a table, include a sequence number column in the table definition. Then, when you retrieve data from the table, use an ORDER BY clause naming that column.

Updating data as it is retrieved from a table


You can update rows of data as you retrieve them. On the select-statement, use FOR UPDATE OF followed by a list of columns that may be updated. Then use the cursor-controlled UPDATE statement. The WHERE CURRENT OF clause names the cursor that points to the row you want to update. If a FOR UPDATE OF, an ORDER BY, a FOR READ ONLY, or a SCROLL clause without the DYNAMIC clause is not specified, all columns can be updated. If a multiple-row FETCH statement has been specified and run, the cursor is positioned on the last row of the block. Therefore, if the WHERE CURRENT OF clause is specified on the UPDATE statement, the last row in the block is updated. If a row within the block must be updated, the program must first position the cursor on that row. Then the UPDATE WHERE CURRENT OF can be specified. Consider the following example:
Table 27. Updating a Table Scrollable Cursor SQL Statement EXEC SQL DECLARE THISEMP DYNAMIC SCROLL CURSOR FOR SELECT EMPNO, WORKDEPT, BONUS FROM CORPDATA.EMPLOYEE WHERE WORKDEPT = D11 FOR UPDATE OF BONUS END-EXEC. EXEC SQL OPEN THISEMP END-EXEC. EXEC SQL WHENEVER NOT FOUND GO TO CLOSE-THISEMP END-EXEC. EXEC SQL FETCH NEXT FROM THISEMP FOR 5 ROWS INTO :DEPTINFO :IND-ARRAY END-EXEC. ... determine if any employees in department D11 receive a bonus less than $500.00. If so, update that record to the new minimum of $500.00. DEPTINFO and IND-ARRAY are declared in the program as a host structure array and an indicator array. Comments

254

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Table 27. Updating a Table (continued) Scrollable Cursor SQL Statement EXEC SQL FETCH RELATIVE :NUMBACK FROM THISEMP END-EXEC. EXEC SQL UPDATE CORPDATA.EMPLOYEE SET BONUS = 500 WHERE CURRENT OF THISEMP END-EXEC. EXEC SQL FETCH RELATIVE :NUMBACK FROM THISEMP FOR 5 ROWS INTO :DEPTINFO :IND-ARRAY END-EXEC. ... branch back to determine if any more employees in the block have a bonus under $500.00. ... branch back to fetch and process the next block of rows. CLOSE-THISEMP. EXEC SQL CLOSE THISEMP END-EXEC. Comments ... positions to the record in the block to update by fetching in the reverse order. ... updates the bonus for the employee in department D11 that is under the new $500.00 minimum. ... positions to the beginning of the same block that was already fetched and fetches the block again. (NUMBACK -(5 - NUMBACK - 1))

Restrictions
You cannot use FOR UPDATE OF with a select-statement that includes any of these elements: v The first FROM clause identifies more than one table or view. v The first FROM clause identifies a read-only view. v The first SELECT clause specifies the keyword DISTINCT. v v v v The outer subselect contains a GROUP BY clause. The outer subselect contains a HAVING clause. The first SELECT clause contains a column function. The select-statement contains a subquery such that the base object of the outer subselect and of the subquery is the same table. v The select-statement contains a UNION or UNION ALL operator. v The select-statement includes a FOR READ ONLY clause. v The SCROLL keyword is specified without DYNAMIC. If a FOR UPDATE OF clause is specified, you cannot update columns that were not named in the FOR UPDATE OF clause. But you can name columns in the FOR UPDATE OF clause that are not in the SELECT list, as in this example:
SELECT A, B, C FROM TABLE FOR UPDATE OF A,E

Do not name more columns than you need in the FOR UPDATE OF clause; indexes on those columns are not used when you access the table.

Chapter 16. Solving Common Database Problems

255

Updating data previously retrieved


You can page through and update data that had previously been retrieved by doing one of three things: v Use the UPDATE statement with a WHERE clause that names all of the values in the row or specifies a unique key of the table. You can code one statement, using host variables in the WHERE clause, and run the same statement many times with different values of the variables to update different rows. v For a scrollable cursor, the program can use the appropriate scroll options to retrieve the row that had previously been fetched. Then, using the WHERE CURRENT OF clause on the UPDATE statement, the row can be changed to the appropriate value.

Changing the table definition


You can add, drop, and alter columns in a table using the SQL ALTER TABLE statement or the Change Physical File (CHGPF) CL command. See the SQL Reference book for information on how to use the SQL ALTER TABLE statement. See the Control Language (CL) book for information on how to use the Change Physical File (CHGPF) CL command. You can also dynamically create a view of the table, which includes only the columns you want, in the order you want.

256

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Chapter 17. Distributed Relational Database Function


A distributed relational database consists of a set of SQL objects that are spread across interconnected computer systems. These relational databases can be of the same type (for example, DB2 UDB for AS/400) or of different types (DB2 for OS/390, DB2 for VM, DB2 Universal Database (UDB), or non-IBM database management systems which support DRDA). Each relational database has a relational database manager to manage the tables in its environment. The database managers communicate and cooperate with each other in a way that allows a given database manager access to run SQL statements on a relational database on another system. The application requester supports the application side of a connection. The application server is the local or remote database to which an application requester is connected. DB2 UDB for AS/400 provides support for Distributed Relational Database Architecture (DRDA) to allow an application requester to communicate with application servers. In addition, DB2 UDB for AS/400 can invoke exit programs to allow access to data on other database management systems which do not support DRDA. These exit programs are called application requester driver (ARD) programs. DB2 UDB for AS/400 supports two levels of distributed relational database: v Remote unit of work (RUW) Remote unit of work is where the preparation and running of SQL statements occurs at only one application server during a unit of work. DB2 UDB for AS/400 supports RUW over either APPC or TCP/IP. v Distributed unit of work (DUW) Distributed unit of work is where the preparation and running of SQL statements can occur at multiple applications servers during a unit of work. However, a single SQL statement can only refer to objects located at a single application server. DB2 UDB for AS/400 supports DUW over APPC only. For comprehensive information about distributed relational databases, see theDistributed Database Programming book.

DB2 UDB for AS/400 distributed relational database support


The DB2 UDB Query Manager and SQL Development Kit licensed program supports interactive access to distributed databases with the following SQL statements: v CONNECT v SET CONNECTION v DISCONNECT v v v v RELEASE DROP PACKAGE GRANT PACKAGE REVOKE PACKAGE

For detailed descriptions of these statements, see the SQL Reference book.

Copyright IBM Corp. 2000

257

Additional support is provided by the development kit through parameters on the SQL precompiler commands: Create SQL ILE C Object (CRTSQLCI) command Create SQL COBOL Program (CRTSQLCBL) command Create SQL ILE COBOL Object (CRTSQLCBLI) command Create SQL PL/I Program (CRTSQLPLI) command Create SQL RPG Program (CRTSQLRPG) command Create SQL ILE RPG Object (CRTSQLRPGI) command For more information on the SQL precompiler commands, see the topic Preparing and Running a Program with SQL Statements in the SQL Programming with Host Languages information. The create SQL Package (CRTSQLPKG) command lets you create an SQL package from an SQL program that was created as a distributed program. Syntax and parameter definitions for the CRTSQLPKG and CRTSQLxxx commands are provided in Appendix C. DB2 UDB for AS/400 CL Command Descriptions.

DB2 UDB for AS/400 distributed relational database example program


A remote unit of work relational database sample program has been shipped with the SQL product. There are several files and members within the QSQL library to help you set up an environment that will run a distributed DB2 UDB for AS/400 sample program. To use these files and members, you need to run the SETUP batch job located in the file QSQL/QSQSAMP. The SETUP batch job allows you to customize the example to do the following: v Create the QSQSAMP library at the local and remote locations. v Set up relational database directory entries at the local and remote locations. v Create application panels at the local location. v Precompile, compile, and run programs to create distributed sample application collections, tables, indexes, and views. v Load data into the tables at the local and remote locations. v Precompile and compile programs. v Create SQL packages at the remote location for the application programs. v Precompile, compile, and run the program to update the location column in the department table. Before running the SETUP, you may need to edit the SETUP member of the QSQL/QSQSAMP file. Instructions are included in the member as comments. To run the SETUP, specify the following command on the AS/400 command line:
========> SBMDBJOB QSQL/QSQSAMP SETUP

Wait for the batch job to complete. To use the sample program, specify the following command on the command line:
========> ADDLIBLE QSQSAMP

258

DB2 UDB for AS/400 SQL Programming Concepts V4R5

To call the first display that allows you to customize the sample program, specify the following command on the command line.
========> CALL QSQ8HC3

The following display appears. From this display, you can customize your database sample program.
DB2 for OS/400 ORGANIZATION APPLICATION ACTION...........: D (DISPLAY) OBJECT...........: DS (DEPT STRUCTURE) _ __ A (ADD) U (UPDATE) DE (DEPARTMENT) E (ERASE) EM (EMPLOYEE) MN (MANAGER NAME)

SEARCH CRITERIA..: __ DI (DEPARTMENT ID) DN (DEPARTMENT NAME) EI (EMPLOYEE ID) MI (MANAGER ID) EN (EMPLOYEE NAME) LOCATION.........: DATA.............: ________________

(BLANK IMPLIES LOCAL LOCATION)

_______________________________

Bottom F3=Exit (C) COPYRIGHT IBM CORP. 1982, 1991

SQL package support


The OS/400 program supports an object called an SQL package. (OS/400 object type is *SQLPKG.) The SQL package contains the control structures and access plans necessary to process SQL statements on the application server when running a distributed program. An SQL package can be created when: v The RDB parameter is specified on the CRTSQLxxx command and the program object is successfully created. The SQL package will be created on the system specified by the RDB parameter. If the compile is unsuccessful or the compile only creates the module object, the SQL package will not be created. v Using the CRTSQLPKG command. The CRTSQLPKG can be used to create a package when the package was not created at precompile time or if the package is needed at an RDB other than the one specified on the precompile command. The Delete SQL Package (DLTSQLPKG) command allows you to delete an SQL package on the local system. An SQL package is not created unless the privileges held by the authorization ID associated with the creation of the SQL package includes appropriate authority for creating a package on the remote system (the application server). To run the program, the authorization ID must include EXECUTE privileges on the SQL package. On AS/400 systems, the EXECUTE privilege includes system authority of *OBJOPR and *EXECUTE. The syntax for the Create SQL Package (CRTSQLPKG) command is shown in Appendix C. DB2 UDB for AS/400 CL Command Descriptions.
Chapter 17. Distributed Relational Database Function

259

Valid SQL statements in an SQL package


Programs that connect to another AS/400 can use any of the SQL statements as described in the SQL Reference book, except the SET TRANSACTION statement. Programs compiled using DB2 UDB for AS/400 that refer to a system that is not DB2 UDB for AS/400 can use executable SQL statements supported by that remote system. The precompiler will continue to issue diagnostic messages for statements it does not understand. These statements are sent to the remote system during the creation of the SQL package. The run-time support will return a SQLCODE of -84 or -525 when the statement cannot be run on the current application server. For example, multiple-row FETCH, blocked INSERT, and scrollable cursor support are allowed only in distributed programs where both the application requester and application server are OS/400 at Version 2 Release 2 or later. For more information, see the appendix that contains the section Considerations for Using Distributed Relational Database in the SQL Reference book.

Considerations for creating an SQL package


There are many considerations to think about when you are creating an SQL package. Some of these considerations are listed below.

CRTSQLPKG Authorization
When creating an SQL package on an AS/400 system the authorization ID used must have *USE authority to the CRTSQLPKG command.

Creating a Package on a non-DB2 UDB for AS/400


When you create a program and SQL package for a non-DB2 UDB for AS/400, and try to use SQL statements that are unique to that relational database, the CRTSQLxxx GENLVL parameter should be set to 30. The program will be created unless a message with a severity level of greater than 30 is issued. If a message is issued with a severity level of greater than 30, the statement is probably not valid for any relational database. For example, undefined or unusable host variables or constants that are not valid would generate a message severity greater than 30. The precompiler listing should be checked for unexpected messages when running with a GENLVL greater than 10. When you are creating a package for a DB2 Universal Database, you must set the GENLVL parameter to a value less than 20. If the RDB parameter specifies a system that is not a DB2 UDB for AS/400 system, then the following options should not be used on the CRTSQLxxx command: v COMMIT(*NONE) v OPTION(*SYS) v DATFMT(*MDY) v DATFMT(*DMY) v v v v v DATFMT(*JUL) DATFMT(*YMD) DATFMT(*JOB) DYNUSRPRF(*OWNER) TIMFMT(*HMS) if TIMSEP(*BLANK) or TIMSEP(,) is specified

v SRTSEQ(*JOBRUN) v SRTSEQ(*LANGIDUNQ)

260

DB2 UDB for AS/400 SQL Programming Concepts V4R5

v SRTSEQ(*LANGIDSHR) v SRTSEQ(library-name/table-name) Note: When connecting to a DB2 Universal Database application server, the following additional rules apply: v The specified date and time formats must be the same format v A value of *BLANK must be used for the TEXT parameter v Default collections (DFTRDBCOL) are not supported v The CCSID of the source program from which the package is being created must not be 65535; if 65535 is used, an empty package is created.

Target Release (TGTRLS)


While creating the package, the SQL statements are checked to determine which release can support the function. This release is set as the restore level of the package. For example, if the package contains a CREATE TABLE statement which adds a FOREIGN KEY constraint to the table, then the restore level of the package will be Version 3 Release 1, because FOREIGN KEY constraints were not supported prior to this release. TGTRLS message are suppressed when the TGTRLS parameter is *CURRENT.

SQL Statement Size


The create SQL package function may not be able to handle the same size SQL statement that the precompiler can process. During the precompile of the SQL program, the SQL statement is placed into the associated space of the program. When this occurs, each token is separated by a blank. In addition, when the RDB parameter is specified, the host variables of the source statement are replaced with an H. The create SQL package function passes this statement to the application server, along with a list of the host variables for that statement. The addition of the blanks between the tokens and the replacement of host variables may cause the statement to exceed the maximum SQL statement size (SQL0101 reason 5).

Statements that do not require a package


In some cases, you might try to create an SQL package but the SQL package will not be created and the program will still run. This situation occurs when the program contains only SQL statements that do not require an SQL package to run. For example, a program that contains only the SQL statement DESCRIBE TABLE will generate message SQL5041 during SQL package creation. The SQL statements that do not require an SQL package are: v DESCRIBE TABLE v COMMIT v ROLLBACK v CONNECT v SET CONNECTION v DISCONNECT v RELEASE

Package object type


SQL packages are always created as non-ILE objects and always run in the default activation group.

Chapter 17. Distributed Relational Database Function

261

ILE programs and service programs


ILE programs and service programs that bind several modules containing SQL statements must have a separate SQL package for each module.

Package creation connection


The type of connection done for the package creation is based on the type of connect requested using the RDBCNNMTH parameter. If RDBCNNMTH(*DUW) was specified, commitment control is used and the connection may be a read-only connection. If the connection is read-only, then the package creation will fail.

Unit of work
Because package creation implicitly performs a commit or rollback, the commit definition must be at a unit of work boundary before the package creation is attempted. The following conditions must all be true for a commit definition to be at a unit of work boundary: v SQL is at a unit of work boundary. v There are no local or DDM files open using commitment control and no closed local or DDM files with pending changes. v There are no API resources registered. v There are no LU 6.2 resources registered that are not associated with DRDA or DDM.

Creating packages locally


The name specified on the RDB parameter can be the name of the local system. If it is the name of the local system, the SQL package will be created on the local system. The SQL package can be saved (SAVOBJ command) and then restored (RSTOBJ command) to another AS/400 system. When you run the program with a connection to the local system, the SQL package is not used. If you specify *LOCAL for the RDB parameter, an *SQLPKG object is not created, but the package information is saved in the *PGM object.

Labels
You can use the LABEL ON statement to create a description for the SQL package.

Consistency token
The program and its associated SQL package contain a consistency token that is checked when a call is made to the SQL package. The consistency tokens must match or the package cannot be used. It is possible for the program and SQL package to appear to be uncoordinated. Assume the program is on the AS/400 system and the application server is another AS/400 system. The program is running in session A and it is recreated in session B (where the SQL package is also recreated). The next call to the program in session A could result in a consistency token error. To avoid locating the SQL package on each call, SQL maintains a list of addresses for SQL packages that are used by each session. When session B re-creates the SQL package, the old SQL package is moved to the QRPLOBJ library. The address to the SQL package in session A is still valid. (This situation can be avoided by creating the program and SQL package from the session that is running the program, or by submitting a remote command to delete the old SQL package before creating the program.)

262

DB2 UDB for AS/400 SQL Programming Concepts V4R5

To use the new SQL package, you should end the connection with the remote system. You can either sign off the session and then sign on again, or you can use the interactive SQL (STRSQL) command to issue a DISCONNECT for unprotected network connections or a RELEASE followed by a COMMIT for protected connections. RCLDDMCNV should then be used to end the network connections. Call the program again.

SQL and recursion


If you invoke SQL from an attention key program while you are already precompiling, you will receive unpredictable results. The CRTSQLxxx, CRTSQLPKG, STRSQL commands and the SQL run-time environment are not recursive. They will produce unpredictable results if recursion is attempted. Recursion would occur if while one of the commands is running, (or running a program with embedded SQL statements) the job is interrupted before the command has completed, and another SQL function is started.

CCSID considerations for SQL


If you are running a distributed application and one of your systems is not an AS/400 system, the job CCSID value on the AS/400 cannot be set to 65535. Before requesting that the remote system create an SQL package, the application requester always converts the name specified on the RDB parameter, SQL package name, library name, and the text of the SQL package from the CCSID of the job to CCSID 500. This is required by DRDA. When the remote relational database is an AS/400 system, the names are not converted from CCSID 500 to the job CCSID. It is recommended that delimited identifiers not be used for table, view, index, collection, library, or SQL package names. Conversion of names does not occur between systems with different CCSIDs. Consider the following example with system A running with a CCSID of 37 and system B running with a CCSID of 500. v Create a program that creates a table with the name ab|c on system A. v Save program ab|c on system A, then restore it to system B. v The code point for in CCSID 37 is x5F while in CCSID 500 it is xBA. v On system B the name would display a[b]c. If you created a program that referenced the table whose name was ab|c., the program would not find the table. The at sign (@), pound sign (#), and dollar sign ($) characters should not be used in SQL object names. Their code points depend on the CCSID used. If you use delimited names or the three national extenders, the name resolution functions may possibly fail in a future release.

Connection management and activation groups Connections and conversations


Prior to the use of TCP/IP by DRDA, the term connection was not ambiguous. It referred to a connection from the SQL point of view. That is, a connection started at the time one did a CONNECT TO some RDB, and ended when a DISCONNECT was done or a RELEASE ALL followed by a successful COMMIT occurred. The
Chapter 17. Distributed Relational Database Function

263

APPC conversation may or may not have been kept up, depending on the jobs DDMCNV attribute value, and whether the conversation was with an AS/400 or other type of system. TCP/IP terminology does not include the term conversation. A similar concept exists, however. With the advent of TCP/IP support by DRDA, use of the term conversation will be replaced, in this book, by the more general term connection, unless the discussion is specifically about an APPC conversation. Therefore, there are now two different types of connections about which the reader must be aware: SQL connections of the type described above, and network connections which replace the term conversation. Where there would be the possibility of confusion between the two types of connections, the word will be qualified by SQL or network to allow the reader to understand the intended meaning. SQL connections are managed at the activation group level. Each activation group within a job manages its own connections and these connections are not shared across activation groups. For programs that run in the default activation group, connections are still managed as they were prior to Version 2 Release 3. The following is an example of an application that runs in multiple activation groups. This example is used to illustrate the interaction between activation groups, connection management, and commitment control. It is not a recommended coding style.

Source code for PGM1:


.... EXEC SQL CONNECT TO SYSB END-EXEC. EXEC SQL SELECT .... END-EXEC. CALL PGM2. .... Figure 10. Source Code for PGM1

Command to create program and SQL package for PGM1:


CRTSQLCBL PGM(PGM1) COMMIT(*NONE) RDB(SYSB)

264

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Source code for PGM2:


... EXEC SQL CONNECT TO SYSC; EXEC SQL DECLARE C1 CURSOR FOR SELECT ....; EXEC SQL OPEN C1; do { EXEC SQL FETCH C1 INTO :st1; EXEC SQL UPDATE ... SET COL1 = COL1+10 WHERE CURRENT OF C1; PGM3(st1); } while SQLCODE == 0; EXEC SQL CLOSE C1; EXEC SQL COMMIT;

....

Figure 11. Source Code for PGM2

Command to create program and SQL package for PGM2:


CRTSQLCI OBJ(PGM2) COMMIT(*CHG) RDB(SYSC) OBJTYPE(*PGM)

Source code for PGM3:


... EXEC SQL INSERT INTO TAB VALUES(:st1); EXEC SQL COMMIT; .... Figure 12. Source Code for PGM3

Commands to create program and SQL package for PGM3:


CRTSQLCI OBJ(PGM3) COMMIT(*CHG) RDB(SYSD) OBJTYPE(*MODULE) CRTPGM PGM(PGM3) ACTGRP(APPGRP) CRTSQLPKG PGM(PGM3) RDB(SYSD)

Chapter 17. Distributed Relational Database Function

265

SYSA Job: SYSB (Remote)


Call

Job:
Default Activation Group: SQL Package for PGM1

Default Activation Group:

PGM1 Call

Connect

SYSC (Remote)
System-Named Activation Group:

Job:
Default Activation Group:
Connect

PGM2

SQL Package for PGM2

Call

Return Call

Activation Group APPGRP:

SYSD (Remote) Job:


Connect
Default Activation Group: SQLPackage for PGM3

PGM3

RV2W577-3

In this example, PGM1 is a non-ILE program created using the CRTSQLCBL command. This program runs in the default activation group. PGM2 is created using the CRTSQLCI command, and it runs in a system-named activation group. PGM3 is also created using the CRTSQLCI command, but it runs in the activation group named APPGRP. Because APPGRP is not the default value for the ACTGRP parameter, the CRTPGM command is issued separately. The CRTPGM command is followed by a CRTSQLPKG command that creates the SQL package object on the SYSD relational database. In this example, the user has not explicitly started the job level commitment definition. SQL implicitly starts commitment control. 1. PGM1 is called and runs in the default activation group. 2. PGM1 connects to relational database SYSB and runs a SELECT statement. 3. PGM1 then calls PGM2, which runs in a system-named activation group. 4. PGM2 does a connect to relational database SYSC. Because PGM1 and PGM2 are in different activation groups, the connection started by PGM2 in the system-named activation group does not disconnect the connection started by PGM1 in the default activation group. Both connections are active. PGM2 opens the cursor and fetches and updates a row. PGM2 is running under commitment control, is in the middle of a unit of work, and is not at a connectable state. 5. PGM2 calls PGM3, which runs in activation group APPGRP. 6. The INSERT statement is the first statement run in activation group APPGRP. The first SQL statement causes an implicit connect to relational database SYSD. A row is inserted into table TAB located at relational database SYSD. The insert

266

DB2 UDB for AS/400 SQL Programming Concepts V4R5

is then committed. The pending changes in the system-named activation group are not committed, because commitment control was started by SQL with a commit scope of activation group. 7. PGM3 is then exited and control returns to PGM2. PGM2 fetches and updates another row. 8. PGM3 is called again to insert the row. An implicit connect was done on the first call to PGM3. It is not done on subsequent calls because the activation group did not end between calls to PGM3. Finally, all the rows are processed by PGM2 and the unit of work associated with the system-named activation group is committed.

Multiple connections to the same relational database


If different activation groups connect to the same relational database, each SQL connection has its own network connection and its own application server job. If activation groups are run with commitment control, changes committed in one activation group do not commit changes in other activation groups unless the job-level commitment definition is used.

SYSA Job:

SYSB Job:

Default ActivationGroup:
Connect

Job:
System-Named Activation Group:

Connect

RV2W578-2

Implicit connection management for the default activation group


The application requester can implicitly connect to an application server. Implicit SQL connection occurs when the application requester detects the first SQL statement is being issued by the first active SQL program for the default activation group and the following items are true: v The SQL statement being issued is not a CONNECT statement with parameters. v SQL is not active in the default activation group.
Chapter 17. Distributed Relational Database Function

267

For a distributed program, the implicit SQL connection is to the relational database specified on the RDB parameter. For a nondistributed program, the implicit SQL connection is to the local relational database. SQL will end any active connections in the default activation group when SQL becomes not active. SQL becomes not active when: v The application requester detects the first active SQL program for the process has ended and the following are all true: There are no pending SQL changes There are no connections using protected connections A SET TRANSACTION statement is not active No programs that were precompiled with CLOSQLCSR(*ENDJOB) were run. If there are pending changes, protected connections, or an active SET TRANSACTION statement, SQL is placed in the exited state. If programs precompiled with CLOSQLCSR(*ENDJOB) were run, SQL will remain active for the default activation group until the job ends. v At the end of a unit of work if SQL is in the exited state. This occurs when you issue a COMMIT or ROLLBACK command outside of an SQL program. v At the end of a job.

Implicit connection management for nondefault activation groups


The application requester can implicitly connect to an application server. Implicit SQL connection occurs when the application requester detects that the first SQL statement issued for the activation group is not a CONNECT statement with parameters. For a distributed program, the implicit SQL connection is made to the relational database specified on the RDB parameter. For a nondistributed program, the implicit SQL connection is made to the local relational database. Implicit disconnect can occur at the following times in a process: v When the activation group ends, if commitment control is not active, activation group level commitment control is active, or the job level commitment definition is at a unit of work boundary. If the job level commitment definition is active and not at a unit of work boundary, SQL is placed in the exited state. v If SQL is in the exited state, when the job level commitment definition is committed or rolled back. v At the end of a job.

Distributed support
DB2 UDB for AS/400 supports two levels of distributed relational database: v Remote unit of work (RUW) Remote unit of work is where the preparation and running of SQL statements occurs at only one application server during a unit of work. An activation group with an application process at an application requester can connect to an application server and, within one or more units of work, run any number of

268

DB2 UDB for AS/400 SQL Programming Concepts V4R5

static or dynamic SQL statements that refer to objects on the application server. Remote unit of work is also referred to as DRDA level 1. v Distributed unit of work (DUW) Distributed unit of work is where the preparation and running of SQL statements can occur at multiple applications servers during a unit of work. However, a single SQL statement can only refer to objects located at a single application server. Distributed unit of work is also referred to as DRDA level 2. Distributed unit of work allows: Update access to multiple application servers in one logical unit of work or Update access to a single application server with read access to multiple application servers, in one logical unit of work. Whether multiple application servers can be updated in a unit of work is dependent on the existence of a sync point manager at the application requester, sync point managers at the application servers, and two-phase commit protocol support between the application requester and the application servers. The sync point manager is a system component that coordinates commit and rollback operations among the participants in the two-phase commit protocol. When running distributed updates, the sync point managers on the different systems cooperate to ensure that resources reach a consistent state. The protocols and flows used by sync point managers are also referred to as two-phase commit protocols. If two-phase commit protocols will be used, the connection is a protected resource; otherwise the connection is an unprotected resource. The type of data transport protocols used between systems affects whether the network connection is protected or unprotected. In OS/400 V4R2, TCP/IP connections are always unprotected; thus they can participate in a distributed unit of work in only a limited way. For example, if the first connection made from the program is to an AS/400 over TCP/IP, updates can be performed over it, but any subsequent connections, even over APPC, will be read only. Note that when using Interactive SQL, the first SQL connection is to the local system. Therefore in order to make updates to a remote system using TCP/IP, you must do a RELEASE ALL followed by a COMMIT to end all SQL connections before doing the CONNECT TO remote-tcp-system.

Determining connection type


When a remote connection is established it will use either an unprotected or protected network connection. With regards to committable updates, this SQL connection may be read-only, updateable, or unknown whether it is updateable when the connection is established. A committable update is any insert, delete, update, or DDL statement that is run under commitment control. If the connection is read-only, changes using COMMIT(*NONE) can still be run. After a CONNECT or SET CONNECTION, SQLERRD(4) of the SQLCA indicates the type of connection. SQLERRD(4) will also indicate if the connection uses a unprotected or protected network connection. Specific values are:

Chapter 17. Distributed Relational Database Function

269

1. Committable updates can be performed on the connection. The connection is unprotected. This will occur when: v The connection is established using remote unit of work (RDBCNNMTH(*RUW)). This also includes local connections and application requester driver (ARD) connections using remote unit of work. v If the connection is established using distributed unit of work (RDBCNNMTH(*DUW)) then all the following are true: The connection is not local. The application server does not support distributed unit of work. For example, a DB2 UDB for AS/400 application server with a release of OS/400 prior to Version 3 Release 1. The commitment control level of the program issuing the connect is not *NONE. Either no connections to other application servers (including local) exist that can perform committable updates or all connections are read-only connections to application servers that do not support distributed unit of work. There are no open updateable local files under commitment control for the commitment definition. There are no open updateable DDM files that use a different connection under commitment control for the commitment definition. There are no API commitment control resources for the commitment definition. There are no protected connections registered for the commitment definition. If running with commitment control, SQL will register a one-phase updateable DRDA resource for remote connections or a two-phase updateable DRDA resource for local and ARD connections. 2. No committable updates can be performed on the connection. The connection is read-only. The network connection is unprotected. This will never occur for applications compiled with remote unit of work connection management (*RUW). For distributed unit of work applications, this will occur only when the following are true when the connection is established: v The connection is not local. v The application server does not support distributed unit of work v At least one of the following is true: The commitment control level of the program issuing the connect is *NONE. Another connection exists to an application server that does not support distributed unit-of-work and that application server can perform committable updates Another connection exists to an application server that supports distributed unit-of-work (including local). There are open updateable local files under commitment control for the commitment definition. There are open updateable DDM files that use a different connection under commitment control for the commitment definition.

270

DB2 UDB for AS/400 SQL Programming Concepts V4R5

There are no one-phase API commitment control resources for the commitment definition. There are protected connections registered for the commitment definition. If running with commitment control, SQL will register a one-phase read-only resource. 3. It is unknown if committable updates can be performed. The connection is protected. This will never occur for applications compiled with remote unit of work connection management (*RUW). For distributed unit of work applications, this will occur when all of the following are true when the connection is established: v The connection is not local. v The commitment control level of the program issuing the connect is not *NONE. v The application server supports both distributed unit of work and two-phase commit protocol (protected connections). If running with commitment control, SQL will register a two-phase undetermined resource. 4. It is unknown if committable updates can be performed. The connection is not protected. This will never occur for applications compiled with remote unit of work connection management (*RUW). For distributed unit of work, this will occur only when all of the following are true when the connection is established: v The connection is not local. v The application server supports distributed unit of work v Either the application server does not support two-phase commit protocols (protected connections) or the commitment control level of the program issuing the connect is *NONE. If running with commitment control, SQL will register a one-phase DRDA undetermined resource. 5. It is unknown if committable updates can be performed and the connection is a local connection using distributed unit of work or an ARD connection using distributed unit of work. If running with commitment control, SQL will register a two-phase DRDA undetermined resource. For more information on two-phase and one-phase resources, see the Backup and Recovery book. The following table summarizes the type of connection that will result for remote distributed unit of work connections. SQLERRD(4) is set on successful CONNECT and SET CONNECTION statements.

Chapter 17. Distributed Relational Database Function

271

Table 28. Summary of Connection Type Application Server Supports Two-phase Commit No No No No Yes Yes Yes Yes No No No No Yes Yes Yes Yes Application Server Supports Distributed Unit of Work No No Yes Yes No No Yes Yes No No Yes Yes No No Yes Yes Other Updateable One-phase Resource Registered No Yes No Yes No Yes No Yes No Yes No Yes No Yes No Yes

Connect under Commitment Control No No No No No No No No Yes Yes Yes Yes Yes Yes Yes Yes

SQLERRD(4) 2 2 4 4 2 2 4 4 1 2 4 4 N/A * N/A * 3 3

*DRDA does not allow protected connections to be used to application servers which only support remote unit of work (DRDA1). This includes all DB2 for AS/400 TCP/IP connections.

Connect and commitment control restrictions


There are some restrictions on when you can connect using commitment control. These restrictions also apply to attempting to run statements using commitment control but the connection was established using COMMIT(*NONE). If a two-phase undetermined or updateable resource is registered or a one-phase updateable resource is registered, another one-phase updateable resource cannot not be registered. Furthermore, when protected connections are inactive and the DDMCNV job attribute is *KEEP, these unused DDM connections will also cause the CONNECT statements in programs compiled with RUW connection management to fail. If running with RUW connection management and using the job-level commitment definition, then there are some restrictions. v If the job-level commitment definition is used by more than one activation group, all RUW connections must be to the local relational database. v If the connection is remote, only one activation group may use the job-level commitment definition for RUW connections.

272

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Determining connection status


The CONNECT statement without parameters can be used to determine if the current connection is updateable or read-only for the current unit of work. A value of 1 or 2 will be returned in SQLERRD(3). The value in SQLERRD(3) is determined as follows: 1. Committable updates can be performed on the connection for the unit of work. This will occur when one of the following is true: v SQLERRD(4) has a value of 1. v All of the following are true: SQLERRD(4) has a value of 3 or 5. No connection exists to an application server that does not support distributed unit of work which can perform committable updates. One of the following is true: - The first committable update is performed on a connection that uses a protected connection, is performed on the local database, or is performed on a connection to an ARD program. - There there are open updateable local files under commitment control. - There are open updateable DDM files that use protected connections. - There are two-phase API commitment control resources. - No committable updates have been made. v All of the following are true: SQLERRD(4) has a value of 4 No other connections exist to an application server that does not support distributed unit of work which can perform committable updates. The first committable update is performed on this connection or no committable updates have been made. There are no open updateable DDM files that use protected connections. There are no open updateable local files under commitment control. There are no two-phase API commitment control resources. 2. No committable updates can be performed on the connection for this unit of work. This will occur when one of the following is true: v SQLERRD(4) has a value of 2. v SQLERRD(4) has a value of 3 or 5 and one of the following is true: A connection exists to an updateable application server that only supports remote unit of work. The first committable update is performed on a connection that uses an unprotected connection. v SQLERRD(4) has a value of 4 and one of the following is true: A connection exists to an updateable application server that only supports remote unit of work. The first committable update was not performed on this connection. There are open updateable DDM files that use protected connections. There are open updateable local files under commitment control. There are two-phase API commitment control resources.

Chapter 17. Distributed Relational Database Function

273

This following table summarizes how SQLERRD(3) is determined based on the SQLERRD(4) value, if there is an updateable connection to an application server that only supports remote unit of work, and where the first committable update occurred.
Table 29. Summary of Determining SQLERRD(3) Values Connection Exists to Updateable Remote Unit of Work Application Server --Yes No No No No Yes No No No No Yes No No No No Where First Committable Update Occurred * ---no updates one-phase this connection two-phase -no updates one-phase this connection two-phase -no updates one-phase this connection two-phase

SQLERRD(4) 1 2 3 3 3 3 3 4 4 4 4 4 5 5 5 5 5

SQLERRD(3) 1 2 2 1 2 1 1 2 1 2 1 2 2 1 2 1 1

* The terms in this column are defined as: v No updates indicates no committable updates have been performed, no DDM files open for update using a protected connection, no local files are open for update, and no commitment control APIs are registered. v One-phase indicates the first committable update was performed using an unprotected connection or DDM files are open for update using unprotected connections. v Two-phase indicates a committable update was performed on a two-phase distributed-unit-of-work application server, DDM files are open for update using a protected connection, commitment control APIs are registered, or local files are open for update under commitment control.

When the value of SQLERRD(4) is 3, 4, or 5 (due to an ARD program) and the value of SQLERRD(3) is 2, if an attempt is made to perform a committable update over the connection, the unit of work will be placed in a rollback required state. If an unit of work is in a rollback required state, the only statement allowed is a ROLLBACK statement; all other statements will result in SQLCODE -918.

Distributed unit of work connection considerations


When connecting in a distributed unit of work application, there are many considerations. This section lists some design considerations. v If the unit of work will perform updates at more than one application server and commitment control will be used, all connections over which updates will be

274

DB2 UDB for AS/400 SQL Programming Concepts V4R5

done should be made using commitment control. If the connections are done not using commitment control and later committable updates are performed, read-only connections for the unit of work are likely to result. v Other non-SQL commit resources, such as local files, DDM files, and commitment control API resources, will affect the updateable and read-only status of a connection. v If connecting using commitment control to an application server that does not support distributed unit of work (for example, a V4R2 AS/400 using TCP/IP), that connection will be either updateable or read-only. If the connection is updateable it is the only updateable connection.

Ending connections
Because remote connections use resources, connections that are no longer going to be used should be ended as soon as possible. Connections can be ended implicitly or explicitly. For a description of when connections are implicitly ended see Implicit connection management for the default activation group on page 267 and Implicit connection management for nondefault activation groups on page 268. Connections can be explicitly ended by either the DISCONNECT statement or the RELEASE statement followed by a successful COMMIT. The DISCONNECT statement can only be used with connections that use unprotected connections or with local connections. The DISCONNECT statement will end the connection when the statement is run. The RELEASE statement can be used with either protected or unprotected connections. When the RELEASE statement is run, the connection is not ended but instead placed into the released state. A connection that is in the release stated can still be used. The connection is not ended until a successful COMMIT is run. A ROLLBACK or an unsuccessful COMMIT will not end a connection in the released state. When a remote SQL connection is established, a DDM network connection (APPC conversation or TCP/IP connection) is used. When the SQL connection is ended, the network connection may either be placed in the unused state or dropped. Whether a network connection is dropped or placed in the unused state depends on the DDMCNV job attribute. If the job attribute value is *KEEP and the connection is to another AS/400, the connection becomes unused. If the job attribute value is *DROP and the connection is to another AS/400, the connection is dropped. If the connection is to a non-AS/400, the connection is always dropped. *DROP is desirable in the following situations: v When the cost of maintaining the unused connection is high and the connection will not be used relatively soon. v When running with a mixture of programs, some compiled with RUW connection management and some programs compiled with DUW connection management. Attempts to run programs compiled with RUW connection management to remote locations will fail when protected connections exist. v When running with protected connections using either DDM or DRDA. Additional overhead is incurred on commits and rollbacks for unused protected connections. The Reclaim DDM connections (RCLDDMCNV) command may be used to end all unused connections.

Chapter 17. Distributed Relational Database Function

275

Distributed unit of work


Distributed unit of work (DUW) allows access to multiple application servers within the same unit of work. Each SQL statement can access only one application server. Using distributed unit of work allows changes at multiple applications servers to be committed or rolled back within a single unit of work.

Managing distributed unit of work connections


The CONNECT, SET CONNECTION, DISCONNECT, and RELEASE statements are used to manage connections in the DUW environment. A distributed unit of work CONNECT is run when the program is precompiled using RDBCNNMTH(*DUW), which is the default. This form of the CONNECT statement does not disconnect existing connections but instead places the previous connection in the dormant state. The relational database specified on the CONNECT statement becomes the current connection. The CONNECT statement can only be used to start new connections; if you want to switch between existing connections, the SET CONNECTION statement must be used. Because connections use system resources, connections should be ended when they are no longer needed. The RELEASE or DISCONNECT statement can be used to end connections. The RELEASE statement must be followed by a successful commit in order for the connections to end. The following is an example of a C program running in a DUW environment that uses commitment control.
.... EXEC SQL WHENEVER SQLERROR GO TO done; EXEC SQL WHENEVER NOT FOUND GO TO done; .... EXEC SQL DECLARE C1 CURSOR WITH HOLD FOR SELECT PARTNO, PRICE FROM PARTS WHERE SITES_UPDATED = 'N' FOR UPDATE OF SITES_UPDATED; /* Connect to the systems */ EXEC SQL CONNECT TO LOCALSYS; EXEC SQL CONNECT TO SYSB; EXEC SQL CONNECT TO SYSC; /* Make the local system the current connection */ EXEC SQL SET CONNECTION LOCALSYS; /* Open the cursor */ EXEC SQL OPEN C1; Figure 13. Example of Distributed Unit of Work Program (Part 1 of 4)

276

DB2 UDB for AS/400 SQL Programming Concepts V4R5

while (SQLCODE==0) { /* Fetch the first row */ EXEC SQL FETCH C1 INTO :partnumber,:price; /* Update the row which indicates that the updates have been propagated to the other sites */ EXEC SQL UPDATE PARTS SET SITES_UPDATED='Y' WHERE CURRENT OF C1; /* Check if the part data is on SYSB */ if ((partnumber > 10) && (partnumber < 100)) { /* Make SYSB the current connection and update the price */ EXEC SQL SET CONNECTION SYSB; EXEC SQL UPDATE PARTS SET PRICE=:price WHERE PARTNO=:partnumber; } Figure 13. Example of Distributed Unit of Work Program (Part 2 of 4)

} done:

/* Check if the part data is on SYSC */ if ((partnumber > 50) && (partnumber < 200)) { /* Make SYSC the current connection and update the price */ EXEC SQL SET CONNECTION SYSC; EXEC SQL UPDATE PARTS SET PRICE=:price WHERE PARTNO=:partnumber; } /* Commit the changes made at all 3 sites */ EXEC SQL COMMIT; /* Set the current connection to local so the next row can be fetched */ EXEC SQL SET CONNECTION LOCALSYS;

Figure 13. Example of Distributed Unit of Work Program (Part 3 of 4)

EXEC SQL WHENEVER SQLERROR /* Release the connections EXEC SQL RELEASE SYSB; EXEC SQL RELEASE SYSC; /* Close the cursor */ EXEC SQL CLOSE C1; /* Do another commit which The local connection is released. */ EXEC SQL COMMIT; ...

CONTINUE; that are no longer being used */

will end the released connections. still active because it was not

Figure 13. Example of Distributed Unit of Work Program (Part 4 of 4)

In this program, there are 3 application servers active: LOCALSYS which the local system, and 2 remote systems, SYSB and SYSC. SYSB and SYSC also support distributed unit of work and two-phase commit. Initially all connections are made active by using the CONNECT statement for each of the application servers involved in the transaction. When using DUW, a CONNECT statement does not disconnect the previous connection, but instead places the previous connection in
Chapter 17. Distributed Relational Database Function

277

the dormant state. After all the application servers, have been connected, the local connection is made the current connection using the SET CONNECTION statement. The cursor is then opened and the first row of data fetched. It is then determined at which application servers the data needs to be updated. If SYSB needs to be updated, then SYSB is made the current connection using the SET CONNECTION statement and the update is run. The same is done for SYSC. The changes are then committed. Because two-phase commit is being used, it is guaranteed that the changes are committed at the local system and the two remote systems. Because the cursor was declared WITH HOLD, it remains open after the commit. The current connection is then changed to the local system so that the next row of data can be fetched. This set of fetches, updates, and commits is repeated until all the data has been processed. After all the data has been fetched, the connections for both remote systems are released. They can not be disconnected because they use protected connections. After the connections are released, a commit is issued to end the connections. The local system is still connected and continues processing.

Checking connection status


If running in an environment where it is possible to have read-only connections, the status of the connection should be checked before doing committable updates. This will prevent the unit of work from entering the rollback required state. The following COBOL example shows how to check the connection status.
... EXEC SQL SET CONNECTION SYS5 END-EXEC. ... * Check if the connection is updateable. EXEC SQL CONNECT END-EXEC. * If connection is updateable, update sales information otherwise * inform the user. IF SQLERRD(3) = 1 THEN EXEC SQL INSERT INTO SALES_TABLE VALUES(:SALES-DATA) END-EXEC ELSE DISPLAY 'Unable to update sales information at this time'. ... Figure 14. Example of Checking Connection Status

Cursors and prepared statements


Cursors and prepared statements are scoped to the compilation unit and also to the connection. Scoping to the compilation unit means that a program called from another separately compiled program cannot use a cursor or prepared statement that was opened or prepared by the calling program. Scoping to the connection means that each connection within a program can have its own separate instance of a cursor or prepared statement. The following distributed unit of work example shows how the same cursor name is opened in two different connections, resulting in two instances of cursor C1.

278

DB2 UDB for AS/400 SQL Programming Concepts V4R5

..... EXEC SQL DECLARE C1 CURSOR FOR SELECT * FROM CORPDATA.EMPLOYEE; /* Connect to local and open C1 */ EXEC SQL CONNECT TO LOCALSYS; EXEC SQL OPEN C1; /* Connect to the remote system and open C1 */ EXEC SQL CONNECT TO SYSA; EXEC SQL OPEN C1; /* Keep processing until done */ while (NOT_DONE) { /* Fetch a row of data from the local system */ EXEC SQL SET CONNECTION LOCALSYS; EXEC SQL FETCH C1 INTO :local_emp_struct; /* Fetch a row of data from the remote system */ EXEC SQL SET CONNECTION SYSA; EXEC SQL FETCH C1 INTO :rmt_emp_struct; /* Process the data */ ..... } /* Close the cursor on the remote system */ EXEC SQL CLOSE C1; /* Close the cursor on the local system */ EXEC SQL SET CONNECTION LOCALSYS; EXEC SQL CLOSE C1; ..... Figure 15. Example of Cursors in a DUW program

Application requester driver programs


To complement database access provided by products that implement DRDA, DB2 UDB for AS/400 provides an interface for writing exit programs on a DB2 UDB for AS/400 application requester to process SQL requests. Such an exit program is called an application requester driver. The AS/400 calls the ARD program during the following operations: v During package creation performed using the CRTSQLPKG or CRTSQLxxx commands, when the relational database (RDB) parameter matches the RDB name corresponding to the ARD program. v Processing of SQL statements when the current connection is to an RDB name corresponding to the ARD program. These calls allow the ARD program to pass the SQL statements and information about the statements to a remote relational database and return results back to the system. The system then returns the results to the application or the user. Access to relational databases accessed by ARD programs appears like access to DRDA application servers in the unlike environment. For more information about application requester driver programs, see the OS/400 File APIs.

Problem handling
The primary strategy for capturing and reporting error information for the AS/400 distributed database function is called first failure data capture (FFDC). The purpose of FFDC support is to provide accurate information on errors detected in the DDM components of the OS/400 system from which an APAR 9 can be created.

Chapter 17. Distributed Relational Database Function

279

By means of this function, key structures and the DDM data stream are automatically dumped to a spool file. The first 1024 bytes of the error information are also logged in the system error log. This automatic dumping of error information on the first occurrence of an error means that the failure should not have to be recreated to be reported by the customer. FFDC is active in both the application requester and application server functions of the OS/400 DDM component. However, for the FFDC data to be logged, the system value QSFWERRLOG must be set to *LOG. Note: Not all negative SQLCODEs are dumped; only those that can be used to produce an APAR are dumped. For more information on handling problems on distributed relational database operations, see the Distributed Database Problem Determination Guide When an SQL error is detected, an SQLCODE with a corresponding SQLSTATE is returned in the SQLCA. For more information on these codes, see Appendix B. SQLCODEs and SQLSTATEs.

9. Authorized Program Analysis Report (APAR).

280

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Appendix A. DB2 UDB for AS/400 Sample Tables


This appendix contains the sample tables referred to and used in this guide and the SQL Reference book. Along with the tables are the SQL statements for creating the tables. For detailed information on creating tables, see Creating and using a table on page 14. As a group, the EMPLOYEE, DEPARTMENT, PROJECT, and EMP_ACT tables include information that describes employees, departments, projects, and activities. This information makes up a sample application demonstrating some of the features of the DB2 UDB Query Manager and SQL Development Kit licensed program. The tables are in a collection named CORPDATA (for corporate data). The tables are: v Department table (CORPDATA.DEPARTMENT) v Employee table (CORPDATA.EMPLOYEE) v Employee to project activity table (CORPDATA.EMP_ACT) v Project table (CORPDATA.PROJECT) v Class Schedule table (CL_SCHED) v In Tray table (IN_TRAY) Notes: 1. In these sample tables, a question mark (?) indicates a null value. 2. The IN_TRAY and CL_SCHED tables are used to illustrate examples that include dates and times given in the SQL Reference book. They are not related to the examples in the CORPDATA collection.

Department Table (CORPDATA.DEPARTMENT)


The department table describes each department in the enterprise and identifies its manager and the department it reports to. The department table is created with the following CREATE TABLE statement:
CREATE TABLE CORPDATA.DEPARTMENT (DEPTNO CHAR(3) DEPTNAME VARCHAR(29) MGRNO CHAR(6) ADMRDEPT CHAR(3) NOT NULL, NOT NULL, , NOT NULL )

The following table shows the content of the columns:


Table 30. Columns of the Department Table Column Name DEPTNO DEPTNAME MGRNO ADMRDEPT Description Department number or ID. A name describing the general activities of the department. Employee number (EMPNO) of the department manager. The department (DEPTNO) to which this department reports; the department at the highest level reports to itself.

Copyright IBM Corp. 2000

281

DEPARTMENT
DEPTNO A00 B01 C01 D01 D11 D21 E01 E11 E21 DEPTNAME SPIFFY COMPUTER SERVICE DIV. PLANNING INFORMATION CENTER DEVELOPMENT CENTER MANUFACTURING SYSTEMS ADMINISTRATION SYSTEMS SUPPORT SERVICES OPERATIONS SOFTWARE SUPPORT MGRNO 000010 000020 000030 ? 000060 000070 000050 000090 000100 ADMRDEPT A00 A00 A00 A00 D01 D01 A00 E01 E01

Employee Table (CORPDATA.EMPLOYEE)


The employee table identifies all employees by an employee number and lists basic personnel information. The employee table is created with the following CREATE TABLE statement:
CREATE TABLE CORPDATA.EMPLOYEE (EMPNO CHAR(6) FIRSTNME VARCHAR(12) MIDINIT CHAR(1) LASTNAME VARCHAR(15) WORKDEPT CHAR(3) PHONENO CHAR(4) HIREDATE DATE JOB CHAR(8) EDLEVEL SMALLINT SEX CHAR(1) BIRTHDATE DATE SALARY DECIMAL(9,2) BONUS DECIMAL(9,2) COMM DECIMAL(9,2) NOT NULL, NOT NULL, NOT NULL, NOT NULL, , , , , NOT NULL, , , , , )

The table below shows the content of the columns.


Column Name EMPNO FIRSTNME MIDINIT LASTNAME WORKDEPT PHONENO HIREDATE JOB EDLEVEL SEX BIRTHDATE SALARY Description Employee number First name of employee Middle initial of employee Last name of employee ID of department in which the employee works Employee telephone number Date of hire Job held by the employee Number of years of formal education Sex of the employee (M or F) Date of birth Yearly salary in dollars

282

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Column Name BONUS COMM

Description Yearly bonus in dollars Yearly commission in dollars

EMP NO 000010 000020 000030 000050 000060 000070 000090 000100 000110 000120 000130 000140 000150 000160 000170 000180 000190 000200 000210 000220 000230 000240 000250 000260 000270 000280 000290 000300 000310 000320 000330 000340

FIRST NAME CHRISTINE MICHAEL SALLY JOHN IRVING EVA EILEEN THEODORE VINCENZO SEAN DOLORES HEATHER BRUCE ELIZABETH MASATOSHI MARILYN JAMES DAVID WILLIAM JENNIFER JAMES SALVATORE DANIEL SYBIL MARIA ETHEL JOHN PHILIP MAUDE RAMLAL WING JASON

MID INIT I L A B F D W Q G M A R J S H T K J M S P L R R X F V R

LASTNAME HAAS THOMPSON KWAN GEYER STERN PULASKI HENDERSON SPENSER LUCCHESSI O'CONNELL QUINTANA NICHOLLS ADAMSON PIANKA YOSHIMURA SCOUTTEN WALKER BROWN JONES LUTZ JEFFERSON MARINO SMITH JOHNSON PEREZ SCHNEIDER PARKER SMITH SETRIGHT MEHTA LEE GOUNOT

WORK DEPT A00 B01 C01 E01 D11 D21 E11 E21 A00 A00 C01 C01 D11 D11 D11 D11 D11 D11 D11 D11 D21 D21 D21 D21 D21 E11 E11 E11 E11 E21 E21 E21

PHONE NO 3978 3476 4738 6789 6423 7831 5498 0972 3490 2167 4578 1793 4510 3782 2890 1682 2986 4501 0942 0672 2094 3780 0961 8953 9001 8997 4502 2095 3332 9990 2103 5698

HIRE DATE 1965-01-01 1973-10-10 1975-04-05 1949-08-17 1973-09-14 1980-09-30 1970-08-15 1980-06-19 1958-05-16 1963-12-05 1971-07-28 1976-12-15 1972-02-12 1977-10-11 1978-09-15 1973-07-07 1974-07-26 1966-03-03 1979-04-11 1968-08-29 1966-11-21 1979-12-05 1969-10-30 1975-09-11 1980-09-30 1967-03-24 1980-05-30 1972-06-19 1964-09-12 1965-07-07 1976-02-23 1947-05-05

JOB PRES MANAGER MANAGER MANAGER MANAGER MANAGER MANAGER MANAGER SALESREP CLERK ANALYST ANALYST DESIGNER DESIGNER DESIGNER DESIGNER DESIGNER DESIGNER DESIGNER DESIGNER CLERK CLERK CLERK CLERK CLERK OPERATOR OPERATOR OPERATOR OPERATOR FILEREP FILEREP FILEREP

ED LEVEL 18 18 20 16 16 16 16 14 19 14 16 18 16 17 16 17 16 16 17 18 14 17 15 16 15 17 12 14 12 16 14 16

SEX F M F M M F F M M M F F M F M F M M M F M M M F F F M M F M M M

BIRTH DATE 1933-08-24 1948-02-02 1941-05-11 1925-09-15 1945-07-07 1953-05-26 1941-05-15 1956-12-18 1929-11-05 1942-10-18 1925-09-15 1946-01-19 1947-05-17 1955-04-12 1951-01-05 1949-02-21 1952-06-25 1941-05-29 1953-02-23 1948-03-19 1935-05-30 1954-03-31 1939-11-12 1936-10-05 1953-05-26 1936-03-28 1946-07-09 1936-10-27 1931-04-21 1932-08-11 1941-07-18 1926-05-17

SALARY 52750 41250 38250 40175 32250 36170 29750 26150 46500 29250 23800 28420 25280 22250 24680 21340 20450 27740 18270 29840 22180 28760 19180 17250 27380 26250 15340 17750 15900 19950 25370 23840

BONUS 1000 800 800 800 500 700 600 500 900 600 500 600 500 400 500 500 400 600 400 600 400 600 400 300 500 500 300 400 300 400 500 500

COMM 4220 3300 3060 3214 2580 2893 2380 2092 3720 2340 1904 2274 2022 1780 1974 1707 1636 2217 1462 2387 1774 2301 1534 1380 2190 2100 1227 1420 1272 1596 2030 1907

Employee to Project Activity Table (CORPDATA.EMP_ACT)


The employee to project activity table identifies the employee who performs each activity listed for each project. The employees level of involvement (full-time or part-time) and schedule for activity are also in the table. The employee to project activity table is created with the following CREATE TABLE statement:
CREATE TABLE CORPDATA.EMP_ACT (EMPNO CHAR(6) PROJNO CHAR(6) ACTNO SMALLINT EMPTIME DECIMAL(5,2) EMSTDATE DATE EMENDATE DATE NOT NULL, NOT NULL, NOT NULL, , , )

The table below shows the content of the columns.


Table 31. Columns of the Employee to Project Activity Table Column Name EMPNO PROJNO ACTNO EMPTIME Description Employee ID number PROJNO of the project to which the employee is assigned ID of an activity within a project to which an employee is assigned A proportion of the employees full time (between 0.00 and 1.00) to be spent on the project from EMSTDATE to EMENDATE Start date of the activity
Appendix A. DB2 UDB for AS/400 Sample Tables

EMSTDATE

283

Table 31. Columns of the Employee to Project Activity Table (continued) Column Name EMENDATE Description Completion date of the activity

EMP_ACT
EMPNO 000010 000070 000230 000230 000230 000230 000230 000240 000240 000250 000250 000250 000250 000250 000250 000250 000250 000250 000250 000260 000260 000260 000260 000260 000260 000260 000270 000270 000270 000270 000270 000270 000270 000030 000130 000130 PROJNO AD3100 AD3110 AD3111 AD3111 AD3111 AD3111 AD3111 AD3111 AD3111 AD3112 AD3112 AD3112 AD3112 AD3112 AD3112 AD3112 AD3112 AD3112 AD3112 AD3113 AD3113 AD3113 AD3113 AD3113 AD3113 AD3113 AD3113 AD3113 AD3113 AD3113 AD3113 AD3113 AD3113 IF1000 IF1000 IF1000 ACTNO 10 10 60 60 70 80 180 70 80 60 60 60 60 70 70 70 80 80 180 70 70 80 80 180 180 180 60 60 60 70 70 80 80 10 90 100 EMPTIME .50 1.00 1.00 .50 .50 .50 1.00 1.00 1.00 1.00 .50 .50 1.00 .50 1.00 .25 .25 .50 .50 .50 1.00 1.00 .50 .50 1.00 .50 .50 1.00 .25 .75 1.00 1.00 .50 .50 1.00 .50 EMSTDATE 1982-01-01 1982-01-01 1982-01-01 1982-03-15 1982-03-15 1982-04-15 1982-10-15 1982-02-15 1982-09-15 1982-01-01 1982-02-01 1982-12-01 1983-01-01 1982-02-01 1982-03-15 1982-08-15 1982-08-15 1982-10-15 1982-08-15 1982-06-15 1982-07-01 1982-01-01 1982-03-01 1982-03-01 1982-04-15 1982-06-01 1982-03-01 1982-04-01 1982-09-01 1982-09-01 1982-10-15 1982-01-01 1982-03-01 1982-06-01 1982-01-01 1982-10-01 EMENDATE 1982-07-01 1983-02-01 1982-03-15 1982-04-15 1982-10-15 1982-10-15 1983-01-01 1982-09-15 1983-01-01 1982-02-01 1982-03-15 1983-01-01 1983-02-01 1982-03-15 1982-08-15 1982-10-15 1982-10-15 1982-12-01 1983-01-01 1982-07-01 1983-02-01 1982-03-01 1982-04-15 1982-04-15 1982-06-01 1982-07-01 1982-04-01 1982-09-01 1982-10-15 1982-10-15 1983-02-01 1982-03-01 1982-04-01 1983-01-01 1982-10-01 1983-01-01

284

DB2 UDB for AS/400 SQL Programming Concepts V4R5

EMPNO 000140 000030 000140 000140 000140 000140 000010 000110 000010 000200 000200 000220 000150 000150 000170 000170 000190 000190 000160 000170 000180 000210 000210 000050 000090 000280 000290 000300 000310 000050 000100 000320 000320 000330 000330 000340 000340 000020

PROJNO IF1000 IF2000 IF2000 IF2000 IF2000 IF2000 MA2100 MA2100 MA2110 MA2111 MA2111 MA2111 MA2112 MA2112 MA2112 MA2112 MA2112 MA2112 MA2113 MA2113 MA2113 MA2113 MA2113 OP1000 OP1010 OP1010 OP1010 OP1010 OP1010 OP2010 OP2010 OP2011 OP2011 OP2012 OP2012 OP2013 OP2013 PL2100

ACTNO 90 10 100 100 110 110 10 20 10 50 60 40 60 180 60 70 70 80 60 80 70 80 180 10 10 130 130 130 130 10 10 140 150 140 160 140 170 30

EMPTIME .50 .50 1.00 .50 .50 .50 .50 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 .50 .50 .25 1.00 1.00 1.00 1.00 1.00 .75 1.00 .75 .25 .25 .75 .50 .50 1.00

EMSTDATE 1982-10-01 1982-01-01 1982-01-01 1982-03-01 1982-03-01 1982-10-01 1982-01-01 1982-01-01 1982-01-01 1982-01-01 1982-06-15 1982-01-01 1982-01-01 1982-07-15 1982-01-01 1982-06-01 1982-02-01 1982-10-01 1982-07-15 1982-01-01 1982-04-01 1982-10-01 1982-10-01 1982-01-01 1982-01-01 1982-01-01 1982-01-01 1982-01-01 1982-01-01 1982-01-01 1982-01-01 1982-01-01 1982-01-01 1982-01-01 1982-01-01 1982-01-01 1982-01-01 1982-01-01

EMENDATE 1983-01-01 1983-01-01 1982-03-01 1982-07-01 1982-07-01 1983-01-01 1982-11-01 1982-03-01 1983-02-01 1982-06-15 1983-02-01 1983-02-01 1982-07-15 1983-02-01 1983-06-01 1983-02-01 1982-10-01 1983-10-01 1983-02-01 1983-02-01 1982-06-15 1983-02-01 1983-02-01 1983-02-01 1983-02-01 1983-02-01 1983-02-01 1983-02-01 1983-02-01 1983-02-01 1983-02-01 1983-02-01 1983-02-01 1983-02-01 1983-02-01 1983-02-01 1983-02-01 1982-09-15

Appendix A. DB2 UDB for AS/400 Sample Tables

285

Project Table (CORPDATA.PROJECT)


The project table describes each project that the business is currently undertaking. Data contained in each row include the project number, name, person responsible, and schedule dates. The project table is created with the following CREATE TABLE statement:
CREATE TABLE CORPDATA.PROJECT (PROJNO CHAR(6) PROJNAME VARCHAR(24) DEPTNO CHAR(3) RESPEMP CHAR(6) PRSTAFF DECIMAL(5,2) PRSTDATE DATE PRENDATE DATE MAJPROJ CHAR(6) NOT NOT NOT NOT NULL, NULL, NULL, NULL, , , , )

The table below shows the contents of the columns:


Column Name PROJNO PROJNAME DEPTNO RESPEMP PRSTAFF PRSTDATE PRENDATE MAJPROJ Description Project number Project name Department number of the department responsible for the project Employee number of the person responsible for the project Estimated mean staffing Estimated start date of the project Estimated end date of the project Controlling project number for sub projects

PROJECT
PROJNO AD3100 AD3110 AD3111 AD3112 AD3113 IF1000 IF2000 MA2100 MA2110 MA2111 PROJNAME DEPTNO RESPEMP 000010 000070 000230 000250 000270 000030 000030 000010 000060 000220 PRSTAFF 6.5 6 2 1 2 2 1 12 9 2 PRSTDATE 1982-01-01 1982-01-01 1982-01-01 1982-01-01 1982-01-01 1982-01-01 1982-01-01 1982-01-01 1982-01-01 1982-01-01 PRENDATE MAJPROJ 1983-02-01 1983-02-01 1983-02-01 1983-02-01 1983-02-01 1983-02-01 1983-02-01 1983-02-01 1983-02-01 1982-12-01 ? AD3100 AD3110 AD3110 AD3110 ? ? ? MA2100 MA2110 ADMIN SERVICES D01 GENERAL ADMIN SYSTEMS PAYROLL PROGRAMMING PERSONNEL PROGRAMMING ACCOUNT PROGRAMMING D21 D21 D21 D21

QUERY SERVICES C01 USER EDUCATION WELD LINE AUTOMATION WL PROGRAMMING W L PROGRAM DESIGN C01 D01 D11 D11

286

DB2 UDB for AS/400 SQL Programming Concepts V4R5

PROJNO MA2112 MA2113 OP1000 OP1010 OP2000 OP2010 OP2011 OP2012 OP2013 PL2100

PROJNAME W L ROBOT DESIGN W L PROD CONT PROGS OPERATION SUPPORT OPERATION GEN SYSTEMS SERVICES SYSTEMS SUPPORT SCP SYSTEMS SUPPORT APPLICATIONS SUPPORT DB/DC SUPPORT WELD LINE PLANNING

DEPTNO D11 D11 E01 E11 E01 E21 E21 E21 E21 B01

RESPEMP 000150 000160 000050 000090 000050 000100 000320 000330 000340 000020

PRSTAFF 3 3 6 5 5 4 1 1 1 1

PRSTDATE 1982-01-01 1982-02-15 1982-01-01 1982-01-01 1982-01-01 1982-01-01 1982-01-01 1982-01-01 1982-01-01 1982-01-01

PRENDATE MAJPROJ 1982-12-01 1982-12-01 1983-02-01 1983-02-01 1983-02-01 1983-02-01 1983-02-01 1983-02-01 1983-02-01 1982-09-15 MA2110 MA2110 ? OP1000 ? OP2000 OP2010 OP2010 OP2010 MA2100

Class Schedule Table (CL_SCHED)


The class schedule table describes: each class, the start time for the class, the end time for the class, and the class code. The class schedule table is created with the following CREATE TABLE statement:
CREATE TABLE CL_SCHED (CLASS_CODE DAY STARTING ENDING CHAR(7), SMALLINT, TIME, TIME)

The table below gives the contents of the columns.


Column Name CLASS_CODE DAY STARTING ENDING Description Class code (room:teacher) Day number of 4 day schedule Class start time Class end time

Note: This table has no data.

In Tray Table (IN_TRAY)


The in tray table describes an electronic in-basket containing: a timestamp from when the message was received, the user ID of the person sending the message, and the message itself. The in tray table is created with the following CREATE TABLE statement:

Appendix A. DB2 UDB for AS/400 Sample Tables

287

CREATE TABLE IN_TRAY (RECEIVED SOURCE SUBJECT NOTE_TEXT

TIMESTAMP, CHAR(8), CHAR(64), VARCHAR(3000))

The table below gives the contents of the columns.


Column Name RECEIVED SOURCE SUBJECT NOTE_TEXT Description Date and time received User ID of person sending the note Brief description of the note The note

Note: This table has no data.

288

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Appendix B. SQLCODEs and SQLSTATEs


SQL returns error codes to the application program when an error occurs. This appendix lists SQLCODEs and their associated SQLSTATEs. Detailed descriptions of all DB2 UDB for AS/400 messages, including SQLCODEs, are available on-line and can be displayed and printed from the Display Message Description display. You can access this display by using the CL command Display Message Description (DSPMSGD). SQLCODEs are returned in the SQLCA structure. SQLSTATE is an additional return code that provides application programs with common return codes for common error conditions found among the IBM relational database systems. SQLSTATEs are particularly useful when handling errors in distributed SQL applications. Every SQLCODE has a corresponding message in message file QSQLMSG in library QSYS. The message ID for any SQLCODE is constructed by appending the absolute value (5 digits) of the SQLCODE to SQ and changing the third character to 'L' if the third character is a 0. For example, if the SQLCODE is 30070, the message ID is SQ30070. If SQL encounters an error while processing the statement, the first characters of the SQLSTATE are not '00', '01' or '02', and the SQLCODE is a negative number. If SQL encounters a warning but valid condition while processing your statement, the SQLCODE is a positive number and bytes one and two of the SQLSTATE are '01'. If your SQL statement is processed without encountering an error or warning condition, the SQLCODE returned is 0 and SQLSTATE is '00000'. If you wish, you can quickly reference Positive SQLCODEs on page 291 or Negative SQLCODEs on page 293. When running in debug mode, SQL places a message corresponding to the SQLCODE in the job log for each SQL statement run. If you are not running in debug mode and get a negative SQLCODE, you will get a message in the job log also. An application can also send the SQL message corresponding to any SQLCODE to the job log by specifying the message ID and the replacement text on the CL commands Retrieve Message (RTVMSG), Send Program Message (SNDPGMMSG), and Send User Message (SNDUSRMSG). SQLSTATE values consist of a two-character class code, followed by a three-character code. The class codes conform to ISO/ANSI standards. The class codes are: v 00 Unqualified Successful Completion v 01 Warning v 02 No Data v 03 SQL Statement Not Yet Complete v 07 Dynamic SQL Error v 08 Connection Exception v 09 Triggered Action Exception
Copyright IBM Corp. 2000

289

v v v v v v v v v v v v v v v v v v

0A Feature Not Supported 09 Invalid Token 20 Case Not Found for CASE Statement 21 Cardinality Violation 22 Data Exception 23 Constraint Violation 24 Invalid Cursor State 25 Invalid Transaction State 26 Invalid SQL Statement Identifier 27 Triggered Data Change Violation 28 Invalid Authorization Specification 2B Dependent Privilege Descriptors Still Exist 2C Invalid Character Set Name 2D Invalid Transaction Termination 2E Invalid Connection Name 2F SQL Function Exception 33 Invalid SQL Descriptor Name 34 Invalid Cursor Name

v 35 Invalid Condition Number v 38 External Function Exception v 39 External Function Call Exception v v v v v v v v v v v v 3C Ambiguous Cursor Name 3D Invalid Catalog Name 3F Invalid Collection (Schema) Name 40 Transaction Rollback 42 44 51 53 54 55 56 57 Syntax Error and Access Rule Violation WITH CHECK OPTION Violation Invalid Application State Invalid Operand or Inconsistent Specification SQL or Product Limit Exceeded Object Not in Prerequisite State Miscellaneous SQL or Product Error Resource Not Available or Operator Intervention

v 58 System Error For a list of SQLSTATEs that are used by the DB2 family of products, see IBM SQL Reference, Version 2, SC26-8416. Also available on CD-ROM as a part of the Transaction Processing Collection Kit CD-ROM, SK2T-0730-11. When an SQLSTATE other than '00000' is returned from a non-DB2 UDB for AS/400 application server, DB2 UDB for AS/400 attempts to map the SQLSTATE to a DB2 UDB for AS/400 SQLCODE and message: v If the SQLSTATE is not recognized by DB2 UDB for AS/400, the common message for the class is issued.

290

DB2 UDB for AS/400 SQL Programming Concepts V4R5

v If the SQLSTATE and SQLCODE correspond to a single DB2 UDB for AS/400 SQLCODE, DB2 UDB for AS/400 attempts to convert the tokens returned in SQLERRM to the replacement data expected by the SQL message. If an error occurs while converting the tokens: The SQLCA is not changed. A common message for the class code of the SQLSTATE is issued.

SQLCODE and SQLSTATE Descriptions


In the following brief descriptions of the SQLCODEs (and their associated SQLSTATEs) message data fields are identified by an ampersand (&); and a number (for example, &1); The replacement text for these fields is stored in SQLERRM in the SQLCA. More detailed cause and recovery information for any SQLCODE can be found by using the Display Message Description (DSPMSGD) CL command.

Positive SQLCODEs
N/A SQLCODE 0 SQL0088 SQLCODE +88 SQLSTATE 01504

Explanation: The SQL statement has run successfully. If SQLWARN0 is blank, and SQLSTATE is '00000', the statement was run successfully. Otherwise, a warning condition exists. Check the other warning indicators or SQLSTATE to determine the particular warning condition. For example, if SQLWARN1 is not blank, a string has been truncated. The following warnings have an SQLCODE of zero: v SQLWARN1 SQLSTATE 01004 Explanation: The value of a string column was truncated when assigned to a host variable. v SQLWARN2 SQLSTATE 01003 Explanation: Null values were eliminated from the argument of a column function. v SQLWARN3 SQLSTATE 01503 Explanation: The number of result columns is larger than the number of host variables provided. v SQLWARN4 SQLSTATE 01504 Explanation: The UPDATE or DELETE statement does not include a WHERE clause. v SQLWARN6 SQLSTATE 01506 Explanation: An adjustment was made to a DATE or TIMESTAMP value to correct a date the was not valid. The date resulted from an arithmetic operation. SQL0012 SQLCODE +12 SQLSTATE 01545

Explanation: No WHERE on UPDATE or DELETE. SQL0100 SQLCODE +100 SQLSTATE 02000

Explanation: Row not found for &1. SQL0114 SQLCODE +114 SQLSTATE 01536

Explanation: Relational database &1 not the same as current server &2. SQL0138 SQLCODE +138 SQLSTATE 01544

Explanation: Argument &1 of SUBSTR function not valid. SQL0177 SQLCODE +177 SQLSTATE 01009

Explanation: CHECK condition text too long. SQL0178 SQLCODE +178 SQLSTATE 0100A

Explanation: Query expression text for view &1 in &2 too long. SQL0180 SQLCODE +180 SQLSTATE 01534

Explanation: Syntax of date, time, or timestamp value not valid. SQL0181 SQLCODE +181 SQLSTATE 01534

Explanation: Correlation without qualification occurred for column &1 to table &2. SQL0030 SQLCODE +30 SQLSTATE 01503

Explanation: Value in date, time, or timestamp string not valid.

Explanation: Number of INTO host-variable incorrect.

Appendix B. SQLCODEs and SQLSTATEs

291

SQL0183

SQLCODE +183

SQLSTATE 01535

SQL0445

SQLCODE +445

SQLSTATE 01004

Explanation: The result of a date or timestamp expression not valid. SQL0191 SQLCODE +191 SQLSTATE 01547

Explanation: Value of parameter &4 in procedure &1 in &2 too long. SQL0460 SQLCODE +460 SQLSTATE 01593

Explanation: MIXED data not properly formed. SQL0204 SQLCODE +204 SQLSTATE 01532

Explanation: Truncation of data may have occurred for ALTER TABLE in &1 of &2. SQL0462 SQLCODE +462 SQLSTATE 01Hxx

Explanation: Object &1 in &2 type *&3 not found. SQL0237 SQLCODE +237 SQLSTATE 01005

Explanation: Procedure or user-defined function &1 in &2 returned a warning SQLSTATE. SQL0551 SQLCODE +551 SQLSTATE 01548

Explanation: Not enough SQLVAR entries were provided in the SQLDA. SQL0239 SQLCODE +239 SQLSTATE 01005

Explanation: Not authorized to object &1 in &2 type *&3. SQL0552 SQLCODE +552 SQLSTATE 01542

Explanation: Not enough SQLVAR entries were provided in the SQLDA. SQL0304 SQLCODE +304 01547, 01565 SQLSTATE 01515,

Explanation: Not authorized to &1. SQL0569 SQLCODE +569 SQLSTATE 01006

Explanation: Conversion error in assignment to host variable &2. SQL0326 SQLCODE +326 SQLSTATE 01557

Explanation: Not all requested privileges revoked from object &1 in &2 type &3. SQL0570 SQLCODE +570 SQLSTATE 01007

Explanation: Too many host variables specified. SQL0331 SQLCODE +331 SQLSTATE 01520

Explanation: Not all requested privileges to object &1 in &2 type &3 granted. SQL0595 SQLCODE +595 SQLSTATE 01526

Explanation: Characters conversion cannot be performed. SQL0335 SQLCODE +335 SQLSTATE 01517

Explanation: Commit level &1 escalated to &2 lock. SQL0596 SQLCODE +596 SQLSTATE 01002

Explanation: Characters conversion has resulted in substitution characters. SQL0360 SQLCODE +360 SQLSTATE 01627

Explanation: Error occurred during disconnect. SQL0645 SQLCODE +645 SQLSTATE 01528

Explanation: Datalink in table &1 in &2 may not be valid due to pending links. SQL0403 SQLCODE +403 SQLSTATE 01522

Explanation: WHERE NOT NULL clause ignored for index &1 in &2. SQL0802 SQLCODE +802 SQLSTATE 01519, 01547, 01564, 01565

Explanation: Alias &1 in &2 created but table or view not found. SQL0420 SQLCODE +420 SQLSTATE 01565

Explanation: Data conversion or data mapping error. SQL0863 SQLCODE +863 SQLSTATE 01539

Explanation: Character in CAST argument not valid.

Explanation: Mixed or DBCS CCSID not supported by relational database &1.

292

DB2 UDB for AS/400 SQL Programming Concepts V4R5

SQL0990

SQLCODE +990

SQLSTATE 01587

Explanation: Outcome unknown for the unit of work. SQL7905 SQLCODE +7905 SQLSTATE 01567

Explanation: Table &1 in &2 created but could not be journaled.

Negative SQLCODEs
SQL0007 SQLCODE -07 SQLSTATE 42601 SQL0099 SQLCODE -99 SQLSTATE 42992 Explanation: Character &1 (HEX &2) not valid in SQL statement. SQL0010 SQLCODE -10 SQLSTATE 42603 Explanation: Operator in join condition not valid. SQL0101 Explanation: String constant beginning &1 not delimited. SQL0029 SQLCODE -29 SQLSTATE 42601 SQLCODE -101 54010, 54011 SQLSTATE 54001,

Explanation: SQL statement too long or complex. SQL0102 SQLCODE -102 SQLSTATE 54002

Explanation: INTO clause missing from embedded SELECT statement. SQL0051 SQLCODE -51 SQLSTATE 3C000

Explanation: String constant beginning with &1 too long. SQL0103 SQLCODE -103 SQLSTATE 42604

Explanation: Numeric constant &1 not valid. SQL0104 SQLCODE -104 SQLSTATE 42601

Explanation: Cursor or procedure &1 previously declared. SQL0060 SQLCODE -60 SQLSTATE 42815

Explanation: Token &1 was not valid. Valid tokens: &2. SQL0105 SQLCODE -105 SQLSTATE 42604

Explanation: Value &3 for argument &1 of &2 function not valid. SQL0078 SQLCODE -78 SQLSTATE 42629

Explanation: Mixed or graphic string constant not valid. SQL0106 SQLCODE -106 SQLSTATE 42611

Explanation: Parameter name required for routine &1 in &2. SQL0080 SQLCODE -80 SQLSTATE 42978

Explanation: Precision specified for FLOAT column not valid. SQL0107 SQLCODE -107 SQLSTATE 42622

Explanation: Indicator variable &1 not SMALLINT type. SQL0084 SQLCODE -84 SQLSTATE 42612

Explanation: &1 too long. Maximum &2 characters. SQL0109 SQLCODE -109 SQLSTATE 42601

Explanation: SQL statement not allowed. SQL0090 SQLCODE -90 SQLSTATE 42618

Explanation: &1 clause not allowed. SQL0110 SQLCODE -110 SQLSTATE 42606

Explanation: Host variable not permitted here. SQL0097 SQLCODE -97 SQLSTATE 42601

Explanation: Hexadecimal constant beginning with &1 not valid.

Explanation: Use of data type not valid.

Appendix B. SQLCODEs and SQLSTATEs

293

SQL0112

SQLCODE -112

SQLSTATE 42607

SQL0129

SQLCODE -129

SQLSTATE 54004

Explanation: Argument of function &1 is another function. SQL0113 SQLCODE -113 2E000, 42602 SQLSTATE 28000,

Explanation: Too many tables in SQL statement. SQL0130 SQLCODE -130 22025 SQLSTATE 22019,

Explanation: Name &1 not allowed. SQL0114 SQLCODE -114 SQLSTATE 42961

Explanation: Escape character &1 or LIKE pattern not valid. SQL0131 SQLCODE -131 SQLSTATE 42818

Explanation: Relational database &1 not the same as current server &2. SQL0115 SQLCODE -115 SQLSTATE 42601

Explanation: Operands of LIKE not compatible or not valid. SQL0132 SQLCODE -132 SQLSTATE 42824

Explanation: Comparison operator &1 not valid. SQL0117 SQLCODE -117 SQLSTATE 42802

Explanation: LIKE predicate not valid. SQL0133 SQLCODE -133 SQLSTATE 42906

Explanation: Statement inserts wrong number of values. SQL0118 SQLCODE -118 SQLSTATE 42902

Explanation: Operator on correlated column in SQL function not valid. SQL0134 SQLCODE -134 SQLSTATE 42907

Explanation: Table &1 in &2 also specified in a FROM clause. SQL0119 SQLCODE -119 SQLSTATE 42803

Explanation: Argument of function too long. SQL0136 SQLCODE -136 SQLSTATE 54005

Explanation: Column &1 in HAVING clause not in GROUP BY. SQL0120 SQLCODE -120 SQLSTATE 42903

Explanation: ORDER BY or GROUP BY columns too long. SQL0137 SQLCODE -137 SQLSTATE 54006

Explanation: Result too long. SQL0138 SQLCODE -138 SQLSTATE 22011

Explanation: Use of column function &2 not valid. SQL0121 SQLCODE -121 SQLSTATE 42701

Explanation: Duplicate column name &1 in INSERT or UPDATE. SQL0122 SQLCODE -122 SQLSTATE 42803

Explanation: Argument &1 of SUBSTR function not valid. SQL0144 SQLCODE -144 SQLSTATE 58003

Explanation: Section number not valid. SQL0145 SQLCODE -145 SQLSTATE 55005

Explanation: Column specified in SELECT list not valid. SQL0125 SQLCODE -125 SQLSTATE 42805

Explanation: Recursion not supported for an application server other than the AS/400 system. SQL0150 SQLCODE -150 SQLSTATE 42807

Explanation: ORDER BY column number &1 not valid. SQL0128 SQLCODE -128 SQLSTATE 42601

Explanation: View or logical file &1 in &2 read-only.

Explanation: Use of NULL is not valid.

294

DB2 UDB for AS/400 SQL Programming Concepts V4R5

SQL0151

SQLCODE -151

SQLSTATE 42808

SQL0175

SQLCODE -175

SQLSTATE 58028

Explanation: Column &1 in table &2 in &3 read-only. SQL0152 SQLCODE -152 SQLSTATE 42809

Explanation: COMMIT failed. SQL0180 SQLCODE -180 SQLSTATE 22007

Explanation: Constraint type not valid for constraint &1 in &2. SQL0153 SQLCODE -153 SQLSTATE 42908

Explanation: Syntax of date, time, or timestamp value not valid. SQL0181 SQLCODE -181 SQLSTATE 22007

Explanation: Column list required for CREATE VIEW. SQL0154 SQLCODE -154 SQLSTATE 42909

Explanation: Value in date, time, or timestamp string not valid. SQL0182 SQLCODE -182 SQLSTATE 42816

Explanation: UNION and UNION ALL for CREATE VIEW not valid. SQL0156 SQLCODE -156 SQLSTATE 42809

Explanation: A date, time, or timestamp expression not valid. SQL0183 SQLCODE -183 SQLSTATE 22008

Explanation: &1 in &2 not a table. SQL0157 SQLCODE -157 SQLSTATE 42810

Explanation: The result of a date or timestamp expression not valid. SQL0184 SQLCODE -184 SQLSTATE 42610

Explanation: View &1 in &2 not valid in FOREIGN KEY clause. SQL0158 SQLCODE -158 SQLSTATE 42811

Explanation: Parameter marker not valid in expression. SQL0187 SQLCODE -187 SQLSTATE 42816

Explanation: Number of columns specified not consistent. SQL0159 SQLCODE -159 SQLSTATE 42809

Explanation: Use of labeled duration is not valid. SQL0188 SQLCODE -188 28000, 2E000 SQLSTATE 22503,

Explanation: &1 in &2 not correct type. SQL0160 SQLCODE -160 SQLSTATE 42813

Explanation: &1 is not a valid string representation of an authorization name or a relational database name. SQL0189 SQLCODE -189 SQLSTATE 22522

Explanation: WITH CHECK OPTION not allowed for view &1 in &2. SQL0161 SQLCODE -161 SQLSTATE 44000

Explanation: Coded Character Set Identifier &1 is not valid. SQL0190 SQLCODE -190 SQLSTATE 42837

Explanation: INSERT/UPDATE not allowed due to WITH CHECK OPTION. SQL0170 SQLCODE -170 SQLSTATE 42605

Explanation: Attributes of column &3 in &1 in &2 not compatible. SQL0191 SQLCODE -191 SQLSTATE 22504

Explanation: Number of arguments for function &1 not valid. SQL0171 SQLCODE -171 SQLSTATE 42815

Explanation: MIXED data not properly formed. SQL0192 SQLCODE -192 SQLSTATE 42937

Explanation: Argument &1 of function &2 not valid.

Explanation: Argument of TRANSLATE function not valid.

Appendix B. SQLCODEs and SQLSTATEs

295

SQL0194

SQLCODE -194

SQLSTATE 42848

SQL0221

SQLCODE -221

SQLSTATE 42873

Explanation: KEEP LOCKS not allowed. SQL0195 SQLCODE -195 SQLSTATE 42814

Explanation: Number of rows &2 not valid. SQL0225 SQLCODE -225 SQLSTATE 42872

Explanation: Last column of &1 in &2 cannot be dropped. SQL0196 SQLCODE -196 SQLSTATE 42817

Explanation: FETCH not valid; cursor &1 not declared with SCROLL. SQL0226 SQLCODE -226 SQLSTATE 24507

Explanation: Column &3 in &1 in &2 cannot be dropped with RESTRICT. SQL0197 SQLCODE -197 SQLSTATE 42877

Explanation: Current row deleted or moved for cursor &1. SQL0227 SQLCODE -227 SQLSTATE 24513

Explanation: Column &1 cannot be qualified. SQL0198 SQLCODE -198 SQLSTATE 42617

Explanation: FETCH not valid, cursor &1 in unknown position. SQL0228 SQLCODE -228 SQLSTATE 42620

Explanation: SQL statement empty or blank. SQL0199 SQLCODE -199 SQLSTATE 42601

Explanation: FOR UPDATE OF clause not valid with SCROLL for cursor &1. SQL0231 SQLCODE -231 SQLSTATE 22006

Explanation: Keyword &1 not expected. Valid tokens: &2. SQL0203 SQLCODE -203 SQLSTATE 42702

Explanation: Position of cursor &1 not valid for FETCH of current row. SQL0250 SQLCODE -250 SQLSTATE 42718

Explanation: Column &1 is ambiguous. SQL0204 SQLCODE -204 SQLSTATE 42704

Explanation: Local relational database not defined in the directory. SQL0251 SQLCODE -251 42602 SQLSTATE 2E000,

Explanation: &1 in &2 type *&3 not found. SQL0205 SQLCODE -205 SQLSTATE 42703

Explanation: Column &1 not in table &2. SQL0206 SQLCODE -206 SQLSTATE 42703

Explanation: Character in relational database name &1 is not valid. SQL0255 SQLCODE -255 SQLSTATE 42999

Explanation: Column &1 not in specified tables. SQL0208 SQLCODE -208 SQLSTATE 42707

Explanation: DB2 Multisystem query error. SQL0256 SQLCODE -256 SQLSTATE 42998

Explanation: ORDER BY column &1 not in results table. SQL0212 SQLCODE -212 SQLSTATE 42712

Explanation: Constraint &1 in &2 not allowed on distributed file. SQL0270 SQLCODE -270 SQLSTATE 42997

Explanation: Duplicate table designator &1 not valid. SQL0214 SQLCODE -214 SQLSTATE 42822

Explanation: Unique index not allowed. SQL0301 SQLCODE -301 07006,42895 SQLSTATE

Explanation: ORDER BY expression is not valid.

Explanation: Input host variable &2 or argument &1 not valid.

296

DB2 UDB for AS/400 SQL Programming Concepts V4R5

SQL0302

SQLCODE -302 SQLSTATE 22001, 22003, 22023, 22024

SQL0331

SQLCODE -331

SQLSTATE 22021

Explanation: Conversion error on input host variable &2. SQL0303 SQLCODE -303 42806 SQLSTATE 22001,

Explanation: Character conversion cannot be performed. SQL0332 SQLCODE -332 SQLSTATE 57017

Explanation: Character conversion between CCSID &1 and CCSID &2 not valid. SQL0334 SQLCODE -334 SQLSTATE 22524

Explanation: Host variable &1 not compatible with SELECT item. SQL0304 SQLCODE -304 22023, 22504 SQLSTATE 22003,

Explanation: Character conversion has resulted in truncation. SQL0338 SQLCODE -338 SQLSTATE 42972

Explanation: Conversion error in assignment to host variable &2. SQL0305 SQLCODE -305 SQLSTATE 22002

Explanation: JOIN expression not valid. SQL0340 SQLCODE -340 SQLSTATE 42726

Explanation: Indicator variable required. SQL0306 SQLCODE -306 SQLSTATE 42863

Explanation: Duplicate name &1 for common table expression. SQL0341 SQLCODE -341 SQLSTATE 42835

Explanation: Undefined host variable in REXX. SQL0311 SQLCODE -311 SQLSTATE 22501

Explanation: Cyclic references between common table expressions. SQL0346 SQLCODE -346 SQLSTATE 42836

Explanation: Length in a varying-length host variable not valid. SQL0312 SQLCODE -312 SQLSTATE 42618

Explanation: Recursion not allowed for common table expressions. SQL0350 SQLCODE -350 SQLSTATE 42962

Explanation: Host variable &1 not defined or not usable. SQL0313 SQLCODE -313 07004 SQLSTATE 07001,

Explanation: Column &1 is not valid as key field for index or constraint. SQL0351 SQLCODE -351 SQLSTATE 56084

Explanation: Number of host variables not valid. SQL0328 SQLCODE -328 SQLSTATE 42996

Explanation: Column &1 not allowed in partitioning key. SQL0329 SQLCODE -329 SQLSTATE 0E000

Explanation: The AR is not at the same level and DB2/400 cannot transform the data type to a compatible type. SQL0352 SQLCODE -352 SQLSTATE 56084

Explanation: The SET PATH name list is not valid. SQL0330 SQLCODE -330 SQLSTATE 22021

Explanation: The AS is not at the same level and DB2/400 cannot transform the data type to a compatible type. SQL0357 SQLCODE -357 SQLSTATE 57050

Explanation: Character conversion cannot be performed.

Explanation: File server &1 used in DataLink not currently available.

Appendix B. SQLCODEs and SQLSTATEs

297

SQL0358

SQLCODE -358

SQLSTATE 428D1

SQL0414

SQLCODE -414

SQLSTATE 42824

Explanation: Error &1 occurred using DataLink data type. SQL0392 SQLCODE -392 SQLSTATE 42855

Explanation: Column &1 not valid in LIKE predicate. SQL0415 SQLCODE -415 SQLSTATE 42825

Explanation: UNION operands not compatible. SQL0417 SQLCODE -417 SQLSTATE 42609

Explanation: Assignment of LOB to specified host variable not allowed. SQL0398 SQLCODE -398 SQLSTATE 428D2

Explanation: Combination of parameter markers not valid. SQL0418 SQLCODE -418 SQLSTATE 42610

Explanation: AS LOCATOR cannot be specified for a non-LOB parameter. SQL0401 SQLCODE -401 SQLSTATE 42818

Explanation: Use of parameter marker is not valid. SQL0419 SQLCODE -419 SQLSTATE 42911

Explanation: Comparison operator &1 operands not compatible. SQL0402 SQLCODE -402 SQLSTATE 42819

Explanation: Negative scale not valid. SQL0420 SQLCODE -420 SQLSTATE 22018

Explanation: &1 use not valid. SQL0404 SQLCODE -404 SQLSTATE 22001

Explanation: Character in CAST argument not valid. SQL0421 SQLCODE -421 SQLSTATE 42826

Explanation: Value for column &1 too long. SQL0405 SQLCODE -405 SQLSTATE 42820

Explanation: Number of UNION operands not equal. SQL0423 SQLCODE -423 SQLSTATE 0F001

Explanation: Numeric constant &1 out of range. SQL0406 SQLCODE -406 22023, 22504 SQLSTATE 22003,

Explanation: LOB locator &1 not valid. SQL0428 SQLCODE -428 SQLSTATE 25501

Explanation: Conversion error on assignment to column &2. SQL0407 SQLCODE -407 SQLSTATE 23502

Explanation: SQL statement cannot be run. SQL0429 SQLCODE -429 SQLSTATE 54028

Explanation: Null values are not allowed in column &1. SQL0408 SQLCODE -408 SQLSTATE 42821

Explanation: The maximum number of concurrent LOB locators has been reached. SQL0432 SQLCODE -432 SQLSTATE 42841

Explanation: INSERT or UPDATE value for column &1 not compatible. SQL0410 SQLCODE -410 SQLSTATE 42820

Explanation: A parameter marker cannot have the user-defined type name &1. SQL0433 SQLCODE -433 SQLSTATE 22001

Explanation: Floating point literal &1 not valid. SQL0412 SQLCODE -412 SQLSTATE 42823

Explanation: Significant digits truncated during CAST from numeric to character. SQL0440 SQLCODE -440 SQLSTATE 42884

Explanation: Subquery with more than one result column not valid.

Explanation: Number of arguments on CALL must match procedure.

298

DB2 UDB for AS/400 SQL Programming Concepts V4R5

SQL0441

SQLCODE -441

SQLSTATE 42601

SQL0455

SQLCODE -455

SQLSTATE 42882

Explanation: Clause or keyword &1 not valid where specified. SQL0442 SQLCODE -442 SQLSTATE 54023

Explanation: Specific name not same as procedure name. SQL0456 SQLCODE -456 SQLSTATE 42710

Explanation: Maximum # of parameters on CALL exceeded. SQL0443 SQLCODE -443 38501 SQLSTATE 2Fxxx,

Explanation: Specific name &3 in &2 already exists. SQL0457 SQLCODE -457 SQLSTATE 42939

Explanation: Name &1 in &2 not allowed for function. SQL0458 SQLCODE -458 SQLSTATE 42883

Explanation: Trigger program or external procedure detected on error. SQL0444 SQLCODE -444 SQLSTATE 42724

Explanation: Function &1 in &2 not found with matching signature. SQL0461 SQLCODE -461 SQLSTATE 42846

Explanation: External program &4 in &1 not found. SQL0446 SQLCODE -446 SQLSTATE 22003

Explanation: Cast from &1 to &2 not supported. SQL0463 SQLCODE -463 SQLSTATE 39001

Explanation: Conversion error in assignment of argument &2. SQL0448 SQLCODE -448 SQLSTATE 54023

Explanation: SQLSTATE &4 returned from routine &1 in &2 not valid.. SQL0469 SQLCODE -469 SQLSTATE 42886

Explanation: Maximum parameters on DECLARE PROCEDURE exceeded. SQL0449 SQLCODE -449 SQLSTATE 42878

Explanation: IN, OUT, INOUT not valid for parameter &4 in procedure &1 in &2. SQL0470 SQLCODE -470 SQLSTATE 39002

Explanation: External program name for procedure &1 in &2 not valid. SQL0451 SQLCODE -451 SQLSTATE 42815

Explanation: NULL values not allowed for parameter &4 in procedure. SQL0473 SQLCODE -473 SQLSTATE 42918

Explanation: Attributes of parameter &1 not valid for procedure. SQL0452 SQLCODE -452 SQLSTATE 428A1

Explanation: User-defined type &1 cannot be created. SQL0475 SQLCODE -475 SQLSTATE 42866

Explanation: Unable to access a file that is referred to by a file reference variable. SQL0453 SQLCODE -453 SQLSTATE 42880

Explanation: RETURNS data type for function &3 in &4 not valid. SQL0476 SQLCODE -476 SQLSTATE 42725

Explanation: Return type for function &1 in &2 not compatible with CAST TO type. SQL0454 SQLCODE -454 SQLSTATE 42723

Explanation: Function &1 in &2 not unique. SQL0478 SQLCODE -478 SQLSTATE 42893

Explanation: Function &1 in &2 with the same signature already exists.

Explanation: Object &1 in &2 of type &3 cannot be dropped.

Appendix B. SQLCODEs and SQLSTATEs

299

SQL0483

SQLCODE -483

SQLSTATE 42885

SQL0510

SQLCODE -510

SQLSTATE 42828

Explanation: Parameters for function &1 in &2 not same as sourced function. SQL0484 SQLCODE -484 SQLSTATE 42733

Explanation: Cursor &1 for file &2 is read-only. SQL0511 SQLCODE -511 SQLSTATE 42829

Explanation: FOR UPDATE OF clause not valid. SQL0513 SQLCODE -513 SQLSTATE 42924

Explanation: Routine &1 in &2 already exists. SQL0487 SQLCODE -487 SQLSTATE 38001

Explanation: SQL statements not allowed. SQL0490 SQLCODE -490 SQLSTATE 428B7

Explanation: Alias &1 in &2 cannot reference another alias. SQL0514 SQLCODE -514 SQLSTATE 26501

Explanation: Numeric value &1 not valid. SQL0491 SQLCODE -491 SQLSTATE 42601

Explanation: Prepared statement &2 not found. SQL0516 SQLCODE -516 SQLSTATE 26501

Explanation: RETURNS clause required on CREATE FUNCTION statement. SQL0492 SQLCODE -492 SQLSTATE 42879

Explanation: Prepared statement &2 not found. SQL0517 SQLCODE -517 SQLSTATE 07005

Explanation: Data type for function &1 in &2 not valid for source type. SQL0501 SQLCODE -501 SQLSTATE 24501

Explanation: Prepared statement &2 not SELECT statement. SQL0518 SQLCODE -518 SQLSTATE 07003

Explanation: Prepared statement &1 not found. SQL0519 SQLCODE -519 SQLSTATE 24506

Explanation: Cursor &1 not open. SQL0502 SQLCODE -502 SQLSTATE 24502

Explanation: Prepared statement &2 in use. SQL0520 SQLCODE -520 SQLSTATE 42828

Explanation: Cursor &1 already open. SQL0503 SQLCODE -503 SQLSTATE 42912

Explanation: Column &3 cannot be updated. SQL0504 SQLCODE -504 SQLSTATE 34000

Explanation: Cannot UPDATE or DELETE on cursor &1. SQL0525 SQLCODE -525 SQLSTATE 51015

Explanation: Cursor &1 not declared. SQL0507 SQLCODE -507 SQLSTATE 24501

Explanation: Statement not valid on application server. SQL0527 SQLCODE -527 SQLSTATE 42874

Explanation: Cursor &1 not open. SQL0508 SQLCODE -508 SQLSTATE 24504

Explanation: ALWCPYDTA(*NO) specified but temporary result required for &1. SQL0530 SQLCODE -530 SQLSTATE 23503

Explanation: Cursor &1 not positioned on locked row. SQL0509 SQLCODE -509 SQLSTATE 42827

Explanation: Insert or UPDATE value not allowed by referential constraint. SQL0531 SQLCODE -531 23504 SQLSTATE 23001,

Explanation: Table &2 in &3 not same as table in cursor &1.

Explanation: Update prevented by referential constraint.

300

DB2 UDB for AS/400 SQL Programming Concepts V4R5

SQL0532

SQLCODE -532 23504

SQLSTATE 23001,

SQL0557

SQLCODE -557

SQLSTATE 42852

Explanation: Delete prevented by referential constraint. SQL0536 SQLCODE -536 SQLSTATE 42914

Explanation: Privilege not valid for table or view &1 in &2. SQL0573 SQLCODE -573 SQLSTATE 42890

Explanation: Table does not have matching parent key. SQL0574 SQLCODE -574 SQLSTATE 42894

Explanation: Delete not allowed because table referenced in subquery can be affected. SQL0537 SQLCODE -537 SQLSTATE 42709

Explanation: Default value not valid. SQL0577 SQLCODE -577 2F002 SQLSTATE 38002,

Explanation: Duplicate column name in definition of key. SQL0538 SQLCODE -538 SQLSTATE 42830

Explanation: Modifying SQL data not permitted. SQL0578 SQLCODE -578 SQLSTATE 2F005

Explanation: Foreign key attributes do not match parent key. SQL0539 SQLCODE -539 SQLSTATE 42888

Explanation: RETURN statement not executed for SQL function &1 in &2. SQL0579 SQLCODE -579 2F004 SQLSTATE 38004,

Explanation: Table does not have primary key. SQL0541 SQLCODE -541 SQLSTATE 42891

Explanation: Reading SQL data not permitted. SQL0580 SQLCODE -580 SQLSTATE 42625

Explanation: Duplicate UNIQUE constraint already exists. SQL0543 SQLCODE -543 SQLSTATE 23511

Explanation: At least one result in CASE expression must be not NULL. SQL0581 SQLCODE -581 SQLSTATE 42804

Explanation: Constraint &1 conflicts with SET NULL or SET DEFAULT rule. SQL0544 SQLCODE -544 SQLSTATE 23512

Explanation: The results in a CASE expression are not compatible. SQL0583 SQLCODE -583 SQLSTATE 42845

Explanation: CHECK constraint &1 cannot be added. SQL0545 SQLCODE -545 SQLSTATE 23513

Explanation: Use of function &1 in &2 not valid. SQL0585 SQLCODE -585 SQLSTATE 42732

Explanation: INSERT or UPDATE not allowed by CHECK constraint. SQL0546 SQLCODE -546 SQLSTATE 42621

Explanation: Library &1 is used incorrectly on the SET PATH statement SQL0590 SQLCODE -590 SQLSTATE 42734

Explanation: CHECK condition of constraint &1 not valid. SQL0551 SQLCODE -551 SQLSTATE 42501

Explanation: Name &1 specified in &2 not unique. SQL0601 SQLCODE -601 SQLSTATE 42710

Explanation: Not authorized to object &1 in &2 type *&3. SQL0552 SQLCODE -552 SQLSTATE 42502

Explanation: Object &1 in &2 type *&3 already exists.

Explanation: Not authorized to &1.

Appendix B. SQLCODEs and SQLSTATEs

301

SQL0602

SQLCODE -602

SQLSTATE 54008

SQL0631

SQLCODE -631

SQLSTATE 54008

Explanation: More than 120 columns specified for CREATE INDEX. SQL0603 SQLCODE -603 SQLSTATE 23515

Explanation: Foreign key for referential constraint too long. SQL0637 SQLCODE -637 SQLSTATE 42614

Explanation: Unique index cannot be created because of duplicate keys. SQL0604 SQLCODE -604 SQLSTATE 42611

Explanation: Duplicate &1 keyword. SQL0642 SQLCODE -642 SQLSTATE 54021

Explanation: Attributes of column not valid. SQL0607 SQLCODE -607 SQLSTATE 42832

Explanation: Maximum number of constraints exceeded. SQL0658 SQLCODE -658 SQLSTATE 42917

Explanation: Operation not allowed on system table &1 in &2. SQL0612 SQLCODE -612 SQLSTATE 42711

Explanation: Function cannot be dropped. SQL0666 SQLCODE -666 SQLSTATE 57005

Explanation: &1 is a duplicate column name. SQL0613 SQLCODE -613 SQLSTATE 54008

Explanation: Estimated query processing time exceeds limit. SQL0667 SQLCODE -667 SQLSTATE 23520

Explanation: Primary or unique key constraint too long. SQL0614 SQLCODE -614 SQLSTATE 54008

Explanation: Foreign key does not match a value in the parent key. SQL0675 SQLCODE -675 SQLSTATE 42892

Explanation: Length of columns for CREATE INDEX too long. SQL0615 SQLCODE -615 SQLSTATE 55006

Explanation: Specified delete rule not allowed with existing trigger. SQL0679 SQLCODE -679 SQLSTATE 57006

Explanation: Object &1 in &2 type *&3 not dropped. It is in use. SQL0616 SQLCODE -616 SQLSTATE 42893

Explanation: Object &1 in &2 type *&3 not created due to pending operation. SQL0683 SQLCODE -683 SQLSTATE 42842

Explanation: &1 in &2 type &3 cannot be dropped with RESTRICT. SQL0624 SQLCODE -624 SQLSTATE 42889

Explanation: FOR DATA or CCSID clause not valid for specified type. SQL0707 SQLCODE -707 SQLSTATE 42939

Explanation: Table already has primary key. SQL0628 SQLCODE -628 SQLSTATE 42613

Explanation: Name &1 in &2 not allowed for distinct type. SQL0713 SQLCODE -713 SQLSTATE 42815

Explanation: Clauses are mutually exclusive. SQL0629 SQLCODE -629 SQLSTATE 42834

Explanation: Host variable for &2 is NULL. SQL0724 SQLCODE -724 SQLSTATE 54038

Explanation: SET NULL not allowed for referential constraint.

Explanation: Too many cascaded trigger programs.

302

DB2 UDB for AS/400 SQL Programming Concepts V4R5

SQL0751

SQLCODE -751

SQLSTATE 42987

SQL0783

SQLCODE -783

SQLSTATE 42738

Explanation: SQL statement &1 not allowed in stored procedure or trigger. SQL0752 SQLCODE -752 SQLSTATE 0A001

Explanation: Select list for cursor &1 in FOR statement not valid. SQL0784 SQLCODE -784 SQLSTATE 42860

Explanation: Connection cannot be changed. Reason code is &1. SQL0773 SQLCODE -773 SQLSTATE 20000

Explanation: Check constraint &1 cannot be dropped. SQL0785 SQLCODE -785 SQLSTATE 428D8

Explanation: Case not found for CASE statement. SQL0774 SQLCODE -774 SQLSTATE 2D522

Explanation: Use of SQLCODE or SQLSTATE not valid. SQL0802 SQLCODE -802 SQLSTATE 22003, 22012, 22023, 22504

Explanation: Statement cannot be executed within a compound SQL statement. SQL0775 SQLCODE -775 SQLSTATE 42910

Explanation: Data conversion or data mapping error. SQL0803 SQLCODE -803 SQLSTATE 23505

Explanation: Statement not allowed in a compound SQL statement. SQL0776 SQLCODE -776 SQLSTATE 428D4

Explanation: Duplicate key value specified. SQL0804 SQLCODE -804 SQLSTATE 07002

Explanation: SQLDA not valid. SQL0805 SQLCODE -805 SQLSTATE 51002

Explanation: Cursor &1 specified in FOR statement not allowed. SQL0777 SQLCODE -777 SQLSTATE 42919

Explanation: SQL package &1 in &2 not found. SQL0811 SQLCODE -811 SQLSTATE 21000

Explanation: Nested compound statements not allowed. SQL0778 SQLCODE -778 SQLSTATE 428D5

Explanation: Result of SELECT INTO or subquery more than one row. SQL0818 SQLCODE -818 SQLSTATE 51003

Explanation: End label &1 not same as begin label. SQL0779 SQLCODE -779 SQLSTATE 42736

Explanation: Consistency tokens do not match. SQL0822 SQLCODE -822 SQLSTATE 51004

Explanation: Label &1 specified on LEAVE statement not valid. SQL0780 SQLCODE -780 SQLSTATE 428D6

Explanation: Address in SQLDA not valid. SQL0827 SQLCODE -827 SQLSTATE 42862

Explanation: UNDO specified for a handler and ATOMIC not specified. SQL0781 SQLCODE -781 SQLSTATE 42737

Explanation: &1 in &2 type *SQLPKG cannot be accessed. SQL0840 SQLCODE -840 SQLSTATE 54004

Explanation: Condition &1 specified in handler not defined. SQL0782 SQLCODE -782 SQLSTATE 428D7

Explanation: Number of selected items exceeds 8000. SQL0842 SQLCODE -842 SQLSTATE 08002

Explanation: Condition value &1 specified in handler not valid.

Explanation: Connection already exists.

Appendix B. SQLCODEs and SQLSTATEs

303

SQL0843

SQLCODE -843

SQLSTATE 08003

SQL0950

SQLCODE -950

SQLSTATE 42705

Explanation: Connection does not exist. SQL0858 SQLCODE -858 SQLSTATE 08501

Explanation: Relational database &1 not in relational database directory. SQL0951 SQLCODE -951 SQLSTATE 55007

Explanation: Cannot disconnect relational database due to LU 6.2 protected conversation. SQL0862 SQLCODE -862 SQLSTATE 55029

Explanation: Object &1 in &2 not altered. It is in use. SQL0952 SQLCODE -952 SQLSTATE 57014

Explanation: Local program attempted to connect to a remote relational database. SQL0871 SQLCODE -871 SQLSTATE 54019

Explanation: Processing of the SQL statement ended by ENDRDBRQS command. SQL0969 SQLCODE -969 SQLSTATE 58033

Explanation: Too many CCSID values specified. SQL0900 SQLCODE -900 SQLSTATE 08003

Explanation: Unexpected client driver error. SQL0971 SQLCODE -971 SQLSTATE 57011

Explanation: Application process not in a connected state. SQL0901 SQLCODE -901 SQLSTATE 58004

Explanation: Referential constraint &4 in check pending state. SQL5001 SQLCODE -5001 SQLSTATE 42703

Explanation: SQL system error. SQL0904 SQLCODE -904 SQLSTATE 57011

Explanation: Column qualifier &2 undefined. SQL5002 SQLCODE -5002 SQLSTATE 42812

Explanation: Resource limit exceeded. SQL0906 SQLCODE -906 SQLSTATE 24514

Explanation: Collection must be specified for table &1. SQL5003 SQLCODE -5003 SQLSTATE 42922

Explanation: Operation not performed because of previous error. SQL0907 SQLCODE -907 SQLSTATE 27000

Explanation: Cannot perform operation under commitment control. SQL5005 SQLCODE -5005 SQLSTATE 42815

Explanation: Attempt to change same row twice. SQL0910 SQLCODE -910 SQLSTATE 57007

Explanation: Operator &4 not consistent with operands. SQL5012 SQLCODE -5012 SQLSTATE 42618

Explanation: Object &1 in &2 type *&3 has a pending change. SQL0913 SQLCODE -913 SQLSTATE 57033

Explanation: Host variable not a numeric with zero scale. SQL5016 SQLCODE -5016 SQLSTATE 42833

Explanation: Row or object &1 in &2 type *&3 in use. SQL0917 SQLCODE -917 SQLSTATE 42969

Explanation: Object name &1 not valid for naming option. SQL5021 SQLCODE -5021 SQLSTATE 42930

Explanation: Package not created. SQL0918 SQLCODE -918 SQLSTATE 51021

Explanation: FOR UPDATE OF column &1 also in ORDER BY.

Explanation: Rollback required.

304

DB2 UDB for AS/400 SQL Programming Concepts V4R5

SQL5023

SQLCODE -5023

SQLSTATE 26510

SQL7018

SQLCODE -7018

SQLSTATE 42970

Explanation: Duplicate statement name in DECLARE CURSOR. SQL5024 SQLCODE -5024 SQLSTATE 42618

Explanation: COMMIT HOLD or ROLLBACK HOLD not allowed. SQL7021 SQLCODE -7021 SQLSTATE 57043

Explanation: Host variable &1 not character. SQL5047 SQLCODE -5047 SQLSTATE 42616

Explanation: Local program attempting to run on application server. SQL7022 SQLCODE -7022 SQLSTATE 42977

Explanation: Error processing SRTSEQ or LANGID parameter. SQL5051 SQLCODE -5051 SQLSTATE 42875

Explanation: User &1 not the same as current user &2 for connect to local relational database. SQL7024 SQLCODE -7024 SQLSTATE 42876

Explanation: Incorrect qualifier. SQL7001 SQLCODE -7001 SQLSTATE 42858

Explanation: Index cannot be created because of CCSID incompatibility. SQL7026 SQLCODE -7026 SQLSTATE 42896

Explanation: File &1 in &2 not database file. SQL7002 SQLCODE -7002 SQLSTATE 42847

Explanation: Auxiliary storage pool not found. SQL7027 SQLCODE -7027 SQLSTATE 42984

Explanation: Override parameter not valid. SQL7003 SQLCODE -7003 SQLSTATE 42857

Explanation: Unable to grant to a view. SQL7028 SQLCODE -7028 SQLSTATE 42944

Explanation: File &1 in &2 has more than one format. SQL7006 SQLCODE -7006 SQLSTATE 55018

Explanation: Unable to CHGOBJOWN for primary group. SQL7029 SQLCODE -7029 SQLSTATE 428B8

Explanation: Cannot drop collection &1. SQL7007 SQLCODE -7007 SQLSTATE 51009

Explanation: New name &3 is not valid. SQL7031 SQLCODE -7031 SQLSTATE 54044

Explanation: COMMIT or ROLLBACK not valid. SQL7008 SQLCODE -7008 SQLSTATE 55019

Explanation: Sort sequence table &1 too long. SQL7032 SQLCODE -7032 SQLSTATE 42904

Explanation: &1 in &2 not valid for operation. SQL7010 SQLCODE -7010 SQLSTATE 42850

Explanation: SQL procedure &1 in &2 not created. SQL7033 SQLCODE -7033 SQLSTATE 42923

Explanation: Logical file &1 in &2 not valid for CREATE VIEW. SQL7011 SQLCODE -7011 SQLSTATE 42851

Explanation: Alias name &1 in &2 not allowed. SQL7034 SQLCODE -7034 SQLSTATE 42926

Explanation: &1 in &2 not table, view, or physical file. SQL7017 SQLCODE -7017 SQLSTATE 42971

Explanation: LOB locators are not allowed with COMMIT(*NONE). SQL7037 SQLCODE -7037 SQLSTATE 42835

Explanation: Commitment control is already active to a DDM target.

Explanation: Data in a distributed file &1 in &2 cannot be redistributed.

Appendix B. SQLCODEs and SQLSTATEs

305

SQL7038

SQLCODE -7038

SQLSTATE 429B7

SQ30053

SQLCODE -30053

SQLSTATE 42506

Explanation: Delete cascade not valid for &1 in &2. SQL7941 SQLCODE -7941 SQLSTATE 42981

Explanation: Not authorized to create package for owner &1. SQ30060 SQLCODE -30060 SQLSTATE 08004

Explanation: Application process not at commit boundary. SQL9012 SQLCODE -9012 SQLSTATE 42968

Explanation: User not authorized to relational database &1. SQ30061 SQLCODE -30061 SQLSTATE 08004

Explanation: DB2 UDB Query Manager and SQL Development Kit not available. SQ30000 SQLCODE -30000 SQLSTATE 58008

Explanation: Relational database &1 not found. SQ30070 SQLCODE -30070 SQLSTATE 58014

Explanation: Distributed Relational Database Architecture (DRDA) protocol error. SQ30001 SQLCODE -30001 SQLSTATE 57042

Explanation: Distributed Data Management (DDM) command &1 not supported. SQ30071 SQLCODE -30071 SQLSTATE 58015

Explanation: Call to distributed SQL program not allowed. SQ30020 SQLCODE -30020 SQLSTATE 58009

Explanation: Distributed Data Management (DDM) object &1 not supported. SQ30072 SQLCODE -30072 SQLSTATE 58016

Explanation: Distributed Relational Database Architecture (DRDA) protocol error. SQ30021 SQLCODE -30021 SQLSTATE 58010

Explanation: Distributed Data Management (DDM) parameter &1 not supported. SQ30073 SQLCODE -30073 SQLSTATE 58017

Explanation: Distributed relational database not supported by the remote system. SQ30040 SQLCODE -30040 SQLSTATE 57012

Explanation: Distributed Data Management (DDM) parameter value &1 not supported. SQ30074 SQLCODE -30074 SQLSTATE 58018

Explanation: DDM resource &2 at relational database &1 not available. SQ30041 SQLCODE -30041 SQLSTATE 57013

Explanation: Distributed Data Management (DDM) reply message &1 not supported. SQ30080 SQLCODE -30080 SQLSTATE 08001

Explanation: DDM resources at relational database &1 not available. SQ30050 SQLCODE -30050 SQLSTATE 58011

Explanation: Communication error occurred during distributed database processing. SQ30089 SQLCODE -30089 SQLSTATE 08001

Explanation: DDM command &1 is not valid while bind process is in progress. SQ30051 SQLCODE -30051 SQLSTATE 58012

Explanation: Communication error occurred during DB2 Multisystem processing. SQ30090 SQLCODE -30090 2D528, 2D529 SQLSTATE 25000,

Explanation: Bind process for specified package name and consistency token not active. SQ30052 SQLCODE -30052 SQLSTATE 42932

Explanation: Change request not valid for read-only application server.

Explanation: Program preparation assumptions not correct.

306

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Appendix C. DB2 UDB for AS/400 CL Command Descriptions


This appendix contains the syntax diagrams referred to and used in this book and the SQL Reference book.

CRTSQLPKG (Create Structured Query Language Package) Command


Job: B,I Pgm: B,I REXX: B,I
*LIBL/ CRTSQLPKG PGM( *CURLIB/ library-name/ program-name )

Exec

(1) *PGM relational-database-name

RDB(

USER(

*CURRENT user-name

PASSWORD(

*NONE password

GENLVL(

10 severity-level

REPLACE(

*YES *NO

DFTRDBCOL(

*PGM *NONE collection-name

*LIBL/ PRTFILE( *CURLIB/ library-name/

QSYSPRT printer-file-name

OBJTYPE(

*PGM *SRVPGM

Copyright IBM Corp. 2000

307

CRTSQLPKG
*ALL (2) MODULE( module-name )

TEXT(

*PGMTXT *BLANK 'description'

Notes: 1 2 All parameters preceding this point can be specified in positional form. A maximum of 256 modules may be specified.

Purpose: The Create Structured Query Language Package (CRTSQLPKG) command is used to create (or re-create) an SQL package on a relational database from an existing distributed SQL program. A distributed SQL program is a program created by specifying the RDB parameter on a CRTSQLxxx (where xxx = C, CI, CBL, CBLI, FTN, PLI, or RPG or RPGI) command. Parameters: PGM Specifies the qualified name of the program for which the SQL package is being created. The program must be a distributed SQL program. The name of the program can be qualified by one of the following library values: *LIBL: All libraries in the jobs library list are searched until the first match is found. *CURLIB: The current library for the job is searched. If no library is specified as the current library for the job, the QGPL library is used. library-name: Specify the name of the library to be searched. program-name: Specify the name of the program for which the package is being created. RDB Specifies the name of the relational database where the SQL package is being created. *PGM: The relational database name specified for the SQL program is used. The relational database name is specified on the RDB parameter of the distributed SQL program. relational-database-name: Specify the name of the relational database where the SQL package is to be created. Use the Work with Relational Database Directory Entry (WRKRDBDIRE) command to show the relational database names that are valid on this parameter.

308

DB2 UDB for AS/400 SQL Programming Concepts V4R5

CRTSQLPKG
USER Specifies the user name sent to the remote system when starting the conversation. *CURRENT: The user name associated with the current job is used. user-name: Specify the user name being used for the application server job. PASSWORD Specifies the password to be used on the remote system. *NONE: No password is sent. If this value is specified, USER(*CURRENT) must also be specified. password: Specify the password of the user name specified on the USER parameter. GENLVL Specifies the maximum severity level allowed for errors detected during SQL package creation. If errors occur at a level that exceeds the specified level, the SQL package is not created. 10: The default severity-level is 10. severity-level: Specify the maximum severity level. Valid values range from 0 through 40. REPLACE Specifies whether an existing package is being replaced with the new package. More information on this parameter is in Appendix A, Expanded Parameter Descriptions in the CL Reference book. *YES: An existing SQL package of the same name is replaced by the new SQL package. *NO: An existing SQL package of the same name is not replaced; a new SQL package is not created if the package already exists in the specified library. DFTRDBCOL Specifies the collection name to be used for unqualified names of tables, views, indexes, and SQL packages. This parameter applies only to static SQL statements in the package. *PGM: The collection name specified for the SQL program is used. The default relational database collection name is specified on the DFTRDBCOL parameter of the distributed SQL program. *NONE: Unqualified names for tables, views, indexes, and SQL packages use the search conventions specified on the OPTION parameter of the CRTSQLxxx command used to create the program. collection-name: Specify the collection name that is used for unqualified tables, views, indexes, and SQL packages. PRTFILE Specifies the qualified name of the printer device file to which the create SQL package error listing is directed. If no errors are detected during the creation of the SQL package, no listing is produced.
Appendix C. DB2 UDB for AS/400 CL Command Descriptions

309

CRTSQLPKG
The name of the printer file can be qualified by one of the following library values: *LIBL: All libraries in the jobs library list are searched until the first match is found. *CURLIB: The current library for the job is searched. If no library is specified as the current library for the job, the QGPL library is used. library-name: Specify the name of the library to be searched. QSYSPRT: If a file name is not specified, the create SQL package error listing is directed to the IBM-supplied printer file QSYSPRT. printer-file-name: Specify the name of the printer device file to which the create SQL package error listing is directed. OBJTYPE Specifies the type of program for which an SQL package is created. *PGM: Create an SQL package from the program specified on the PGM parameter. *SRVPGM: Create an SQL package from the service program specified on the PGM parameter. MODULE Specifies a list of modules in a bound program. *ALL: An SQL package is created for each module in the program. An error message is sent if none of the modules in the program contain SQL statements or none of the modules is a distributed module. Note: CRTSQLPKG can process programs that do not contain more than 1024 modules. module-name: Specify the names of up to 256 modules in the program for which an SQL package is to be created. If more than 256 modules exist that need to have an SQL package created, multiple CRTSQLPKG commands must be used. Duplicate module names in the same program are allowed. This command looks at each module in the program and if *ALL or the module name is specified on the MODULE parameter, processing continues to determine whether an SQL package should be created. If the module is created using SQL and the RDB parameter is specified on the precompile command, an SQL package is created for the module. The SQL package is associated with the module of the bound program. TEXT Specifies text that briefly describes the SQL package and its function. *PGMTXT: The text from the program for which the SQL package is being created is used. *BLANK: No text is specified. description: Specify a maximum of 50 characters of text, enclosed in apostrophes. Example:

310

DB2 UDB for AS/400 SQL Programming Concepts V4R5

CRTSQLPKG
CRTSQLPKG PAYROLL RDB(SYSTEMA) TEXT('Payroll Program')

This command creates an SQL package from the distributed SQL program PAYROLL on relational database SYSTEMA.

DLTSQLPKG (Delete Structured Query Language Package) Command


Job: B,I Pgm: B,I REXX: B,I Exec

DLTSQLPKG

*LIBL/ SQLPKG( *CURLIB/ *USRLIBL/ *ALL/ *ALLUSR/ library-name/ SQL-package-name generic*-SQL-package name )

(1)

Notes: 1 All parameters preceding this point can be specified in positional form.

Purpose: The Delete Structured Query Language Package (DLTSQLPKG) command is used to delete one or more SQL packages. DLTSQLPKG is a local command and must be used on the AS/400 system where the SQL package being deleted is located. To delete an SQL package on a remote system that is also an AS/400 system, use the Submit Remote Command (SBMRMTCMD) command to run the DLTSQLPKG command on the remote system. The user can do the following to delete an SQL package from a remote system that is not an AS/400 system: v Use interactive SQL to run the CONNECT and DROP PACKAGE operations. v Sign on the remote system and use a command local to that system. v Create and run an SQL program that contains a DROP PACKAGE SQL statement. Parameters: SQLPKG Specifies the qualified name of the SQL package being deleted. A specific or generic SQL package name can be specified. The name of the SQL Package can be qualified by one of the following library values: *LIBL: All libraries in the jobs library list are searched until the first match is found.
Appendix C. DB2 UDB for AS/400 CL Command Descriptions

311

DLTSQLPKG
*CURLIB: The current library for the job is searched. If no library is specified as the current library for the job, the QGPL library is used. *USRLIBL: Only the libraries in the user portion of the jobs library list are searched. *ALL: All libraries in the system, including QSYS, are searched. *ALLUSR: All user libraries are searched. All libraries with names that do not begin with the letter Q are searched except for the following:
#CGULIB #COBLIB #DFULIB #DSULIB #RPGLIB #SDALIB #SEULIB

Although the following Qxxx libraries are provided by IBM, they typically contain user data that changes frequently. Therefore, these libraries are considered user libraries and are also searched:
QDSNX QGPL QGPL38 QPFRDATA QRCL QS36F QUSER38 QUSRADSM QUSRBRM QUSRIJS QUSRINFSKR QUSRRDARS QUSRSYS QUSRVxRxMx

Note: A different library name, of the form QUSRVxRxMx, can be created by the user for each release that IBM supports. VxRxMx is the version, release, and modification level of the library. library-name: Specify the name of the library to be searched. SQL-package-name: Specify the name of the SQL package being deleted. generic*-SQL-package-name: Specify the generic name of the SQL package to be deleted. A generic name is a character string of one or more characters followed by an asterisk (*); for example, ABC*. If a generic name is specified, all SQL packages with names that begin with the generic name, and for which the user has authority, are deleted. If an asterisk is not included with the generic (prefix) name, the system assumes it to be the complete SQL package name. Example:
DLTSQLPKG SQLPKG(JONES)

This command deletes the SQL package JONES.

RUNSQLSTM (Run Structured Query Language Statement) Command


Job: B,I Pgm: B,I REXX: B,I Exec
source-file-name *CURLIB/ library-name/ )

*LIBL/ RUNSQLSTM SRCFILE (

312

DB2 UDB for AS/400 SQL Programming Concepts V4R5

RUNSQLSTM
(1) SRCMBR ( source-file-member-name ) *UR *CHG *ALL *RS *CS *NONE *NC *RR

COMMIT (

NAMING (

*SYS *SQL

PROCESS(

*RUN *SYN

ALWCPYDTA (

*OPTIMIZE *YES *NO

ALWBLK (

*ALLREAD *NONE *READ

ERRLVL (

10 severity-level

DATFMT (

*JOB *USA *ISO *EUR *JIS *MDY *DMY *YMD *JUL

DATSEP (

*JOB '/' '.' ',' '-' ' ' *BLANK

TIMFMT (

*HMS *USA *ISO *EUR *JIS

TIMSEP (

*JOB ':' '.' ',' ' ' *BLANK

) DECMPT (

*SYSVAL *JOB *PERIOD *COMMA

Appendix C. DB2 UDB for AS/400 CL Command Descriptions

313

RUNSQLSTM
*JOB *LANGIDUNQ *LANGIDSHR *HEX *LIBL/ table-name *CURLIB/ library-name/

SRTSEQ (

LANGID (

*JOB language-identifier

DFTRDBCOL (

*NONE collection-name

FLAGSTD (

*NONE *ANS

SAAFLAG (

*NOFLAG *FLAG

*LIBL/ PRTFILE ( *CURLIB/ library-name/

QSYSPRT printer-file-name

SQL-procedure-parameters:
*CURRENT VxRxMx *ENDACTGRP *ENDMOD

TGTRLS (

CLOSQLCSR (

OUTPUT (

*NONE *PRINT

DBGVIEW (

*NONE *STMT *LIST

USRPRF (

*NAMING *OWNER *USER

DYNUSRPRF (

*USER *OWNER

DLYPRP (

*NO *YES

314

DB2 UDB for AS/400 SQL Programming Concepts V4R5

RUNSQLSTM
Notes: 1 All parameters preceding this point can be specified in positional form.

Purpose: The Run Structured Query Language Statement (RUNSQLSTM) command processes a source file of SQL statements. Parameters: SRCFILE Specifies the qualified name of the source file that contains the SQL statements to be run. The name of the source file can be qualified by one of the following library values: *LIBL: All libraries in the jobs library list are searched until the first match is found. *CURLIB: The current library for the job is searched. If no library is specified as the current library for the job, the QGPL library is used. library-name: Specify the name of the library to be searched. source-file-name: Specify the name of the source file that contains the SQL statements to be run. The source file can be a database file or an inline data file. SRCMBR Specifies the name of the source file member that contains the SQL statements to be run. COMMIT Specifies whether SQL statements in the source file are run under commitment control. *CHG or *UR: Specifies the objects referred to in SQL ALTER, CALL, COMMENT ON, CREATE, DROP, GRANT, LABEL ON, RENAME, and REVOKE statements and the rows updated, deleted, and inserted are locked until the end of the unit of work (transaction). Uncommitted changes in other jobs can be seen. *ALL or *RS: Specifies the objects referred to in SQL ALTER, CALL, COMMENT ON, CREATE, DROP, GRANT, LABEL ON, RENAME, and REVOKE statements and the rows selected, updated, deleted, and inserted are locked until the end of the unit of work (transaction). Uncommitted changes in other jobs cannot be seen. *CS: Specifies the objects referred to in SQL ALTER, CALL, COMMENT ON, CREATE, DROP, GRANT, LABEL ON, RENAME, and REVOKE statements and the rows updated, deleted, and inserted are locked until the end of the unit of work (transaction). A row that is selected, but not updated, is locked until the next row is selected. Uncommitted changes in other jobs cannot be seen. *NONE or *NC: Specifies that commitment control is not used. Uncommitted changes in other jobs can be seen. If the SQL DROP COLLECTION statement is included in the program, *NONE or *NC must be used. If a relational

Appendix C. DB2 UDB for AS/400 CL Command Descriptions

315

RUNSQLSTM
database is specified on the RDB parameter and the relational database is on a system that is not on an AS/400, *NONE or *NC cannot be specified. *RR: Specifies the objects referred to in SQL ALTER, CALL, COMMENT ON, CREATE, DROP, GRANT, LABEL ON, RENAME, and REVOKE statements and the rows selected, updated, deleted, and inserted are locked until the end of the unit of work (transaction). Uncommitted changes in other jobs cannot be seen. All tables referred to in SELECT, UPDATE, DELETE, and INSERT statements are locked exclusively until the end of the unit of work (transaction). NAMING Specifies the naming convention used for naming objects in SQL statements. *SYS: The system naming convention (library-name/file-name) is used. *SQL: The SQL naming convention (collection-name.table-name) is used. PROCESS Specifies whether SQL statements in the source file member are executed or syntax-checked only. *RUN: Statement are syntax-checked and run. *SYN: Statements are syntax-checked only. ALWCPYDTA Specifies whether a copy of the data can be used in a SELECT statement. *OPTIMIZE: The system determines whether to use the data retrieved directly from the database or to use a copy of the data. The decision is based on which method provides the best performance. If COMMIT is *CHG or *CS and ALWBLK is not *ALLREAD, or if COMMIT is *ALL or *RR, then a copy of the data is used only when it is necessary to run a query. *YES: A copy of the data is used only when necessary. *NO: A copy of the data is not used. If temporary copy of the data is required to perform the query, an error message is returned. ALWBLK Specifies whether the database manager can use record blocking, and the extent to which blocking can be used for read-only cursors. *ALLREAD: Rows are blocked for read-only cursors if *NONE or *CHG is specified on the COMMIT parameter. All cursors in a program that are not explicitly able to be updated are opened for read-only processing even though EXECUTE or EXECUTE IMMEDIATE statements may be in the program. Specifying *ALLREAD: v Allows record blocking under commitment control level *CHG in addition to the blocking allowed for *READ. v Can improve the performance of almost all read-only cursors in programs, but limits queries in the following ways: The Rollback (ROLLBACK) command, a ROLLBACK statement in host languages, or the ROLLBACK HOLD SQL statement does not reposition a read-only cursor when *ALLREAD is specified.

316

DB2 UDB for AS/400 SQL Programming Concepts V4R5

RUNSQLSTM
Dynamic running of a positioned UPDATE or DELETE statement (for example, using EXECUTE IMMEDIATE), cannot be used to update a row in a cursor unless the DECLARE statement for the cursor includes the FOR UPDATE clause. *NONE: Rows are not blocked for retrieval of data for cursors. Specifying *NONE: v Guarantees that the data retrieved is current. v May reduce the amount of time required to retrieve the first row of data for a query. v Stops the database manager from retrieving a block of data rows that is not used by the program when only the first few rows of a query are retrieved before the query is closed. v Can degrade the overall performance of a query that retrieves a large number of rows. *READ: Records are blocked for read-only retrieval of data for cursors when: v *NONE is specified on the COMMIT parameter, which indicates that commitment control is not used. v The cursor is declared with a FOR FETCH ONLY clause or there are no dynamic statements that could run a positioned UPDATE or DELETE statement for the cursor. Specifying *READ can improve the overall performance of queries that meet the above conditions and retrieve a large number of records. ERRLVL Specifies whether the processing is successful, based on the severity of the messages generated by the processing of the SQL statements. If errors that are greater than the value specified on this parameter occur during processing, no more statements are processed and the statements are rolled back if they are running under commitment control. 10: Statement processing is stopped when error messages with a severity level greater than 10 are received. severity-level: Specify the severity level to be used. DATFMT Specifies the format used when accessing date result columns. For input date strings, the specified value is used to determine whether the date is specified in a valid format. Note: An input date string that uses the format *USA, *ISO, *EUR, or *JIS is always valid. *JOB: The format specified for the job is used. Use the Display Job (DSPJOB) command to determine the current date format for the job. *USA: The United States date format (mm/dd/yyyy) is used. *ISO: The International Organization for Standardization (ISO) date format (yyyy-mm-dd) is used.

Appendix C. DB2 UDB for AS/400 CL Command Descriptions

317

RUNSQLSTM
*EUR: The European date format (dd.mm.yyyy) is used. *JIS: The Japanese Industrial Standard date format (yyyy-mm-dd) is used. *MDY: The date format (mm/dd/yy) is used. *DMY: The date format (dd/mm/yy) is used. *YMD: The date format (yy/mm/dd) is used. *JUL: The Julian date format (yy/ddd) is used. DATSEP Specifies the separator used when accessing date result columns. Note: This parameter applies only when *JOB, *MDY, *DMY, *YMD, or *JUL is specified on the DATFMT parameter. *JOB: The date separator specified for the job is used. Use the Display Job (DSPJOB) command to determine the current value for the job. /: A slash (/) is used. .: A period (.) is used. ,: A comma (,) is used. -: A dash (-) is used. : A blank ( ) is used. *BLANK: A blank ( ) is used. TIMFMT Specifies the format used when accessing time result columns. For input time strings, the specified value is used to determine whether the time is specified in a valid format. Note: An input date string that uses the format *USA, *ISO, *EUR, or *JIS is always valid. *HMS: The hh:mm:ss format is used. *USA: The United States time format hh:mm xx is used, where xx is AM or PM. *ISO: The International Organization for Standardization (ISO) time format hh.mm.ss is used. *EUR: The European time format hh.mm.ss is used. *JIS: The Japanese Industrial Standard time format hh:mm:ss is used. TIMSEP Specifies the separator used when accessing time result columns.

318

DB2 UDB for AS/400 SQL Programming Concepts V4R5

RUNSQLSTM
Note: This parameter applies only when *HMS is specified on the TIMFMT parameter. *JOB: The time separator specified for the job is used. Use the Display Job (DSPJOB) command to determine the current value for the job. :: A colon (:) is used. .: A period (.) is used. ,: A comma (,) is used. : A blank ( ) is used. *BLANK: A blank ( ) is used. DECMPT Specifies the decimal point value used for numeric constants in SQL statements. *JOB: The value used as the decimal point for numeric constants in SQL is the representation of decimal point specified by the job running the statement. *SYSVAL: The QDECFMT system value is used as the decimal point. *PERIOD: A period represents the decimal point. *COMMA: A comma represents the decimal point. SRTSEQ Specifies the sort sequence table to be used for string comparisons in SQL statements. *JOB: The LANGID value for the job is retrieved. *LANGIDSHR: The sort sequence table uses the same weight for multiple characters, and is the shared-weight sort sequence table associated with the language specified on the LANGID parameter. *LANGIDUNQ: The unique-weight sort table for the language specified on the LANGID parameter is used. *HEX: A sort sequence table is not used. The hexadecimal values of the characters are used to determine the sort sequence. The name of the table name can be qualified by one of the following library values: *LIBL: All libraries in the jobs library list are searched until the first match is found. *CURLIB: The current library for the job is searched. If no library is specified as the current library for the job, the QGPL library is used. library-name: Specify the name of the library to be searched. table-name: Specify the name of the sort sequence table to be used.

Appendix C. DB2 UDB for AS/400 CL Command Descriptions

319

RUNSQLSTM
LANGID Specifies the language identifier to be used when SRTSEQ(*LANGIDUNQ) or SRTSEQ(*LANGIDSHR) is specified. *JOB: The LANGID value for the job is retrieved during the precompile. language-identifier: Specify a language identifier. DFTRDBCOL Specifies the collection name used for the unqualified names of tables, views, indexes, and SQL packages. This parameter applies only to static SQL statements. *NONE: The naming convention defined on the OPTION parameter is used. collection-name: Specify the name of the collection identifier. This value is used instead of the naming convention specified on the OPTION parameter. FLAGSTD Specifies the American National Standards Institute (ANSI) flagging function. This parameter flags SQL statements to verify whether they conform to the following standards.
ANSI X3.135-1992 entry ISO 9075-1992 entry FIPS 127.2 entry

*NONE: The SQL statements are not checked to determine whether they conform to ANSI standards. *ANS: The SQL statements are checked to determine whether they conform to ANSI standards. SAAFLAG Specifies the IBM SQL flagging function. This parameter flags SQL statements to verify whether they conform to IBM SQL syntax More information about which IBM database products IBM SQL syntax is in the DRDA IBM SQL Reference, SC26-3255-00. *NOFLAG: The SQL statements are not checked to determine whether they conform to IBM SQL syntax. *FLAG: The SQL statements are checked to determine whether they conform to IBM SQL syntax. PRTFILE Specifies the qualified name of the printer device file to which the RUNSQLSTM printout is directed. The file must have a minimum length of 132 bytes. If a file with a record length of less than 132 bytes is specified, information is lost. The name of the printer file can be qualified by one of hte following library values: *LIBL: All libraries in the jobs library list are searched until the first match is found. *CURLIB: The current library for the job is searched. If no library is specified as the current library for the job, the QGPL library is used. library-name: Specify the name of the library to be searched.

320

DB2 UDB for AS/400 SQL Programming Concepts V4R5

RUNSQLSTM
QSYSPRT: If a file name is not specified, the RUNSQLSTM printout is directed to the IBM-supplied printer file QSYSPRT. printer-file-name: Specify the name of the printer device file to which the RUNSQLSTM printout is directed. Parameters for SQL procedures: The parameters listed below only apply to statements within the source file that create SQL procedures. The parameters are used during the creation of the program object associated with the SQL procedure. TGTRLS Specifies the release of the operating system on which the user intends to use the object being created. In the examples given for the *CURRENT value, and when specifying the release-level value, the format VxRxMx is used to specify the release, where Vx is the version, Rx is the release, and Mx is the modification level. For example, V2R3M0 is version 2, release 3, modification level 0. *CURRENT The object is to be used on the release of the operating system currently running on the users system. For example, if V2R3M5 is running on the system, *CURRENT means the user intends to use the object on a system with V2R3M5 installed. The user can also use the object on a system with any subsequent release of the operating system installed. Note: If V2R3M5 is running on the system, and the object is to be used on a system with V2R3M0 installed, specify TGTRLS(V2R3M0) not TGRRLS(*CURRENT). release-level: Specify the release in the format VxRxMx. The object can be used on a system with the specified release or with any subsequent release of the operating system installed. Valid values depend on the current version, release, and modification level, and they change with each new release. If you specify a release-level which is earlier than the earliest release level supported by this command, an error message is sent indicating the earliest supported release. CLOSQLCSR Specifies when SQL cursors are implicitly closed, SQL prepared statements are implicitly discarded, and LOCK TABLE locks are released. SQL cursors are explicitly closed when you issue the CLOSE, COMMIT, or ROLLBACK (without HOLD) SQL statements. *ENDACTGRP: SQL cursors are closed and SQL prepared statements are implicitly discarded. ENDMOD: SQL cursors are closed and SQL prepared statements are implicitly discarded when the module is exited. LOCK TABLE locks are released when the first SQL program on the call stack ends. OUTPUT Specifies whether the precompiler listing is generated. *NONE: The precompiler listing is not generated.
Appendix C. DB2 UDB for AS/400 CL Command Descriptions

321

RUNSQLSTM
*PRINT: The precompiler listing is generated. DBGVIEW Specifies the type of source debug information to be provided by the SQL precompiler. *NONE: The source view will not be generated. *STMT: Allows the compiled module to be debugged using program statement numbers and symbolic identifiers. *LIST: Generates the listing view for debugging the compiled module object. USRPRF Specifies the user profile that is used when the compiled program object is run, including the authority that the program object has for each object in static SQL statements. The profile of either the program owner or the program user is used to control which objects can be used by the program object. *NAMING: The user profile is determined by the naming convention. If the naming convention is *SQL, USRPRF(*OWNER) is used. If the naming convention is *SYS, USRPRF(*USER) is used. *USER: The profile of the user running the program object is used. *OWNER: The user profiles of both the program owner and the program user are used when the program is run. DYNUSRPRF Specifies the user profile to be used for dynamic SQL statements. *USER: For local, dynamic SQL statements run under the user of the programs user. For distributed, dynamic SQL statements run under the profile of the SQL packages user. *OWNER: For local, dynamic SQL statements run under the profile of the programs owner. For distributed, dynamic SQL statements run under the profile of the SQL packages owner. DLYPRP Specifies whether the dynamic statement validation for a PREPARE statement is delayed until an OPEN, EXECUTE, or DESCRIBE statement is run. Delaying validation improves performance by eliminating redundant validation. *NO: Dynamic statement validation is not delayed. When the dynamic statement is prepared, the access plan is validated. When the dynamic statement is used in an OPEN or EXECUTE statement, the access plan is revalidated. Because the authority or the existence of objects referred to by the dynamic statement may change, you must still check the SQLCODE or SQLSTATE after issuing the OPEN or EXECUTE statement to ensure that the dynamic statement is still valid. *YES: Dynamic statement validation is delayed until the dynamic statement is used in an OPEN, EXECUTE, or DESCRIBE SQL statement. When the dynamic statement is used, the validation is completed and an access plan is built. If you specify *YES on this parameter, you should check the SQLCODE and SQLSTATE after running an OPEN, EXECUTE, or DESCRIBE statement to ensure that the dynamic statement is valid.

322

DB2 UDB for AS/400 SQL Programming Concepts V4R5

RUNSQLSTM
Note: If you specify *YES, performance is not improved if the INTO clause is used on the PREPARE statement or if a DESCRIBE statement uses the dynamic statement before an OPEN is issued for the statement. Example:
RUNSQLSTM SRCFILE(MYLIB/MYFILE) SRCMBR(MYMBR)

This command processes the SQL statements in member MYMBR found in file MYFILE in library MYLIB.

STRSQL (Start Structured Query Language) Command


Job: I Pgm: I REXX: I Exec
*SYS *SQL

STRSQL *NC *NONE *CHG *UR *CS *RS *ALL *RR NAMING( ) )

COMMIT(

PROCESS(

*RUN *VLD *SYN

LIBOPT(

*LIBL *CURLIB *USRLIBL *ALL *ALLUSR library-name

(1) *ALL *SQL *ALWAYS *FORWARD

LISTTYPE(

REFRESH(

ALWCPYDTA(

*YES *OPTIMIZE *NO

DATFMT(

*JOB *USA *ISO *EUR *JIS *MDY *DMY *YMD *JUL

Appendix C. DB2 UDB for AS/400 CL Command Descriptions

323

STRSQL
(2) DATSEP( *JOB *BLANK / . , - *HMS *USA *ISO *EUR *JIS

TIMFMT(

(3) TIMSEP(

*JOB *BLANK : . ,

DECPNT(

*SYSVAL *PERIOD *COMMA *JOB

(4) PGMLNG(

*NONE *C *CBL *PLI *RPG *FTN

(5) SQLSTRDLM(

(6)

*QUOTESQL *APOSTSQL

SRTSEQ(

*JOB *JOBRUN *LANGIDUNQ *LANGIDSHR *HEX *LIBL/ table-name *CURLIB/ library-name/

LANGID(

*JOB *JOBRUN language-ID

Notes: 1 2 3 4 All parameters preceding this point can be specified in positional form. DATSEP is only valid when *MDY, *DMY, *YMD, or *JUL is specified on the DATFMT parameter. TIMSEP is only valid when TIMFMT(*HMS) is specified. PGMLNG and SQLSTRDLM are valid only when PROCESS(*SYN) is specified.

324

DB2 UDB for AS/400 SQL Programming Concepts V4R5

STRSQL
5 6 PGMLNG and SQLSTRDLM are valid only when PROCESS(*SYN) is specified. SQLSTRDLM is valid only when PGMLNG(*CBL) is specified.

Purpose: The Start Structured Query Language (STRSQL) command starts the interactive Structured Query Language (SQL) program. The program starts the statement entry of the interactive SQL program which immediately shows the Enter SQL Statements display. This display allows the user to build, edit, enter, and run an SQL statement in an interactive environment. Messages received during the running of the program are shown on this display. Parameters: COMMIT Specifies whether the SQL statements are run under commitment control. *NONE or *NC: Specifies that commitment control is not used. Uncommitted changes in other jobs can be seen. If the SQL DROP COLLECTION statement is included in the program, *NONE or *NC must be used. If a relational database is specified on the RDB parameter and the relational database is on a system that is not on an AS/400, *NONE or *NC cannot be specified. *CHG or *UR: Specifies the objects referred to in SQL ALTER, CALL, COMMENT ON, CREATE, DROP, GRANT, LABEL ON, RENAME, and REVOKE statements and the rows updated, deleted, and inserted are locked until the end of the unit of work (transaction). Uncommitted changes in other jobs can be seen. *CS: Specifies the objects referred to in SQL ALTER, CALL, COMMENT ON, CREATE, DROP, GRANT, LABEL ON, RENAME, and REVOKE statements and the rows updated, deleted, and inserted are locked until the end of the unit of work (transaction). A row that is selected, but not updated, is locked until the next row is selected. Uncommitted changes in other jobs cannot be seen. *ALL or *RS: Specifies the objects referred to in SQL ALTER, CALL, COMMENT ON, CREATE, DROP, GRANT, LABEL ON, RENAME, and REVOKE statements and the rows selected, updated, deleted, and inserted are locked until the end of the unit of work (transaction). Uncommitted changes in other jobs cannot be seen. *RR: Specifies the objects referred to in SQL ALTER, CALL, COMMENT ON, CREATE, DROP, GRANT, LABEL ON, RENAME, and REVOKE statements and the rows selected, updated, deleted, and inserted are locked until the end of the unit of work (transaction). Uncommitted changes in other jobs cannot be seen. All tables referred to in SELECT, UPDATE, DELETE, and INSERT statements are locked exclusively until the end of the unit of work (transaction). Note: The default for this parameter for the CRTSQLXXX commands (when XXX=CI, CPPI, CBL, FTN, PLI, CBLI, RPG or RPGI) is *CHG. NAMING Specifies the naming convention used for naming objects in SQL statements.

Appendix C. DB2 UDB for AS/400 CL Command Descriptions

325

STRSQL
*SYS: The system naming convention (library-name/file-name) is used. *SQL: The SQL naming convention (collection-name.table-name) is used. PROCESS Specifies the values used to process the SQL statements. *RUN: The statements are syntax checked, data checked, and then run. *VLD: The statements are syntax checked and data checked, but not run. *SYN: The statements are syntax checked only. LIBOPT Specifies which collections and libraries are used as a basis for building a collection list when the F4, F16, F17, or F18 function key is pressed. The name of the collection list can be qualified by one of the following library values: *LIBL: All libraries in the jobs library list are searched until the first match is found. *CURLIB: The current library for the job is searched. If no library is specified as the current library for the job, the QGPL library is used. *USRLIBL: Only the libraries in the user portion of the jobs library list are searched. *ALL: All libraries in the system, including QSYS, are searched. *ALLUSR: All user libraries are searched. All libraries with names that do not begin with the letter Q are searched except for the following:
#CGULIB #COBLIB #DFULIB #DSULIB #RPGLIB #SDALIB #SEULIB

Although the following Qxxx libraries are provided by IBM, they typically contain user data that changes frequently. Therefore, these libraries are considered user libraries and are also searched:
QDSNX QGPL QGPL38 QPFRDATA QRCL QS36F QUSER38 QUSRADSM QUSRBRM QUSRIJS QUSRINFSKR QUSRRDARS QUSRSYS QUSRVxRxMx

Note: A different library name, of the form QUSRVxRxMx, can be created by the user for each release that IBM supports. VxRxMx is the version, release, and modification level of the library. library-name: Specify the name of the library to be searched. LISTTYPE Specifies the types of objects that are displayed with list support by pressing the F4, F16, F17, or F18 function key. *ALL: All objects are displayed. *SQL: Only SQL-created objects are displayed. REFRESH Specifies when the display select output data is refreshed.

326

DB2 UDB for AS/400 SQL Programming Concepts V4R5

STRSQL
*ALWAYS: Data is normally refreshed during forward and backward scrolling. *FORWARD: Data is refreshed only during forward scrolling to the end of the data for the first time. When scrolling backward, a copy of the data already viewed is shown. ALWCPYDTA Specifies whether a copy of the data can be used in a SELECT statement. If COMMIT(*ALL) is specified, SQL run time ignores the ALWCPYDTA value and uses current data. *YES: A copy of the data is used when necessary. *OPTIMIZE: The system determines whether to use the data retrieved from the database or to use a copy of the data. The determination is based on which will provide the best performance. *NO: A copy of the data is not allowed. If a temporary copy of the data is required to perform the query, an error message is returned. DATFMT Specifies the date format used in SQL statements. *JOB: The format specified on the job attribute DATFMT is used. *USA: The United States date format (mm/dd/yyyy) is used. *ISO: The International Standards Organization date format (yyyy-mm-dd) is used. *EUR: The European date format (dd.mm.yyyy) is used. *JIS: The Japanese Industry Standard Christian Era date format (yyyy-mm-dd) is used. *MDY: The month, day, and year date format (mm/dd/yy) is used. *DMY: The day, month, and year date format (dd/mm/yy) is used. *YMD: The year, month, and day date format (yy/mm/dd) is used. *JUL: The Julian date format (yy/ddd) is used. DATSEP Specifies the date separator used in SQL statements. *JOB: The date separator specified on the job attribute is used. If the user specifies *JOB on a new interactive SQL session, the current value is stored and used. Later changes to the jobs date separator are not detected by interactive SQL. *BLANK: A blank ( ) is used. /: A slash (/) is used. .: A period (.) is used.

Appendix C. DB2 UDB for AS/400 CL Command Descriptions

327

STRSQL
,: A comma (,) is used. -: A dash (-) is used. : A blank ( ) is used. TIMFMT Specifies the time format used in SQL statements. *HMS: The Hour-Minute-Second time format (hh:mm:ss) is used. *USA: The United States time format (hh:mm xx, where xx is AM or PM) is used. *ISO: The International Standards Organization time format (hh.mm.ss) is used. *EUR: The European time format (hh.mm.ss) is used. *JIS: The Japanese Industry Standard Christian Era time format (hh:mm:ss) is used. TIMSEP Specifies the time separator used in SQL statements. *JOB: The time separator specified on the job attribute is used. If the user specifies *JOB on a new interactive SQL session, the current value is stored and used. Later changes to the jobs time separator are not detected by interactive SQL. *BLANK: A blank ( ) is used. :: A colon (:) is used. .: A period (.) is used. ,: A comma (,) is used. : A blank ( ) is used. DECPNT Specifies the kind of decimal point to use. *JOB: The value used as the decimal point for numeric constants in SQL is the representation of decimal point specified for the job running the statement. *SYSVAL: The decimal point is extracted from the system value. If the user specifies *SYSVAL on a new interactive SQL session, the current value is stored and used. Later changes to the systems time separator are not detected by interactive SQL. *PERIOD: A period represents the decimal point. *COMMA: A comma represents the decimal point. PGMLNG Specifies which program language syntax rules to use. To use this parameter, *SYN must be selected at the PROCESS parameter.

328

DB2 UDB for AS/400 SQL Programming Concepts V4R5

STRSQL
*NONE: No specific languages syntax check rules are used. The supported languages are: *C: Syntax checking is done according to the C language syntax rules. *CBL: Syntax checking is done according to the COBOL language syntax rules. *PLI: Syntax checking is done according to the PL/I language syntax rules. *RPG: Syntax checking is done according to the RPG language syntax rules. *FTN: Syntax checking is done according to the FORTRAN language syntax rules. SQLSTRDLM Specifies the SQL string delimiter. Use of this parameter requires using the COBOL (*CBL) character set. *QUOTESQL: A quotation mark represents the SQL string delimiter. *APOSTSQL: An apostrophe represents the SQL string delimiter. SRTSEQ Specifies the sort sequence table to be used for string comparisons in SQL statements on the Enter SQL Statements display. *JOB: The SRTSEQ value for the job is retrieved. *JOBRUN: The SRTSEQ value for the job is retrieved each time the user starts interactive SQL. *LANGIDUNQ: The unique-weight sort table for the language specified on the LANGID parameter is used. *LANGIDSHR: The shared-weight sort table for the language specified on the LANGID parameter is used. *HEX: A sort sequence table is not used. The hexadecimal values of the characters are used to determine the sort sequence. The name of the table name can be qualified by one of the following library values: *LIBL: All libraries in the jobs library list are searched until the first match is found. *CURLIB: The current library for the job is searched. If no library is specified as the current library for the job, the QGPL library is used. library-name: Specify the name of the library to be searched. table-name: Specify the name of the sort sequence table to be used with the interactive SQL session. LANGID Specifies the language identifier to be used when SRTSEQ(*LANGIDUNQ) or SRTSEQ(*LANGIDSHR) is specified. *JOB: The LANGID value for the job is retrieved.
Appendix C. DB2 UDB for AS/400 CL Command Descriptions

329

STRSQL
*JOBRUN: The LANGID value for the job is retrieved each time interactive SQL is started. language-ID: Specify the language identifier to be used. Example:
STRSQL PROCESS(*SYN) NAMING(*SQL) DECPNT(*COMMA) PGMLNG(*CBL) SQLSTRDLM(*APOSTSQL)

This command starts an interactive SQL session that checks only the syntax of SQL statements. The character set used by the syntax checker uses the COBOL language syntax rules. The SQL naming convention is used for this session. The decimal point is represented by a comma, and the SQL string delimiter is represented by an apostrophe.

330

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Bibliography
This guide lists publications that provide additional information about topics described or referred to in this guide. The manuals in this section are listed with their full title and order number, but when referred to in text, a shortened version of the title is used. v Backup and Recovery, SC41-5304-04 This guide contains a subset of the information found in the Backup and Recovery book The manual contains information about planning a backup and recovery strategy, the different types of media available to save and restore procedures, and disk recovery procedures. It also describes how to install the system again from backup. v File Management This guide provides information about using files in application programs. v Database Programming This guide provides a detailed description of the DB2 UDB for AS/400 database organization, including information on how to create, describe, and update database files on the system. v CL Programming, SC41-5721-03 This guide provides a wide-ranging discussion of the AS/400 programming topics, including a general discussion of objects and libraries, CL programming, controlling flow and communicating between programs, working with objects in CL programs, and creating CL programs. Other topics include predefined and impromptu messages and handling, defining and creating user-defined commands and menus, application testing, including debug mode, breakpoints, traces, and display functions. v Control Language (CL) This guide provides a description of the AS/400 control language (CL) and its OS/400 commands. (Non-OS/400 commands are described in the respective licensed program publications.) It also provides an overview of all the CL commands for the AS/400 system, and it describes the syntax rules needed to code them. v Security - Reference, SC41-5302-04 This guide provides information about system security concepts, planning for security, and setting up security on the system. It also gives information about protecting the system and data from being used by people who do not have the proper authorization, protecting the data from intentional or unintentional damage or destruction, keeping security up-to-date, and setting up security on the system. v SQL Reference This guide provides information about DB2 UDB for AS/400 statements and their parameters. It also includes an appendix describing the SQL communications area (SQLCA) and SQL description area (SQLDA). v IDDU Use, SC41-5704-00 This guide describes how to use DB2 UDB for AS/400 interactive data definition utility (IDDU) to describe data dictionaries, files, and records to the system. v DATABASE 2/400 Advanced Database Functions, GG24-4249 This guide provides suggestions, guidelines, and practical examples of when and how functions offered by DB2 UDB for AS/400 such as triggers, referential integrity, DRDA-2, 2-phase commit, and stored procedures, can be effectively used. The book reports examples developed in several programming languages (RPG, COBOL, C), using native and SQL data access interface, both in the Integrated Language Environment and with the Original Program Model. v ILE COBOL for AS/400 Programmers Guide, SC09-2540-01 This guide provides information you need to design, write, test, and maintain COBOL for AS/400 programs on the AS/400 system. v ILE RPG for AS/400 Programmers Guide, SC09-2507-02 This guide provides information you need to design, write, test, and maintain ILE RPG for AS/400 programs on the AS/400 system. v ILE C for AS/400 Run-Time Library Reference, SC09-2711-01 This guide provides information you need to design, write, test, and maintain ILE C for AS/400 programs on the AS/400 system.

Copyright IBM Corp. 2000

331

v ILE C for AS/400 Programmers Guide, SC09-2712-01 This guide provides information you need to design, write, test, and maintain ILE C for AS/400 programs on the AS/400 system. v ILE COBOL for AS/400 Reference, SC09-2539-01 This guide provides information you need to design, write, test, and maintain COBOL for AS/400 programs on the AS/400 system. v REXX/400 Programmers Guide, SC41-5728-00 This guide provides information you need to design, write, test, and maintain REXX/400 programs on the AS/400 system. v PL/I Users Guide and Reference, SC09-1825 This guide provides information about using AS/400 PL/I in the System/38 environment. Differences between the System/38 environment and the AS/400 environment are identified as well as the enhancements available in the AS/400 environment. DB2 Multisystem This guide describes the fundamental concepts of distributed relational database files, nodegroups, and partitioning. The book provides the information you need to create and use database files that are partitioned across multiple AS/400 systems. Information is provided on how to configure the systems, how to create the files, and how the files can be used in applications. Performance Tools for AS/400, SC41-5340-00 This guide provides the programmer with the information needed to collect data about the system, job, or program performance. This book also has tips for printing and analyzing performance data to identify and correct inefficiencies that might exist. Information about the manager and agent feature is included. SQL Call Level Interface (ODBC) This guide provides the information necessary for application programmers to write applications using the DB2 call level interface. AS/400 Developer Kit for Java This guide provides information you need to design, write, test, and maintain Java programs on the AS/400 system. It also contains a chapter, AS/400 Developer Kit for Java JDBC driver, which provides information about accessing AS/400 database files from Java programs by using JDBC or SQLj.

332

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Index Special Characters


% (percent sign) use with LIKE 73 arithmetic error in UDFs 192, 195 arithmetic expression error 37, 38 arranging rows 41 assignments in dynamic SQL example 179 assignments involving different UDTs example 180 assignments involving UDTs example 179 asterisk (select all columns) 38 atomic operation data definition statements (DDL) 243 data integrity 243 definition 243 Auditing C2 security 236 authority, public 235 authorization Create SQL Package (CRTSQLPKG) command 260 for creating package 259 for running using a package 259 ID 236 testing 249, 250 auxiliary storage pools 239, 247 AVG over a UDT example 167 CCSID connection to non-DB2 UDB for AS/400 263 delimited identifier effect 263 dynamic SQL statement 202 package considerations 263 Change Class (CHGCLS) command 237 change information in table host variables 33, 34 Change Job (CHGJOB) command 237 Change Logical File (CHGLF) command 237 Change Physical File (CHGPF) command 237 change session attributes interactive SQL 227 changing data 33 information in a table 25 table definition 92, 256 changing a column 93 Character Large OBjects 150 check constraints 99 check pending 107, 245 checking syntax in interactive SQL 223 CHGPF command 33 CL_SCHED table 287 class schedule table 287 clause 47 AND 74 DISTINCT 72 FROM 36 GROUP BY example 41 HAVING 42 INTO example 32 PREPARE statement, use with 205 restriction 210 NOT 74 null value 45 OR 74 ORDER BY 43 SELECT 38 SET 33 USING DESCRIPTOR 215 VALUES 31 WHENEVER NOT FOUND 60 WHERE character string 31 example 38, 215 expression 39 joining tables 76 multiple search condition within 74 NOT keyword 40 WHERE CURRENT OF 61 CLI 2

A
access plan definition 11 in a package 12 in a program 11 accessing remote databases interactive SQL 229 activation groups connection management example 263 add row to table 32 adding a column 92 adding data to end of table 254 adding indexes 96 address variable, in dynamic SQL 199 advanced coding technique complex search condition 72 inserting multiple rows into a table 69 joining data from multiple tables 75 aggregating functions 163 ALIAS names creating 48 ALIAS statement 48 ALL 86 allocating storage for SQLDA 210 ALTER TABLE 92 AND keyword description 74 multiple search condition 74 ANY 86 API QSQCHKS 2 QSQPRCED 2 application dynamic SQL designing and running 201 overview 199 application design user-defined function (UDF) 189 application domain and object-orientation 149 application forms using CREATE TABLE example 175 application program creating 9 testing SQL statements in 249 application requester 257 application requester driver (ARD) programs package creation 279 running statements 279 application server 257 ARD (application requester driver) programs 279 Copyright IBM Corp. 2000

B
basic SQL statements and clauses 31 BETWEEN clause, multiple search condition 72 BETWEEN keyword 72 bibliography 331 Binary Large OBjects 150 BLOBs (Binary Large OBjects) uses and definition 150 blocked insert statement 70

C
C2 security auditing 236 call level interface 2 call-type contents with table functions 194 call-type, passing to UDF 194 CAST FROM clause 192, 194, 195 castability 161 casting, UDFs 172 catalog database design, use in 97 definition 6 getting information about 97 column 97 integrity 247 LABEL ON information 48 QSYS2 views 6 table 97

333

CLOBs (Character Large OBjects) uses and definition 150 CLOSQLCSR parameter effect on implicit disconnect 267 coded character set conversion error 38 coding techniques 31, 55, 69 collating rows 41 collection changing table definition 256 creating 13 definition 3, 6 solving problem paging through retrieved data 253 retrieving data a second time 256 column adding 92 defining heading 16, 48 definition 3, 6 deleting 94 FOR UPDATE OF clause 58 getting catalog information about 97 name definition 39 SET clause, value 33 updating view 29 column definition changing 93 column functions 163 combining information from multiple tables 23 SELECT statement 80 subselect with UNION example 80 command RUNSQLSTM errors 232 command, CL Create Structured Query Language Package (CRTSQLPKG) 308 CRTSQLPKG (Create Structured Query Language Package) 308 Delete Structured Query Language Package (DLTSQLPKG) 311 DLTSQLPKG (Delete Structured Query Language Package) 311 command (CL) Change Class (CHGCLS) 237 Change Job (CHGJOB) 237 Change Logical File (CHGLF) 237 Change Physical File (CHGPF) 237 CHGCLS (Change Class) 237 CHGJOB (Change Job) 237 CHGLF (Change Logical File) 237 CHGPF (Change Physical File) 237 Create Duplicate Object (CRTDUPOBJ) 250 Create SQL Package (CRTSQLPKG) 259, 311 Create User Profile (CRTUSRPRF) 236 CRTDUPOBJ (Create Duplicate Object) command 250 CRTUSRPRF (Create User Profile) 236 Delete Library (DLTLIB) 244

command (CL) (continued) Delete SQL Package (DLTSQLPKG) 259, 312 Display Message Description (DSPMSGD) 289 DLTLIB (Delete Library) 244 DSPMSGD (Display Message Description) 289 Edit Check Pending Constraints (EDTCPCST) 245 Edit Rebuild of Access Paths (EDTRBDAP) 245 Edit Recovery for Access Paths (EDTRCYAP) 246 EDTCPCST (Edit Check Pending Constraints) 245 EDTRBDAP (Edit Rebuild of Access Paths) 245 EDTRCYAP (Edit Recovery for Access Paths) 246 Grant Object Authority (GRTOBJAUT) 235 GRTOBJAUT (Grant Object Authority) 235, 237 Override Database File (OVRDBF) 62, 237 OVRDBF (Override Database File) 62, 237 Reclaim DDM connections (RCLDDMCNV) 275 Retrieve Message (RTVMSG) 289 Revoke Object Authority (RVKOBJAUT) 235 RTVMSG (Retrieve Message) 289 Run SQL Statements (RUNSQLSTM) 2 RUNSQLSTM (Run SQL statements) 2 RUNSQLSTM (Run SQL Statements) 231, 323 RVKOBJAUT (Revoke Object Authority) 235 Send Program Message (SNDPGMMSG) 289 Send User Message (SNDUSRMSG) 289 SNDPGMMSG (Send Program Message) 289 SNDUSRMSG (Send User Message) 289 Start Commitment Control (STRCMTCTL) 240 Start Journal Access Path (STRJRNAP) 246 STRCMTCTL (Start Commitment Control) 240 STRJRNAP (Start Journal Access Path) 246 STRSQL (Start SQL) 330 comment for RUNSQLSTM 231 getting 49 COMMENT ON statement using, example 49 COMMIT keyword 240 prepared statements 203

COMMIT (continued) statement 261 statement description 6 commitment control activation group example 263 committable updates 269 description 239 distributed connection restrictions 272 DRDA resource 269 INSERT statement 33 job-level commitment definition 267, 272 protected resource 269 rollback required 274 RUNSQLSTM command 232 SQL statement processor 232 sync point manager 269 two-phase commit 269 unprotected resource 269 common database problem solving 253 comparison operators 40 comparisons involving UDTs example 177, 178 compiled application program object managing object 9 output source file member 11 program 9 user source file member 11 compiling application program object output source file member 11 program 11 user source file member 11 compiling a UDF 164 completing a unit of work 67 complex search condition keyword for use in 72 multiple search condition 72 performing 72 WHERE clause 31 concurrency data 237 definition 237 condition keyword for use in search 72 multiple search within a WHERE clause 74 performing complex search 72 CONNECT statement 257, 261 interactive SQL 230 connection DDM 275 determining type 269 ending DDM 275 protected 269 unprotected 269 connection management ARD programs 279 commitment control restrictions 272 distributed unit of work considerations 274 ending connections DDMCNV effect on 275 DISCONNECT statement 275

334

DB2 UDB for AS/400 SQL Programming Concepts V4R5

connection management (continued) RELEASE statement 275 example 263 implicit connection default activation group 267 nondefault activation group 268 implicit disconnection default activation group 267 nondefault activation group 268 multiple connections to same relational database 267 connection status determining 273 example 278 consistency token 262 consistent behavior and UDTs 173 constant definition 40 SET clause, value 33 constraint 245 definition 8 referential 8 unique 8 constraint mechanisms on large objects 149 constraints check 99 referential check pending 107 creating tables 100 delete rules 105 deleting from tables 105 inserting into tables 102 removing 102 update rules 104 updating tables 103 control, commitment 239 control information to access large object data 151 control structures 12 convention SQL naming 4 system naming 3 conversion error 37 CORPDATA.DEPARTMENT (department) 281 CORPDATA.EMP_ACT (employee to project activity) 283 CORPDATA.EMP_ACT table 283 CORPDATA.EMPLOYEE table 282 CORPDATA.PROJECT (project) 286 CORPDATA.PROJECT table 286 correlated names 90 references 90 correlated subquery definition 88 DELETE statement, use in 91 examples HAVING clause 90 UPDATE statement 91 WHERE clause 88 note on using 92 correlation definition 85 name 23, 79 using subquery 85

cost of a UDT example 167 counter for UDFs example 198 counting and defining UDFs example 168 CREATE COLLECTION statement 13 CREATE DISTINCT TYPE statement and castability 161 examples of using 175 to define a UDT 174 Create Duplicate Object (CRTDUPOBJ) command 250 CREATE FUNCTION statement 194 to register a UDF 165 CREATE INDEX sort sequence 53 CREATE SCHEMA statement 232 Create SQL Package (CRTSQLPKG) command 259, 311 authority required 260 Create Structured Query Language Package (CRTSQLPKG) command 308 CREATE TABLE prompting 223 CREATE TABLE statement 14 examples of using 175 Create User Profile (CRTUSRPRF) command 236 CREATE VIEW statement 29 creating index example 96 SQL collection example 13 structured query language package 308 table description 14 example 14 view 95 description 28 on a table 29 over multiple tables 30 creating ALIAS names 48 cross join 78 CRTDUPOBJ (Create Duplicate Object) command 250 CRTSQLPKG (Create SQL Package) command 311 CRTSQLPKG (Create Structured Query Language Package) command 308 CRTSQLxxx commands 3 CRTUSRPRF command create user profile 236 ctr() UDF C program listing 198 CURDATE scalar function 46 CURRENT DATE special register 45 current row 60 CURRENT SERVER special register 45 current session printing 227 removing all entries from 227 CURRENT TIME special register 45 CURRENT TIMESTAMP special register 45 CURRENT TIMEZONE special register 45

cursor distributed unit of work 278 example overview 56 example steps 58, 62 open 59 open, effect of recovery on 67 retrieving SELECT statement result 214 scrollable positioning within a table 55 serial positioning within a table 55 using 55 WITH HOLD clause 67 CURTIME scalar function 46

D
damage tolerance 246 data adding to the end of table 254 paging retrieved 253 retrieving in reverse order 253 updating as it is retrieved 254 previously retrieved 256 view, processing 36 data definition statement (DDL) 4 data dictionary WITH DATA DICTIONARY clause CREATE COLLECTION statement 6 CREATE SCHEMA statement 6 data independence 32, 38 data integrity 99 atomic operation 243 commitment control 239 concurrency 237 constraint 245 damage tolerance 246 data definition statements (DDL) 243 function 237 index recovery 246 journaling 239 save/restore 245 data manipulation statement (DML) 4 data mapping error 37 data protection 235 data types BLOBs 150 CLOBs 150 DBCLOBs 150 object-oriented 149 database design, using the catalog in 97 relational 3 date format 47 specifying current value 47 date/time arithmetic 47 DB2 Multisystem 2 DB2 Query Manager for AS/400 2 DB2 UDB for AS/400 1 distributed relational database support 257 DB2 UDB for AS/400 sample table 281 Index

335

DB2 UDB Query Manager and SQL Development Kit 1 distributed relational database support 257 DB2 UDB Symmetric Multiprocessing 2 DB2 Universal Database considerations for packages 260 DBCLOBs (Double-Byte Character Large OBjects) uses and definition 150 DBCS (double-byte character set) considerations in interactive SQL 223 DBGVIEW(*SOURCE) parameter 250 dbinfo, passing to UDF 194 DBINFO keyword 194 dbminfo argument, elements of 194 deadlock detection 238 debugging 249 common database problem 253 program 250 DECLARE CURSOR statement using 36 DECLARE statement 200 default collection name (DFTRDBCOL) parameter 3 DEFAULT keyword SET clause, value 34 default value 14, 18, 32 inserting in a view 95 define cursor 58 defining column heading 16, 48 table name 48 defining the UDT and UDFs example 181 definitions 257 access plan 11 authorization ID 3 authorization name 3 catalog 6 collection 3, 6 column 3, 6 column name 39 concurrency 237 constant 40 constraint 8 correlated subquery 88 correlation 85 CURRENT DATE special register 45 current row 60 CURRENT SERVER special register 45 CURRENT TIME special register 45 CURRENT TIMESTAMP special register 45 CURRENT TIMEZONE special register 45 data definition statement (DDL) 4 data dictionary 6 data manipulation statement (DML) 4 distributed unit of work 257 expression 39 field 3 host variable 40 index 8

definitions 257 (continued) join 30 join operation 23 journal 6 journal receiver 6 library 3 logical file 3 null value 45 NULL value 40 outer-level SELECT 84 output source file member 11 package 3, 9, 12, 259 physical file 3 predicate 38 program 11 record 3 referential integrity 8 remote unit of work 257 row 3, 6 search condition 38 special register 40 SQL package 3 SQLCODE 289 SQLSTATE 289 stored procedure 8 subquery 84 table 3, 6 trigger 8 user profile 3 user source file member 11 USER special register 45 view 3, 7 delete current row 61 Delete Library (DLTLIB) command 244 Delete SQL Package (DLTSQLPKG) command 259, 312 DELETE statement correlated subquery, use in 91 description 28, 34 Delete Structured Query Language Package (DLTSQLPKG) command 311 deleting structured query language package 311 deleting a column 94 deleting information in a table 28 department table CORPDATA.DEPARTMENT 281 DESCRIBE statement use with dynamic SQL 203 DESCRIBE TABLE statement 261 description SQLCODEs and SQLSTATEs 291 designing dynamic SQL application 201 DFT_SQLMATHWARN configuration parameter 192, 195 DFTRDBCOL (default collection name) parameter 3 diagnostic-message, passing to UDF 193 DISCONNECT statement 257, 261 ending connection 275 Display Message Description (DSPMSGD) command 289 displaying SQLCODE and SQLSTATE description 289 DISTINCT 71

DISTINCT 71 (continued) clause 72 keyword 255 distinct type 161 distributed relational database accessing remote databases 229 application requester 257 application server 257 committable updates 269, 273 connection management 263 multiple connections 267 connection restrictions 272 connection type determining 269 protected 269 unprotected 269 consideration for creating packages 260 creating packages 260 DB2 UDB for AS/400 support 257 determining connection status 273 distributed RUW example program 258 distributed unit of work 257, 268, 276 ending connections DDMCNV effect on 275 DISCONNECT statement 275 RELEASE statement 275 first failure data capture (FFDC) 279 implicit connection default activation group 267 nondefault activation group 268 implicit disconnection default activation group 267 nondefault activation group 268 interactive SQL 229 packages 259 statement in 260 precompiler diagnostic messages 260 problem handling 279 protected connection 269 protected resource 269 remote unit of work 257, 268 rollback required state 274 session attributes 230 SQL packages 259 sync point manager 269 two-phase commit 269 unprotected connection 269 unprotected resource 269 valid SQL statements 260 Distributed Relational Database Architecture (DRDA) 1 distributed unit of work 257, 268, 276 connection considerations 274 connection status 273 connection type 269 cursors 278 prepared statements 278 sample program 276 DLTSQLPKG (Delete SQL Package) command 312 DLTSQLPKG (Delete Structured Query Language Package) command 311 Double-Byte Character Large OBjects 150

336

DB2 UDB for AS/400 SQL Programming Concepts V4R5

DRDA (Distributed Relational Database Architecture) 257 DRDA level 1 268 DRDA level 2 268 DRDA resource 269 DROP PACKAGE statement 257 duplicate rows eliminating 81 preventing 71 DUW (distributed unit of work) 257 dynamic SQL address variable 199 allocating storage 205 application 199, 201 building and running statements 199 CCSID 202 cursor, use in 204 DESCRIBE statement 203 EXECUTE statement 201 fixed-list SELECT statement, using 204 parameter marker 215 PREPARE statement 201 processing non-SELECT statements 202 replacing parameter markers with host variables 216 run-time overhead 199 statements 4 varying-list SELECT statement 203

E
Edit Check Pending Constraints (EDTCPCST) command 245 Edit Rebuild of Access Paths (EDTRBDAP) command 245 Edit Recovery for Access Paths (EDTRCYAP) command 246 eliminating duplicate rows 81 employee-to-project activity table 283 encapsulation and UDTs 173 end-of-data reached 59 entering DBCS data 223 ERRLVL 232 error data mapping ORDER BY 37 error determination in distributed relational database first failure data capture (FFDC) 279 establishing position at end of table 253 examples 49 AND 74 application forms using CREATE TABLE 175 assignments in dynamic SQL 179 assignments involving different UDTs 180 assignments involving UDTs 179 AVG over a UDT 167 BETWEEN 72 catalog getting column information 97

examples 49 (continued) catalog (continued) getting table information 97 changing information in a table 25 changing rows in table host variables 33, 34 COMMENT ON 49 comparisons involving UDTs 177, 178 correlated subquery HAVING clause 90 WHERE clause 88 correlation name 23 cost of a UDT 167 counter for UDFs 198 counting and defining UDFs 168 creating index 96 SQL collection 13 table 14 view on a table 29 views over multiple tables 30 ctr() UDF C program listing 198 CURRENT DATE 47 CURRENT TIMEZONE 47 cursor 56 cursor in DUW program 278 defining stored procedures with CREATE PROCEDURE 118 defining the UDT and UDFs 181 deleting information in a table 28 determining connection status 278 distributed RUW program 258 distributed unit of work program 276 dynamic CALL 127 embedded CALL 124, 125 EXISTS 87 exploiting LOB function to populate the database 182 exploiting LOB locators to manipulate UDT instances 183 exploiting UDFs to query instances of UDTs 183 exponentiation and defining UDFs 165 extracting a document to a file (CLOB elements in a table) 156 function invocations 169 getting catalog information about column 97 table 97 getting comment 49 getting information about column using catalog 97 table using catalog 97 getting information from multiple tables 23 single table 20 IN 73 inserting add row to table 32 multiple rows into a table 69 inserting data into a CLOB column 158 invoking stored procedures 127

examples 49 (continued) where a CREATE PROCEDURE exists 124 where no CREATE PROCEDURE exists 125 join 76 LABEL ON statement 16, 48 LIKE 73 list function in interactive SQL 224 LOBFILE.SQB COBOL program listing 157 LOBFILE.SQC C program listing 157 LOBLOC.SQB COBOL program listing 154 LOBLOC.SQC C program listing 153 money using CREATE DISTINCT TYPE 175 multiple search condition (WHERE clause) 74 OR 74 ORDER BY sort sequence 51 parameter markers in functions 169 preventing duplicate rows 71 QSYSPRT listing SQL statement processor 233 removing information from table 28, 35 resume using CREATE DISTINCT TYPE 175 returning completion status to calling program 136 sales using CREATE TABLE 175 sample table 281 search 72 search string and BLOBs 166 SELECT records sort sequence 52 SELECT statement allocating storage for SQLDA 210 selecting into table host variables 36 special register 47 stored procedures returning completion status 136 string search and defining UDFs 166 string search over UDT 167 subquery 84 Union simple 83 UNION using host variables 81 UNION ALL using host variables 83 unqualified function reference 170 UPDATE statement 25 use of UDTs in UNION 180 user-defined sourced functions on UDTs 178 using a locator to work with a CLOB value 152 using index 96 using qualified function reference 170 view sort sequence 53

Index

337

examples 49 (continued) WITH CASCADED CHECK OPTION 110 WITH LOCAL CHECK OPTION 110 working with index 96 exception join 77 EXECUTE IMMEDIATE statement 201 EXECUTE privileges for packages 259 EXECUTE statement 201, 202 EXISTS keyword, use in subquery 87 exiting interactive SQL 228 exploiting LOB function to populate the database example 182 LOB locators to manipulate UDT instances example 183 UDFs to query instances of UDTs example 183 exponentiation and defining UDFs example 165 expression definition 39 SET clause, value 34 using in the WHERE clause 39 extended dynamic QSQPRCED 2 extensibility and UDTs 173 extracting a document to a file (CLOB elements in a table) example 156

functions (continued) table functions 163

G
getting catalog information about column 97 table 97 comment 49 information from multiple table 23 from single table 20 Grant Object Authority (GRTOBJAUT) command 235 GRANT PACKAGE statement 257 GROUP BY clause 41 keyword 255 using null value with 41 grouping the row you select 41

H
HAVING clause 42 host structure array multiple-row FETCH 63 host variable definition 40 SET clause, value 34

F
failed session, recovering 228 FETCH using host structure array multiple-row 63 FETCH statement 214 FFDC (first failure data capture) 279 field 3 file reference variables examples of using 156 for manipulating LOBs 150 input values 155 output values 156 first failure data capture (FFDC) 279 fixed-list SELECT statement definition 203 using 203 flexibility and UDTs 173 FOR UPDATE OF clause restrictions 58 format, SQLDA 206 FROM clause 36 function interactive SQL 219 function invocations example 169 function-name, passing to UDF 193 function path and UDFs 162 function references, summary for UDFs 171 function selection algorithm and UDFs 162 functions aggregating functions 163 column functions 163 scalar functions 163 syntax for referring to 169

I
ID, authorization 236 IDDU (interactive data definition utility) 6 ILE programs package 261 ILE service programs package 261 immediate sensitivity 63, 67 implementing a UDF 164 implicit connect 267 implicit disconnect 267 IN keyword description 73 subquery, use in 87 in tray table 287 IN_TRAY table 287 index add 96 definition 8 recovery 246 using 96 working with 96 indicator variables stored procedures 132 indicator variables and LOB locators infix notation and UDFs 172 information, inserting into table 18 inner join 75 INSERT statement blocked 31 default value 18, 32 description 31

INSERT statement (continued) VALUES clause 31 inserting information into table 18 multiple rows into tables 69 note 70 inserting data into a CLOB column example 158 instances of object-oriented data types, storing 149 Integrated Language Environment (ILE) module 12 program 11 service program 12 integrity catalog 247 data 99, 237 referential 99 interactive data definition utility 6 interactive interface concepts 2 interactive SQL accessing remote databases 229 change session attributes 227 description 219 exiting 228 function 219 general use 219 getting started 220 overview 219 package 230 prompting DBCS consideration 223 overview 219 session services 219, 226, 228 statement entry 219, 221 statement processing mode 223 terminology 3 testing your SQL statements with 219, 228 Interactive SQL 2 adding DBCS data 223 prompting 224 syntax checking 223 INTO clause description 32 PREPARE statements 205 restriction 210 invoking UDFs 168

J
job attribute DDMCNV 275 job-level commitment definition 267, 272 join cross 78 definitions 30 exception 77 inner 75 left outer 76 join operation definition 23 in a view 30 joining data from multiple tables 75 table with WHERE clause 76

155

338

DB2 UDB for AS/400 SQL Programming Concepts V4R5

joining (continued) technique 79 journal 6 journal receiver 6 journaling 239

K
keyword AND 74 BETWEEN 72 COMMIT 240 DISTINCT 255 EXISTS 87 GROUP BY 255 IN 73, 87 LIKE 73 NOT 40 OR 74 search condition, use in 72 UNION 80, 255 UNION ALL, specifying 83

LOBs (Large Objects) (continued) manipulating 149 programming options for values 151 storing 149 synergy with UDTs and UDFs examples of complex applications 181 locators for manipulating LOBs 150 logical file 3, 7 LONG VARCHAR storage limits 150 LONG VARGRAPHIC storage limits 150 Loosely Coupled Parallelism 2

null value 45 (continued) SET clause, value 33 UPDATE statement 33 used with GROUP BY clause 41 used with ORDER BY clause 44 NULL value 14 definition 40 numeric conversion error 38

O
object application program 9 collection 3 module 9 Integrated Language Environment (ILE) 12 package 9 program Integrated Language Environment (ILE) 11 service program 9 Integrated Language Environment (ILE) 12 SQL 5 object-orientation and UDFs 160 object-oriented extensions and UDTs 173 object-relational application domain and object-orientation 149 constraint mechanisms 149 data types 149 definition 149 LOBs 149 support for 150 triggers 149 UDTs and UDFs 149 why use the DB2 object extensions 149 ODBC 201 open cursor during a unit of work 67 open database connectivity (ODBC) 201 OPEN statement 215 operation, atomic 243 operators, comparison 40 ORDER BY clause 43 using null values with 44 data mapping errors 37 sort sequence, using 50 using 51 outer join 76 outer-level SELECT 84 output source file member definition 11 overloaded function names and UDFs 162 Override Database File (OVRDBF) command 62, 237 overview, interactive SQL 219

M
manipulating large objects 149 mapping error data 37 marker, parameter 215 maximum size for large object columns, defining 151 member output source file 11 user source file 11 mode interactive SQL 223 modelling entities as independent objects 149 module Integrated Language Environment (ILE) object 12 money using CREATE DISTINCT TYPE example 175 moving large objects using a file reference variable 150 multiple row inserting into a table 69 notes on inserting 70 search condition within a WHERE clause 74 table joining data from 75 multiple-row FETCH statement using descriptor area 64 host structure arrays 63 row storage area 64 with languages 63

L
LABEL ON statement 16, 48 information in catalog 48 package 262 large object descriptor 150 large object value 150 learn how to prompt using interactive SQL 224 leaving interactive SQL 228 left outer join 76 library definition 3 LIKE keyword 73 linking a UDF 164 list function 226 list function in interactive SQL description 224 LOBEVAL.SQB COBOL program listing 157 LOBEVAL.SQC C program listing 157 LOBLOC.SQB COBOL program listing 154 LOBLOC.SQC C program listing 153 LOBs (Large Objects) and DB2 object extensions 149 file reference variables 150 examples of using 156 input values 155 output values 156 SQL_FILE_APPEND, output value option 156 SQL_FILE_CREATE, output value option 156 SQL_FILE_OVERWRITE, output value option 156 SQL_FILE_READ, input value option 156 large object descriptor 150 large object value 150 locators 150, 151 example of using 152 indicator variables 155

N
naming convention *SQL 3 *SYS 3 SQL 4 system 3 negative SQLCODEs 293 non-SELECT statements, processing 202 NOT keyword 40, 74 NOW scalar function 46 null value 45 INSERT statement 32 inserting in a view 95

P
package authority to create 259 authority to run 259 Index

339

package (continued) bind to an application 9 CCSID considerations for 263 consistency token 262 Create SQL Package (CRTSQLPKG) command 259 authority required 260 creating authority required 259 effect of ARD programs 279 errors during 260 on local system 262 RDB parameter 259 RDBCNNMTH parameter 262 TGTRLS parameter 261 type of connection 262 unit of work boundary 262 creating on a non-DB2 UDB for AS/400 errors during 260 required precompiler options for DB2 Common Server 260 unsupported precompiler options 260 DB2 UDB for AS/400 support 259 definition 9, 12, 259 Delete SQL Package (DLTSQLPKG) command 259 deleting 259 interactive SQL 230 labeling 262 restore 262 save 262 SQL statement size 261 statements that do not require package 261 paging retrieved data 253 parameter markers in functions example 169 parameter passing stored procedures 128, 132 table 128 parameters marker 215 passing argument to UDF call-type 194 dbinfo 194 diagnostic-message 193 function-name 193 scratchpad 193 specific-name 193 SQL-argument 194, 195 SQL-argument-ind 192 SQL-argument-ind-array 195 SQL-result 194, 195 SQL-result-ind 192, 195 SQL-state 192 pending check 107 performance UDFs 160 performance and UDTs 173 performance verification 251 performing complex search condition 72 physical file 3, 6 positive SQLCODEs 291

precompiler concepts 1 diagnostic messages 260 precompiler command CRTSQLxxx 50, 260 precompiler parameter DBGVIEW(*SOURCE) 250 predicate definition 38 PREPARE statement non-SELECT statement 202 restrictions 201 using 215 prepared statement distributed unit of work 278 preventing duplicate rows 71 printing current session 227 problems, solving database 253 processing data in a view 36 non-SELECT statements 202 SELECT statement with SQLDA 203 program application 249 debugging 250 definition 11 Integrated Language Environment (ILE) object 11 non-ILE object 11 performance verification 251 project table 286 prompt using interactive SQL 219, 224 prompting CREATE TABLE 223 function 219, 221 overview 219 subqueries 223 protected connections dropping 272 protected resource 269 protection, data 235 public authority 235

Q
QSQCHKS 2 QSQPRCED 2 package 9 QSYS2 catalog views 6 QSYSPRT listing SQL statement processor example 233

R
re-use and UDFs 160 read-only table 59 view 95 read-only connection 269 receiver, journal 6 Reclaim DDM connections (RCLDDMCNV) command 275 record, definition 3 record selection 52

record selection 52 (continued) sort sequence, using 50 recovering effect on open cursor 67 index 246 interactive SQL saved or failed session 228 referential constraints check pending 107 creating tables 100 definition 8 delete rules 105 deleting from tables 105 inserting into tables 102 removing 102 update rules 104 updating tables 103 referential integrity 99 definition 8 registering UDFs 164 related information 331 relational database 3 RELEASE statement 257, 261 ending connection 275 remote databases accessing from interactive SQL 229 remote unit of work 257, 268 connection status 273 connection type 269 example program 258 removing all entries from current session 227 restriction FOR UPDATE OF 255 result table 80 resume using CREATE DISTINCT TYPE example 175 Retrieve Message (RTVMSG) command 289 retrieving data from a table. 20 in reverse order 253 row using a cursor 60 SELECT statement result cursor, using 214 return code 38 RETURNS TABLE clause 192, 194, 195 reuse deleted records INSERT 33 Revoke Object Authority (RVKOBJAUT) command 235 REVOKE PACKAGE statement 257 REXX 2 rollback rollback required state 274 ROLLBACK prepared statements 203 ROLLBACK statement 261 row definition 3, 6 delete current 61 inserting multiple into a table 69 note 70

340

DB2 UDB for AS/400 SQL Programming Concepts V4R5

row (continued) preventing duplicate 71 RRN scalar function 77 rules that govern operations on large objects 149 run mode interactive SQL 223 Run SQL Statements (RUNSQLSTM) command 2 run-time support concepts 1 running dynamic SQL application 201 RUNSQLSTM (Run SQL Statements) 227, 228 command 2, 231 command errors 232 commitment control 232 RUNSQLSTM (Run SQL Statements) command 323 RUW (remote unit of work) 257

S
sales using CREATE TABLE example 175 sample programs distributed RUW program 258 sample tables DB2 UDB for AS/400 281 save/restore 245 packages 262 saved session in a source file 227, 228 recovering 228 scalar functions 163 schedule table class 287 schema-name and UDFs 162 schemas SQL statement processor 232 scratchpad, passing to UDF 193 scrollable cursor 55 search condition definition 38 performing complex 72 subqueries 85 using keyword in 72 security 235 authorization 250 authorization ID 236 commitment control 239 data integrity 237 concurrency 237 public authority 235 view 236 SELECT clause 38 select information into host variables 36 SELECT INTO statement restriction 201 retrieving row 35 SELECT statement definition 20 example of allocating storage for SQLDA 210 processing and using SQLDA 203 using fixed-list 203 using varying-list 204

selecting column 70 semantic behavior of stored objects 149 Send Program Message (SNDPGMMSG) command 289 Send User Message (SNDUSRMSG) command 289 sensitivity immediate 63, 67 serial cursor 55 service program Integrated Language Environment (ILE) object 12 services, session 226 session 228 printing current 227 removing all entries from current 227 saving in a source file 227, 228 session services in interactive SQL 219, 226, 228 SET clause description 33 value column name 33 constant 33 expression 34 host variable 34 null 33 scalar subselect 34 special register 34 SET CONNECTION statement 257, 261 SET CURRENT FUNCTION PATH statement 164 SET TRANSACTION statement effect on implicit disconnect 267 not allowed in package 260 SEU (source entry utility) 228 signature, two functions and the same 162 SMALLINT 192, 195 solving 253 common database problem 253 solving common problems 253 SOME 86 sort sequence CREATE INDEX 53 used with ORDER BY 50 used with record selection 50 using 50 views 53 source entry utility (SEU) 228 source file for RUNSQLSTM 231 member, output definition 11 member, user 11 saving a session in 227, 228 sourced UDF 177 special register CURRENT DATE 45 CURRENT SERVER 45 CURRENT TIME 45 CURRENT TIMESTAMP 45 CURRENT TIMEZONE 45 definition 40

special register (continued) SET clause, value 34 USER 45 specific-name, passing to UDF 193 specifying column, SELECT INTO statement 38 UNION ALL 83 SQL 1 call level interface 2 introduction 1 object 5 statements types 4 SQL-argument, passing to UDF 194, 195 SQL-argument 192 SQL-argument-ind, passing to UDF 192 SQL-argument-ind-array, passing to UDF 195 SQL collection 13 SQL_FILE_READ, input value option 156 SQL naming convention 4 SQL package 3 SQL-result, passing to UDF 194, 195 SQL-result 192 SQL-result-ind, passing to UDF 192, 195 SQL-state, passing to UDF 192 SQL statement processor commitment control 232 example QSYSPRT listing 233 schemas 232 using 231 SQLCODEs definition 289 description 291 negative 293 positive 291 testing application program 250 SQLD 206 SQLDA (SQL descriptor area) allocating storage for 210 format 206 processing SELECT statement 203 programming language, use in 205 SELECT statement for allocating storage for SQLDA 210 SQLDABC 206 SQLDAID 206 SQLDATA 208 SQLERRD field of SQLCA SQLERRD(3) field of SQLCA determining connection status 273 determining number of rows fetched 63 SQLERRD(4) field of SQLCA 273 determining connection type 269 determining length of each row retrieved 63 SQLERRD(5) field of SQLCA determining end-of-file 63 SQLIND 208 SQLLEN 207 SQLN 206 SQLNAME 209 SQLRES 208 Index

341

SQLSTATEs code definition 289 definition 289 description 291 testing application program 250 SQLTYPE 206 sqludf.h include file for UDFs 194 SQLVAR 206 Start Commitment Control (STRCMTCTL) command 240 Start Journal Access Path (STRJRNAP) command 246 Start SQL (STRSQL) command 330 starting interactive SQL 220 statement entry 219, 221 statement processing mode interactive SQL 223 statements 45 ALIAS statement example 48 basic, using 31 COMMENT ON statement 49 COMMIT 6 CONNECT 257 CREATE COLLECTION 13 CREATE INDEX sort sequence 53 CREATE PROCEDURE external procedure 117 SQL procedure 117 CREATE SCHEMA 232 CREATE TABLE 14 CREATE VIEW 29 data definition (DDL) 4 data manipulation (DML) 4 date value 47 DECLARE CURSOR 36 DELETE example 34 WHERE clause 28 DISCONNECT 257 DROP PACKAGE 257 dynamic 4 EXECUTE 201, 202 FETCH 214 multiple-row 62 GRANT PACKAGE 257 INSERT using 31 LABEL ON statement example 48 examples 16 multiple-row FETCH 64 OPEN 215 package not required 261 packages 260 PREPARE cursor 215 non-SELECT statement 202 using 201 processing non select 202 RELEASE 257 REVOKE PACKAGE 257 ROLLBACK 6 select 20 SELECT INTO example 35

statements 45 (continued) SELECT INTO (continued) processing data (view) 36 restriction 201 specifying column 38 SET CONNECTION 257 SQL packages 260 testing in application program 249 using interactive SQL 219, 228 time value 47 timestamp value 47 UPDATE changing data value 25 example 33 stopping interactive SQL 228 storage, allocating for SQLDA 210 stored procedures 117, 145 definition 8 parameter passing 128 indicator variables 132 table 128 storing large objects 149 string search and defining UDFs example 166 string search on BLOBs 166 string search over UDT example 167 strong typing and UDTs 176 STRSQL (Start SQL) command 220, 330 Structured Query Language 1 structured query language package creating 308 deleting 311 subquery 88 basic comparison 86 correlated 85, 88 correlated names and references 90 definition 84 examples 84 EXISTS keyword 87 IN keyword 87 notes on using with UPDATE and DELETE 88 prompting 223 quantified comparison 86 search condition 85 subselect combining with the UNION keyword, example 80 SET clause, value 34 Symmetric Multiprocessing 2 sync point manager 269 syntax check QSQCHKS 2 syntax check mode interactive SQL 223 syntax for referring to functions 169 system naming convention 3 system table name 17

T
table adding data to the end 254 changing definition 92, 256 changing information in 25 CL_SCHED (class schedule) 287

table (continued) CORPDATA.DEPARTMENT (department) 281 CORPDATA.EMP_ACT (employee to project activity) 283 CORPDATA.EMPLOYEE 282 CORPDATA.PROJECT (project) 286 creating CREATE TABLE statement 14 view 29 DB2 UDB for AS/400 sample 281 defining name 48 definition 3, 6 deleting information in 28 establishing position at the end 253 getting catalog information about column 97 getting information from multiple 23 from one 20 IN_TRAY 287 inserting information into 18 multiple rows into 69 joining 75 the WHERE clause 76 multiple creating view over 30 sample 281 used in examples CORPDATA.DEPARTMENT (department) 281 CORPDATA.EMP_ACT (employee to project activity) 283 CORPDATA.EMPLOYEE 282 CORPDATA.PROJECT (project) 286 using 14 table functions 163 contents of call-type argument 194 table name system 17 technique coding 31, 55, 69 solving database problem 253 terminology interactive SQL 3 relational database 3 relationship table *SQL 3 *SYS 3 testing authorization 249, 250 debugging your program 250 input data 249 performance verification 251 SQL statements using interactive SQL 219, 228 statements in application program 249 view 249 time format 47 specifying current value 47 timestamp format 47 specifying current value 47 tolerance, damage 246

342

DB2 UDB for AS/400 SQL Programming Concepts V4R5

trigger definition 8 event 8 trigger support 111 triggers and DB2 object extensions truncation error 37 two-phase commit 269 typing interactive SQL 221

149

U
UDFs (User-defined functions) and DB2 object extensions 149 casting 172 concepts 162 definition 160 function path 162 function selection algorithm 162 general considerations 172 implementing UDFs 160 infix notation 172 invoking examples of invocations 168 parameter markers in functions 169 qualified function reference 170 unqualified function reference 170 LOB types 172 overloaded function names 162 process of implementation 164 referring to functions 169 registering UDFs 165 examples of registering 165 schema-name and UDFs 162 sourced 177 summary of function references 171 synergy with UDTs and LOBs examples of complex applications 181 type of functions 163 unqualified reference 162 why use UDFs 160 writing your own UDF 189 UDFs and LOB types 172 UDTs (User-defined types) and DB2 object extensions 149 defining a UDT 174 defining tables 175 manipulating examples of 176 resolving unqualified UDTs 174 strong typing 176 synergy with UDFs and LOBs examples of complex applications 181 why use UDTs 173 UNION ALL, specifying 83 UNION keyword restriction 255 using to combine subselects 80 unique constraint definition 8 unit of work distributed 257

unit of work (continued) effect on open cursor 67 package creation 262 remote 257 rollback required 274 unit of work boundary package creation 262 unprotected resource 269 unqualified function reference example 170 unqualified reference 162 UPDATE statement correlated subquery, using in 91 description 33 WHERE clause 25 updating data as it is retrieved, restrictions 254 committable updates 269 previously retrieved 256 use of UDTs in UNION example 180 user auxiliary storage pool (ASP) 247 user-defined sourced functions on UDTs example 178 user profile authorization ID 3 authorization name 3 user source file member definition 11 USER special register 45 using blocked insert statement 70 cursor example 56 retrieve row 60 date value 47 index 96 null value 45 ORDER BY 51 parameter markers 215 record selection 52 sort sequence 50 time value 47 timestamp value 47 Using views 95 USING clause 212 DESCRIPTOR clause 215 using a locator to work with a CLOB value example 152 using interactive SQL 219 after first time 226 list selection function 224 prompting 221 statement entry 221 using qualified function reference example 170

varying-list SELECT statement (continued) using 204 verification performance 251 view creating 95 CREATE VIEW statement 28 on a table 29 over multiple tables 30 definition 3, 7 limiting access 28 processing data in 36 read-only 95 security 236 sort sequence 53 testing 249 using 95 WITH CASCADED CHECK 108 WITH CHECK 108 WITH LOCAL CHECK 109

W
WHENEVER NOT FOUND clause 60 WHERE clause character string 31 constant 39 description 38 example 215 expression in, using 39 joining tables 76 multiple search condition within a 74 NOT keyword 40 WHERE CURRENT OF clause 61 WITH CASCADED CHECK OPTION 108 WITH CHECK OPTION 108 WITH DATA DICTIONARY clause CREATE COLLECTION statement 6 CREATE SCHEMA statement 6 creating data dictionary 6 WITH LOCAL CHECK OPTION 109 working with index 96

X
X/Open call level interface 2

V
validate mode interactive SQL 223 value default 14, 18 inserting into table or view 31 VALUES clause 31 varying-list SELECT statement definition 204 Index

343

344

DB2 UDB for AS/400 SQL Programming Concepts V4R5

Printed in U.S.A.

You might also like