Escolar Documentos
Profissional Documentos
Cultura Documentos
Learning by Example
Implementation guide for DB2 Java stored procedures DB2 Java stored procedures across platforms Reference guide for network computing enhancements in DB2 UDB for OS/390 V6
ibm.com/redbooks
SG24-5945-00
International Technical Support Organization DB2 Java Stored Procedures Learning by Example
September 2000
Take Note! Before using this information and the product it supports, be sure to read the general information in Appendix F, Special notices on page 355.
First Edition (September 2000) This edition applies to Version 6 of IBM DATABASE 2 Universal Database Server for OS/390 (DB2 UDB Server for OS/390 Version 6), Program Number 5645-DB2, Version 7 of DB2 UDB for UNIX, Windows, OS/2, and other current versions and releases of IBM products. Make sure you are using the correct edition for your level of product. This document was created or updated on September 5, 2000. Comments may be addressed to: IBM Corporation, International Technical Support Organization Dept. QXXE Building 80-E2 650 Harry Road San Jose, California 95120-6099 When you send information to IBM, you grant IBM a non-exclusive right to use or distribute the information in any way it believes appropriate without incurring any obligation to you.
Copyright International Business Machines Corporation 2000. All rights reserved. Note to U.S Government Users Documentation related to restricted rights Use, duplication or disclosure is subject to restrictions set forth in GSA ADP Schedule Contract with IBM Corp.
Contents
Figures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .xi Tables. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xiii Preface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xv How this book is structured . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xv The team that wrote this redbook . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xvi Comments welcome . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xviii Part 1. Background. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 Chapter 1. Java platform support . . . . 1.1 Java overview . . . . . . . . . . . . . . . . . 1.2 Java and the OS/390 Platform . . . . . 1.2.1 OS/390 UNIX System Services. 1.2.2 Enterprise Toolkit for OS/390 . . 1.3 Java and the UNIX Platform . . . . . . . 1.4 Java and the Windows NT Platform . . . . . . . . . . . . . . . .. .. .. .. .. .. .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. .. .. .. .. .. .. . . . . . . . . . . . . . . . . . . . . . .. .. .. .. .. .. .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. .. .. .. .. .. .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .3 .3 .4 .4 .4 .6 .6
Chapter 2. Java and DB2 . . . . . . . . . . . . . . . . . . . . 2.1 Java database connectivity . . . . . . . . . . . . . . . . 2.1.1 DB2 JDBC programs . . . . . . . . . . . . . . . . . 2.1.2 DB2 SQLJ programs. . . . . . . . . . . . . . . . . . 2.1.3 Choosing the access method: JDBC versus 2.1.4 JDBC driver types. . . . . . . . . . . . . . . . . . . . 2.2 Java and DB2 stored procedures . . . . . . . . . . . . 2.2.1 What is a stored procedure? . . . . . . . . . . . . 2.2.2 Supported stored procedure languages . . . 2.2.3 DB2 Java stored procedures . . . . . . . . . . .
..... ..... ..... ..... SQLJ ..... ..... ..... ..... .....
. .7 . .7 . .7 . .8 . .9 . 11 . 12 . 12 . 13 . 14
Part 2. Developing Java stored procedures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 Chapter 3. Java sample application: the ACME software company 3.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.2 System design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.3 Sample application components . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.3.1 DB2 naming conventions . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.4 Portability issues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.4.1 Java stored procedure portability . . . . . . . . . . . . . . . . . . . . . . 3.4.2 DB2 portability issues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.5 Sample stored procedures standard . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 . 19 . 19 . 21 . 23 . 24 . 24 . 24 . 24
iii
3.5.1 JDBC stored procedure sample . . . . . . . . . . 3.5.2 SQLJ stored procedure sample . . . . . . . . . . 3.5.3 COBOL stored procedure sample . . . . . . . . . 3.5.4 Combined SQLJ and JDBC example . . . . . . 3.6 Sample stored procedures enhanced . . . . . . . . 3.6.1 JDBC enhanced stored procedure sample . . 3.6.2 SQLJ enhanced sample . . . . . . . . . . . . . . . . 3.7 Sample Client Code . . . . . . . . . . . . . . . . . . . . . . . 3.7.1 Calling the Java stored procedure from Java 3.7.2 COBOL client application sample . . . . . . . . . 3.7.3 SQLJ client application sample . . . . . . . . . . . 3.7.4 JDBC client application sample . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
.. .. .. .. .. .. .. .. .. .. .. ..
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
.. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. ..
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. 25 . 27 . 29 . 32 . 34 . 34 . 39 . 45 . 45 . 48 . 50 . 52 . 57 . 57 . 57 . 59 . 60 . 63 . 66 . 66 . 68 . 69 . 71 . 73 . 75 . 76 . 78 . 78 . 79 . 79 . 80 . 80 . 80 . 83 . 83 . 83 . 89 . 90 . 90 . 90 . 90
Chapter 4. System setup . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.1 OS/390 system setup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.1.1 Prerequisites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.1.2 Installation tasks. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.1.3 Step 1: Design library structure . . . . . . . . . . . . . . . . . 4.1.4 Step 2: Provide .profile for users . . . . . . . . . . . . . . . . 4.1.5 Step 3: Setting up RRS. . . . . . . . . . . . . . . . . . . . . . . . 4.1.6 Step 4: Define WLM stored procedure address space 4.1.7 Step 5: Install JDBC/SQLJ driver for OS/390 . . . . . . . 4.1.8 Step 6: Set up the JAVAENV data set . . . . . . . . . . . . 4.1.9 Step 7: Verify JDBC cursor and SQLJ properties files 4.1.10 Data sharing considerations . . . . . . . . . . . . . . . . . . . 4.1.11 Maintenance considerations . . . . . . . . . . . . . . . . . . . 4.1.12 Some common setup issues . . . . . . . . . . . . . . . . . . . 4.2 Windows NT system setup . . . . . . . . . . . . . . . . . . . . . . . . . 4.2.1 Prerequisites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.2.2 Installation tasks. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.2.3 Some common setup issues . . . . . . . . . . . . . . . . . . . . 4.3 UNIX system setup. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.3.1 Prerequisites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.3.2 Installation tasks. . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Chapter 5. Designing Java stored procedures . . . . . . . . . . . . 5.1 General design issues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.1.1 Naming . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.1.2 Parameter style: Java or DB2GENERAL . . . . . . . . . . . 5.1.3 Public static method with void return type . . . . . . . . . . . 5.1.4 Parameters must be mappable to base SQL data types 5.1.5 LOBS not supported for Java stored procedures . . . . . 5.1.6 Why do we use [ ] on the output parameters? . . . . . . . .
iv
5.1.7 Using JDBC, SQLJ, or both . . . . . . . . . . . . . . . . . . 5.1.8 Java packages . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.1.9 Case sensitivity . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.1.10 Nested Java stored procedures . . . . . . . . . . . . . . 5.2 Design issues for OS/390 Java stored procedures . . . . . 5.2.1 Must use HPJ compiler . . . . . . . . . . . . . . . . . . . . . . 5.2.2 Must have Java Package as first statement . . . . . . 5.2.3 Packaging considerations . . . . . . . . . . . . . . . . . . . . 5.2.4 Environmental considerations . . . . . . . . . . . . . . . . . 5.3 Design issues for the UNIX, Windows, OS/2 platforms . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
.. .. .. .. .. .. .. .. .. ..
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. 91 . 91 . 92 . 92 . 93 . 93 . 93 . 93 . 94 . 96
Chapter 6. Coding Java stored procedures . . . . . . . . . . . . . . . . . . . 6.1 Null handling with JDBC stored procedures . . . . . . . . . . . . . . . . . . 6.1.1 Calling a stored procedure with a null value . . . . . . . . . . . . . . 6.1.2 Using a Java base type as a parameter . . . . . . . . . . . . . . . . . 6.1.3 Determining if a selected item was an SQL null via wasNull() . 6.1.4 Inserting a NULL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.2 Null handling with SQLJ stored procedures . . . . . . . . . . . . . . . . . . 6.3 SQLJ Iterators and ResultSets . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.3.1 Return ResultSets from SQLJ stored procedures . . . . . . . . . . 6.3.2 Avoid returning a used ResultSet . . . . . . . . . . . . . . . . . . . . . . 6.3.3 Close interim ResultSets . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.3.4 Returning Multiple ResultSets. . . . . . . . . . . . . . . . . . . . . . . . . 6.4 Error Handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.4.1 Getting the results of printStackTrace . . . . . . . . . . . . . . . . . . . 6.5 Debugging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.5.1 Initially writing as a standalone program . . . . . . . . . . . . . . . . . 6.5.2 Writing debugging statements to a table . . . . . . . . . . . . . . . . . 6.5.3 OS/390 debugging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.5.4 UNIX and Windows NT debugging . . . . . . . . . . . . . . . . . . . . . 6.6 Using the DB2 Stored Procedure Builder . . . . . . . . . . . . . . . . . . . . 6.6.1 Advantages of the SPB. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.7 Common errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.7.1 OS/390 errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.7.2 UNIX and Windows NT errors . . . . . . . . . . . . . . . . . . . . . . . . . Chapter 7. Preparing Java stored procedures . . . . 7.1 Program preparation concepts . . . . . . . . . . . . . . . 7.2 OS/390 Java stored procedure preparation . . . . . 7.2.1 Java stored procedure and DB2 package . . . 7.2.2 DB2 authorization issues . . . . . . . . . . . . . . . 7.2.3 OS/390 JDBC program preparation process . 7.2.4 OS/390 SQLJ program preparation process . . . . . . . . . . . . . . . . . . . . . . .. .. .. .. .. .. .. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. .. .. .. .. .. .. . . . . . . . . . . . . . .
. . 97 . . 97 . . 97 . . 97 . . 99 . . 99 . 100 . 100 . 101 . 101 . 101 . 102 . 102 . 102 . 103 . 103 . 103 . 103 . 104 . 105 . 105 . 106 . 106 . 112 . 119 . 119 . 119 . 119 . 120 . 122 . 129
Using UNIX System Services (USS) . . . . . . . . . AIX Java stored procedure preparation . . . . . . . NT / AIX JDBC program preparation process . . NT / AIX SQLJ program preparation process . . The sqlj.install_jar and sqlj.replace_jar routines
. . . . .
.. .. .. .. ..
. . . . .
. . . . .
. . . . .
. . . . .
.. .. .. .. ..
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. 143 . 144 . 144 . 149 . 155 . 157 . 157 . 157 . 160 . 161 . 163 . 163 . 163 . 164 . 164 . 164 . 165 . 165 . 167 . 167 . 167 . 167 . 168 . 168 . 170 . 170 . 170 . 172 . 174 . 174 . 174 . 174 . 175 . 175 . 176 . 181 . 181 . 182 . 182 . 183 . 184
Chapter 8. Deployment and execution . . . . . . . . . . . . . . . . . . . . . 8.1 Deployment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8.1.1 Migrating between environments on S/390 . . . . . . . . . . . . . 8.1.2 Migrating between environments on UNIX/NT . . . . . . . . . . 8.1.3 Porting between UNIX/NT and S/390 . . . . . . . . . . . . . . . . . 8.2 Execution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8.2.1 OS/390 execution considerations . . . . . . . . . . . . . . . . . . . . 8.2.2 UNIX and Windows NT execution considerations . . . . . . . . 8.3 Stored procedure management and version control on OS/390 . 8.3.1 Source code control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8.3.2 Version control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8.3.3 Sample of a test and production version . . . . . . . . . . . . . . . 8.3.4 Running two versions in the same DB2 subsystem . . . . . . . Chapter 9. Client applications invoking Java stored procedures 9.1 DB2 plans and packages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9.1.1 JDBC client requirements . . . . . . . . . . . . . . . . . . . . . . . . . . 9.1.2 SQLJ client requirements . . . . . . . . . . . . . . . . . . . . . . . . . . 9.1.3 Stored procedure requirements . . . . . . . . . . . . . . . . . . . . . 9.1.4 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9.1.5 Usage recommendations . . . . . . . . . . . . . . . . . . . . . . . . . . 9.2 Client coding considerations. . . . . . . . . . . . . . . . . . . . . . . . . . . . 9.2.1 General client coding considerations . . . . . . . . . . . . . . . . . 9.2.2 JDBC client coding considerations . . . . . . . . . . . . . . . . . . . 9.2.3 SQLJ client coding considerations . . . . . . . . . . . . . . . . . . . 9.3 Client authorization issues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9.3.1 JDBC client authorization . . . . . . . . . . . . . . . . . . . . . . . . . . 9.3.2 DB2 for OS/390 stored procedure execute authority . . . . . . 9.4 Sample Java client preparation scripts . . . . . . . . . . . . . . . . . . . . 9.4.1 Sample javacl script . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9.4.2 Sample bindcl.rexx script . . . . . . . . . . . . . . . . . . . . . . . . . . Chapter 10. Migration of DB2 for OS/390 Version 5 to Version 6 . 10.1 Stored procedures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10.1.1 SYSIBM.SYSPROCEDURES no longer used . . . . . . . . . . 10.1.2 Java stored procedures under Version 5. . . . . . . . . . . . . . 10.1.3 DB2 catalog maintenance . . . . . . . . . . . . . . . . . . . . . . . . . 10.1.4 Fallback considerations from Version 6 to Version 5 . . . . .
vi
Part 3. DB2 UDB for OS/390 V6 various enhancements . . . . . . . . . . . . . . . . . . . . . 185 Chapter 11. DB2 UDB for OS/390 network computing enhancements187 11.1 DRDA support for three-part names . . . . . . . . . . . . . . . . . . . . . . . . 187 11.1.1 Three-part names prior to Version 6 . . . . . . . . . . . . . . . . . . . . 187 11.1.2 Three-part names in Version 6 . . . . . . . . . . . . . . . . . . . . . . . . 189 11.1.3 Package requirements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191 11.1.4 How it works . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192 11.1.5 DBPROTOCOL bind option . . . . . . . . . . . . . . . . . . . . . . . . . . 193 11.1.6 Stored procedures considerations . . . . . . . . . . . . . . . . . . . 193 11.1.7 Hopping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194 11.1.8 Advantages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196 11.1.9 Impacts. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197 11.2 DRDA query block size. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198 11.2.1 OPTIMIZE FOR n ROWS clause enhancements. . . . . . . . . . . 198 11.2.2 How it works . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200 11.2.3 Usage recommendations . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201 11.3 DDF connection pooling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202 11.4 STOP DDF MODE(SUSPEND) command . . . . . . . . . . . . . . . . . . . 203 11.4.1 Command syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204 11.5 Declared Global Temporary Tables . . . . . . . . . . . . . . . . . . . . . . . . 205 11.5.1 Usability considerations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207 11.6 Savepoints . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208 11.6.1 Connecting to other DB2 systems. . . . . . . . . . . . . . . . . . . . . . 209 11.6.2 Restrictions on using savepoints . . . . . . . . . . . . . . . . . . . . . . 210 11.6.3 Savepoint performance. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210 11.7 Identity columns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210 11.7.1 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211 11.7.2 Data definition issues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211 11.7.3 Data manipulation issues . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217 11.7.4 Utility issues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218 11.7.5 Other properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220 11.7.6 DB2 catalog table considerations . . . . . . . . . . . . . . . . . . . . . . 221 11.7.7 Usage recommendations . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222 11.7.8 Use of identity columns versus ROWID columns . . . . . . . . . . 228 11.7.9 Data propagation considerations . . . . . . . . . . . . . . . . . . . . . . 229 11.7.10 Influencing insert order in a data sharing environment . . . . . 230 11.7.11 Differences in implementation across the DB2 Family. . . . . . 230 Chapter 12. DB2 UDB for OS/390 schema support . 12.1 Schema characteristics . . . . . . . . . . . . . . . . . . . 12.2 How schemas are used . . . . . . . . . . . . . . . . . . . 12.2.1 Explicit specification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. .. .. .. . . . . . . . . . . . . . . . . .. .. .. .. . . . . . . . . . 233 . 234 . 234 . 234
vii
12.2.2 Implicit specification . . . . . . . . 12.3 Schemas and the CURRENT PATH 12.3.1 SET CURRENT PATH . . . . . . 12.3.2 PATH bind option . . . . . . . . . .
.. .. .. ..
. . . .
. . . .
. . . .
. . . .
.. .. .. ..
. . . .
. . . .
Chapter 13. DB2 UDB for OS/390 stored procedures enhancements 243 13.1 Stored procedures: an overview . . . . . . . . . . . . . . . . . . . . . . . . . . . 243 13.1.1 Why use stored procedures? . . . . . . . . . . . . . . . . . . . . . . . . . 244 13.1.2 SQL CALL processing flow. . . . . . . . . . . . . . . . . . . . . . . . . 246 13.1.3 Stored procedures time line characteristics . . . . . . . . . . . . 247 13.2 The CREATE PROCEDURE DDL statement . . . . . . . . . . . . . . . . . 259 13.2.1 Parameter definitions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262 13.2.2 New options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 263 13.2.3 Enhanced options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 265 13.2.4 Advantages of DDL. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 267 13.2.5 Schema name: CREATE PROCEDURE . . . . . . . . . . . . . . . . . 269 13.2.6 Schema name: CALL statement . . . . . . . . . . . . . . . . . . . . . . . 270 13.3 Lifted DML restrictions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272 13.4 Nested stored procedures: characteristics . . . . . . . . . . . . . . . . . . . 274 13.5 Authorization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275 13.5.1 Who has EXECUTE privilege on a stored procedure? . . . . . . 277 13.6 DISPLAY PROCEDURE command. . . . . . . . . . . . . . . . . . . . . . . . . 280 13.7 Migration considerations. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 281 Part 4. Appendices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 283 Appendix A. New messages and error codes . . . . . . . . . . . . . . . . . . . . 285 A.1 STOP DDF MODE SUSPEND . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 285 Appendix B. Sample code, DDL, and preparation scripts . . . . . . . . . . 287 B.1 Sample DDL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 287 B.1.1 DB2 UDB for OS/390 DDL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 287 B.1.2 DB2 UDB for AIX and Windows DDL . . . . . . . . . . . . . . . . . . . . . . . 297 B.2 Sample stored procedure definitions . . . . . . . . . . . . . . . . . . . . . . . . . . . 307 B.2.1 DB2 UDB for OS/390 stored procedure definitions . . . . . . . . . . . . 307 B.2.2 DB2 UDB for AIX and Windows stored procedure definitions . . . . 317 B.3 Sample stored procedure code. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 318 B.4 Sample client code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 318 B.5 Sample program preparation scripts. . . . . . . . . . . . . . . . . . . . . . . . . . . . 318 B.5.1 OS/390 program preparation scripts. . . . . . . . . . . . . . . . . . . . . . . . 318 B.5.2 AIX program preparation scripts . . . . . . . . . . . . . . . . . . . . . . . . . . . 318 B.5.3 NT program preparation scripts . . . . . . . . . . . . . . . . . . . . . . . . . . . 321
viii
Appendix C. OS/390 Recoverable Resource Services (RRS) . . . . . . . 329 C.1 RRS attachment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 329 Appendix D. Define WLM stored procedure address space . . . . . . . . 331 D.1 Enable stored procedure support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 331 D.1.1 Step 1. Run the installation CLIST in INSTALL or MIGRATE mode.. . 331 D.1.2 Step 2. Edit DSNTIJUZ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 332 D.2 How to use the WLM ISPF application . . . . . . . . . . . . . . . . . . . . . . . . . . 332 D.3 Starting the WLM application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 333 D.4 Control of stored procedures in a WLM environment . . . . . . . . . . . . . . . 334 D.5 Defining the application environment . . . . . . . . . . . . . . . . . . . . . . . . . . . 335 D.6 Refreshing the environment for stored procedures . . . . . . . . . . . . . . . . 337 D.7 Using WLM application environments in compatibility mode . . . . . . . . . 338 D.8 Using WLM application environments in goal mode . . . . . . . . . . . . . . . . 339 D.9 Restricting access. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 341 D.10 Summary of service definition / service policy concepts. . . . . . . . . . . . 342 D.11 Recommendations for full implementation of OS/390 WLM . . . . . . . . . 344 D.12 Considerations for compatibility mode . . . . . . . . . . . . . . . . . . . . . . . . . 345 D.13 Considerations for goal mode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 345 Appendix E. Using the additional material . . . . . . . . . . . . . . . . . . . . . . 347 E.1 Using the CD-ROM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 347 E.1.1 Sample client code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 348 E.1.2 Sample stored procedure code. . . . . . . . . . . . . . . . . . . . . . . . . . . . 349 E.1.3 Sample S390 utilities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 352 E.1.4 Sample SQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 353 E.2 Locating the additional material on the Internet . . . . . . . . . . . . . . . . . . . 354 E.3 Using the Web material. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 354 E.3.1 How to use the Web material . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 354 Appendix F. Special notices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 355 Appendix G. Related publications. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 359 G.1 IBM Redbooks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 359 G.2 IBM Redbooks collections . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 359 G.3 Other resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 360 G.4 Referenced Web sites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 361 How to get IBM Redbooks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 363 IBM Redbooks fax order form . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 364
ix
Glossary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 365 Abbreviations and acronyms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 383 Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 387 IBM Redbooks review . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 393
Figures
1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. Java and DB2 for OS/390 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 Java and DB2 for UWO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 ACME Software Company System Design . . . . . . . . . . . . . . . . . . . . . . . . 20 SQLJ load library data set definition . . . . . . . . . . . . . . . . . . . . . . . . . . . 62 Application load library data set definition . . . . . . . . . . . . . . . . . . . . . . . 63 JAVAENV file data set definition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63 RACF command to assign home directory . . . . . . . . . . . . . . . . . . . . . . . . 66 JAVAENV data set contents . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70 DB2SQLJDBC.PROPERTIES contents . . . . . . . . . . . . . . . . . . . . . . . . 72 DB2 data sharing group with Java stored procedures . . . . . . . . . . . . . . . . 75 Java stored procedure object interrelationships . . . . . . . . . . . . . . . . . . . . 84 Our Java stored procedure object structure. . . . . . . . . . . . . . . . . . . . . . . . 85 Runtime environment overview SQLJ stored procedure. . . . . . . . . . . . 95 OS/390 JDBC program preparation process . . . . . . . . . . . . . . . . . . . . . . 122 OS/390 SQLJ program preparation process . . . . . . . . . . . . . . . . . . . . . . 129 AIX and Windows NT JDBC program preparation process . . . . . . . . . . . 145 AIX and Windows NT SQLJ program preparation process . . . . . . . . . . . 149 Source-centric migration for a JDBC application . . . . . . . . . . . . . . . . . . . 158 Executable-centric migration for a JDBC application. . . . . . . . . . . . . . . . 160 Three-part names prior to DB2 for OS/390 Version 6 . . . . . . . . . . . . . 187 Three-part name Version 6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190 Package requirements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191 How it works. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192 Hopping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194 Loop back . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196 OPTIMIZE FOR large number . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199 OPTIMIZE FOR how it works . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200 Potential issue when using OPTIMIZE FOR n ROWS. . . . . . . . . . . . . . . 202 DDF connection pooling. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203 Typical parent / dependent relationship . . . . . . . . . . . . . . . . . . . . . . . . . . 223 Example DDL for a global temporary table . . . . . . . . . . . . . . . . . . . . . . . 225 Example DDL for an after-insert trigger . . . . . . . . . . . . . . . . . . . . . . . . . . 225 After-insert trigger to retrieve the generated value of an id-column. . . . . 227 Identity column data propagation issues . . . . . . . . . . . . . . . . . . . . . . . . . 229 What is a schema? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 233 How a schema is used explicit specification . . . . . . . . . . . . . . . . . . . . 235 How a schema is used implicit specification . . . . . . . . . . . . . . . . . . . . 236 CURRENT PATH special register . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237 SET CURRENT PATH syntax. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 238 Stored procedures overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 245
xi
41. 42. 43. 44. 45. 46. 47. 48. 49. 50.
DB2 stored procedures access DL/I databases. . . . . . . . . . . . . . . . . . . . 256 Stored procedures: parameters definition . . . . . . . . . . . . . . . . . . . . . . . . 263 Schema name: CALL statement 1/2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 271 Schema name: CALL statement 2/2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272 SQL CALL statement (nesting) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273 Authorization CALL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 276 Authorization who is checked? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 278 Authorization example. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 279 DISPLAY PROCEDURE command . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 280 Sample files directory structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 348
xii
Tables
1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. JDBC driver types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 Stored procedure languages supported by DB2 platform . . . . . . . . . . . . . 14 ACME sample application components . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 Sample Code Java package names . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 DB2 for OS/390 Java APAR enhancements . . . . . . . . . . . . . . . . . . . . . . . 58 VisualAge for Java Enterprise Edition for OS/390 . . . . . . . . . . . . . . . . . . 58 Sample USS library structure. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60 Sample OS/390 library structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62 Null handling within SQL stored procedures . . . . . . . . . . . . . . . . . . . . . . 100 Contents of SQLJPLAN by client and SP type using COLLID. . . . . . . . . 168 Contents of SQLJPLAN by client and SP type not using COLLID. . . . . . 169 Private protocol v DRDA access . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189 START / STOP command versus DDF status . . . . . . . . . . . . . . . . . . . . . 204 Comparison of Identity and ROWID columns . . . . . . . . . . . . . . . . . . . . . 228
xiii
xiv
Preface
Stored procedures can provide major benefits in the areas of application performance, code re-use, security, and integrity. The DB2 Family of products has offered support for stored procedures for some time, with each release offering significant enhancements over the last. In the meantime, Java has been making steady inroads as the standard application development language for many companies large and small. Its inherent portability and openness, combined with the good availability of skilled programming resource, has made it an increasingly attractive choice, and the central plank in many organizations e-business strategy. Until recently, DB2 did not support stored procedures written in Java, so the advantages of the two technologies could not be combined. The latest releases of DB2 have changed all that, opening up new possibilities for efficient, secure, highly portable application development. This IBM Redbook aims to give the reader an in-depth understanding of the techniques and issues associated with the development of DB2 stored procedures written in Java and using SQLJ and/or JDBC for their SQL operations. The extensive collection of sample code presented in this book and included on the accompanying CD-ROM was designed to run against DB2 UDB Server across the OS/390, Windows, and UNIX platforms. We have assumed that the reader has at least a basic understanding of Java terminology (such as classes, methods and packages) in addition to exposure to general DB2 application development concepts.
xv
Part 4, Appendices contains complete listings of all of the sample code referred to throughout the book, together with additional reference material.
xvi
Michael is the co-author of the IBM Redbook, Getting Started with DB2 Stored Procedures: Give Them a Call through the Network. He has also given presentations for the local DB2 User Groups of the Midwest, in the area of DB2 OS/390. Julian Stuhler is a Principal Consultant with Triton Consulting in the United Kingdom. He has over 14 years experience working with the DB2 Family of products for a number of large UK customers, including insurance, telecommunications, banking, financial services and manufacturing companies. In that time he has obtained a large amount of practical experience in areas as diverse as systems programming, application programming, database administration, technical architecture and performance tuning. More recently, Julian has specialized in distributed database performance and the relational database connectivity issues surrounding Internet and intranet applications. Julian has lectured widely on DB2 subjects, both in the UK and Europe. This includes presentations for the International DB2 Users Group (IDUG), Candle Performance Seminars, the UK GUIDE DB2 Working Group, and European GUIDE meetings. Julian is an IBM DB2 Gold Consultant, a regular teacher for IBM's European Education Centre in Belgium, and is currently a member of both the IDUG European Conference Planning Committee and the UK DB2 Guide Committee.
Thanks to the following people for their invaluable contributions to this project: Peggy Abelite John Campbell Curt Cotner Ramani Croisettier Thomas Eng Christopher Farrar Claire McFeely Todd Munk Judy Tobias Tom Toomire IBM Silicon Valley Laboratory Brent Gross Robert Indrigo
xvii
Mike Winer IBM Toronto Laboratory Paolo Bruni Yvonne Lyon IBM International Technical Support Organization, San Jose Center Vasilis Karras Rich Conway Bob Haimowitz IBM International Technical Support Organization, Poughkeepsie Center
Comments welcome
Your comments are important to us! We want our Redbooks to be as helpful as possible. Please send us your comments about this or other Redbooks in one of the following ways: Fax the evaluation form found in IBM Redbooks review on page 393 to the fax number shown on the form. Use the online evaluation form found at ibm.com/redbooks Send your comments in an Internet note to redbook@us.ibm.com
xviii
Part 1. Background
specifying which classes your program needs, using operating system neutral class and package name instead. Objects are central to Java. Understanding how they are created and used is the first task for a Java programmer. Therefore, if you are not familiar with object-oriented programming, you will need to spend some time to acquire an understanding of this concept. This book covers the use of the Java programming language for coding stored procedures within DB2 UDB. We make the assumption that the reader understands basic concepts of Java, such as: Classes Methods Packages JAR files Java Development Kit (JDK) Java environment variables, such as CLASSPATH A number of excellent publications exist that can assist you in understanding these concepts (see Appendix G, Related publications on page 359).
1.2.2.1 The OS/390 High Performance Java Compiler The OS/390 High Performance Java Compiler is part of ET/390. Its purpose is to bind standard Java bytecode into native S/390 object code, which can then run as an executable.
Note
The high performance Java compiler is also known by several other names, including; VisualAge for Java Enterprise Toolkit for OS/390 Byte Code Binder ET/390 Byte Code Binder OS/390 Byte Code Binder For convenience, we will simply refer to the compiler as the HPJ within this book. The HPJ was created for two major reasons: To allow performance-critical Java code to execute more quickly than it would in the interpretive OS/390 Java Virtual Machine (JVM) environment. To allow Java code to be executed in environments that do not have their own JVM (such as DB2 stored procedure address spaces). The HPJ is therefore necessary if you wish to implement Java stored procedures on DB2 for OS/390. Although use of the HPJ creates an OS/390 specific module that will not execute in other environments, code portability is retained, as the Java source and bytecode files are still completely standard. In the future, DB2 stored procedure address spaces will support a JVM environment, allowing the use of stored procedures executing as native Java bytecode, and the HPJ will not be necessary. However, depending upon the level of performance achieved with the JVM implementation, it is possible that you will still want to use the HPJ for performance-critical stored procedures. 1.2.2.2 Other ET/390 tools ET/390 provides a number of additional tools to assist with S/390 Java development and testing. These include: A workstation-based interactive debugger, to allow you to debug your code as it runs.
A workstation-based performance analyzer, to allow you to graphically identify parts of your programs that may be worth tuning. These and other facilities are described in the Java Programming Guide for OS/390, SG24-5619.
2.1.1.1 JDBC and DB2 UDB for OS/390 JDBC is supported by VisualAge for Java based tools. It requires DB2 Version 5 or higher and OS/390 Version 2 release 5 or higher. As shown in Figure 1, JDBC-based Java programs are compiled into Java bytecode using the javac compiler, which is part of the Java Development Toolkit (JDK). Once compiled, they can be executed in the OS/390 JVM. To use JDBC, your program needs to include the java.sql package and to invoke methods according to the JDBC specification. The JDBC driver for DB2 UDB for OS/390 is a Type-2 driver, which gives substantial performance improvements to JDBC applications.
information about the SQL operations in the program. SQLJ profiles are vendor-independent, and need to be customized for the target database in a later step. By default, SQLJ profile filenames have .ser as extension. The SQLJ translator generates a profile for each connection context class in the application (a connection context class corresponds to a particular type of database schema to which your program connects). SQLJ profiles are not produced if there are no SQLJ executable statements in the SQLJ source code. 2. Compile the Java source code output by the translator, using the javac command. This results in one or more .class files containing Java bytecode. By default, the SQLJ command invokes the Java compiler automatically. 3. Customize the SQLJ profiles for DB2, which is done using the db2profc command. Profiles are vendor-independent; therefore, they must be customized. The customization process essentially transforms the generic SQLJ profiles into DB2-specific DBRMs, which can then be bound to DB2 in the normal way. See Part 2, Developing Java stored procedures on page 17 for detailed information.
...
In contrast, JDBC uses a series of generic methods to perform the data access, which is almost always more verbose than the SQLJ equivalent. For example, the JDBC equivalent of the SQLJ code above would look like this:
... System.out.println("Add_customer: about to get hi cust no"); sql = "SELECT HI_CUST_NO+1 " + "FROM HI_CUST_NO"; res = stmt.executeQuery(sql); res.next(); new_cust_no = res.getInt(1); ...
You can see that the JDBC version requires more code, and a knowledge of JDBC methods such as executeQuery, next and getInt. Note also that JDBC does not support the SELECT ... INTO statement. 2.1.3.2 Performance: static versus dynamic SQL Another major differentiator between JDBC and SQLJ can be the way in which your programs perform. JDBC presents a string containing an SQL statement to the database at runtime (which may have just been constructed within the Java application). The first time DB2 gets to see the SQL is when it is actually executed, so all JDBC calls, by their very nature, consist of dynamic SQL . When DB2 is passed the SQL statement, it must perform a number of steps to prepare the statement before it is able to execute it (including syntax checking, authorization checking, and access path selection), and this can often require longer to perform than the actual SQL itself. SQLJ is able to use static SQL by actually embedding the SQL statements within the application code. The SQLJ program preparation process extracts this SQL and binds it against the database, allowing DB2 to perform all of the checks and access path selection as a one-off process. At run time, DB2 uses the pre-prepared access plan and is able to immediately execute the SQL. In general, an SQLJ statement should therefore run more quickly than an equivalent JDBC statement1 .
10
2.1.3.3 Authorization The way in which authorization is handled can also differ, due to the way in which dynamic and static SQL authority checking is managed by DB2. As JDBC uses dynamic SQL, all authorization checking is performed at execution time. By default, DB2 will use the authorization ID of the application process for authorization of dynamic SQL statements. This requires granting sufficient authority directly to that authorization ID to be able to execute any of the SQL statements the JDBC program is likely to submit. SQLJ uses static SQL, so all authority checking is performed at BIND time. The BIND authorization ID is used in the authorization checks, and all that is required at run time is authority to execute the DB2 package associated with the stored procedure (and, for DB2 for OS/390 V6, the authority to run the stored procedure itself). This is a complex area that is covered in more detail in 9.3, Client authorization issues on page 174. 2.1.3.4 So which access method should I use? As usual, the answer to this question is It depends! As a general rule, we recommend that you use SQLJ wherever possible, as it offers significant benefits in developer productivity, performance, and security when compared to JDBC. However, you may encounter situations that require the ability to build the SQL statement within your Java application at run time, and only JDBCs dynamic SQL support can offer this sort of additional flexibility. In these cases, you may be able to benefit from the fortunate situation that both SQLJ and JDBC can be mixed in the same source logic. The majority of the sample code included in this book and the accompanying CD-ROM is provided in both SQLJ and JDBC versions.
Note that DB2 for OS/390 has introduced several features (such as the dynamic statement cache) that help to reduce the overheads associated with dynamic SQL and bring JDBC and SQLJ performance closer together. The degree to which these features will assist the performance of your JDBC calls will depend on a large number of factors - your mileage may vary.
11
The JDBC standard defines four different types of driver, as defined in Table 1 below.
Table 1. JDBC driver types
Type
Description
Portable? a
1 2 3 4
JDBC/ODBC Bridge Native - API part Java Net - protocol all Java Native - protocol all Java
No No Yes Yes
a. Note that this column refers to the portability of the driver itself across various platforms and operating systems, and not the portability of the application using it.
IBM currently supplies Type 2 and some Type 3 drivers for the various members of the DB2 family, as detailed in the following sections. 2.1.4.1 DB2 UDB for OS/390 DB2 UDB for OS/390 Version 5 and Version 6 have Type 2 drivers available as part of the SQLJ support APAR (this SQL service APAR is a prerequisite for Java stored procedures - see 4.1.1, Prerequisites on page 57 for further information). 2.1.4.2 DB2 UDB for UNIX, NT and OS/2 Both Version 6 and Version 7 of DB2 UDB for UNIX, Windows, and OS/2 provide Type 2 and Type 3 drivers. These are installed along with the rest of the Java support components if so requested during the DB2 UDB install process.
12
Stored procedures offer a number of powerful advantages for distributed application development. These include the following; Common business functions can be encapsulated in stored procedures and made universally accessible, promoting code re-use and consistency, and providing support for object-oriented application design. Performance can be significantly improved for distributed applications that require several SQL calls to be made by the client against a remote database. Instead of one trip across the network for each of these calls, they can be combined and executed locally within a stored procedure so only a single trip across the network is needed. This performance improvement can also create subsequent benefits in reducing lock contention. Security can be enhanced, as developers are only able to work with the stored procedure input and output parameters, and are prevented from viewing or altering the underlying code that implements the business function. DB2 stored procedures are integrated with and exploit some of the key OS/390 scalability and availability features. Stored procedures benefit from OS/390 Workload Manager (WLM) address spaces, allowing individual stored procedures to be scheduled according to their business priority and optimized for the system workload. In addition, multiple WLM-controlled address spaces for DB2 stored procedures provide improved program isolation.
13
DB2 Version DB2 for OS/390 Java SQL Procedures Languagea COBOL C/C++ PL/1 REXX Version 5 with APAR PQ31845 Version 6 with APAR PQ31846 Version 6 with APARS PQ29782, PQ30467 & PQ433026 Version 4 Version 4 Version 4 Version 5 with APAR PQ29706 Version 6 with APAR PQ30219 DB2 for UNIX, Windows NT, and OS/2 Version 5 Version 7
a. SQL Procedures Language is based on PSM, or Persistent Stored Modules, which is an ISO standard procedural SQL language. b. Use of REXX for stored procedures on the UNIX, Windows and OS/2 platforms is not encouraged for security reasons.
This book concentrates on the development of stored procedures written in the Java language.
14
SQLJ Translator
Java Compiler
Figure 2 shows a similar diagram for DB2 on the UNIX, OS/2, and Windows platforms. You can see that the picture here is somewhat simpler, because there is no requirement to compile Java stored procedures into native operating system instructions before execution (as there is on the OS/390 platform).
SQLJ Translator
Java Compiler
DB2 Stored Procedure Java Virtual Machine Unix, Windows, OS/2 DB2 UDB for Unix, Windows, OS/2
15
16
17
18
3.1 Overview
The Java examples in this book explore the initial programs of a mythical start-up software company named ACME. This company chose to develop their customer management systems using DB2 UDB.
19
S/390
Websphere
HTTP Server
Java Servlet
Internet
DB2
20
Type
Table
Name
CUSTOMER PRODUCT ORDER ORDER_ITEM
Description
Stores customer details Stores product details Stores order details Stores order item details Adds new customer details into ACMEs system. Summarizes order information by order number or customer number in groups of 5 items Reads new customer / order information from a batch file and invokes the Add_cust_order stored procedure.
Stored Procedure
Add_customer Query_oi_summ
COBOL Program
ADDCUST
To provide practical examples that covered as many different situations as possible, we produced versions of the stored procedures and clients that ran on different platforms OS/390, AIX and Windows NT and used different APIs to access DB2 data such as JDBC only, SQLJ only, and a combination of both JDBC and SQLJ. We also produced a COBOL version of the OS/390 programs, to allow those readers familiar with that language to more easily interpret what the Java programs are doing. Finally, to allow us to make use of some of the new network computing features being introduced to DB2 while retaining compatibility with older releases, we produced two versions of the code. The standard version uses features available today across the entire DB2 family. The enhanced version uses some of the new features available in the DB2 family. The enhanced version also includes the Query_oi_summ stored procedure, which explores advanced topics in Java stored procedures.
21
The stored procedures were packaged according to the following naming conventions:
ACMEapf where
J for JDBC S for SQLJ B for Both JDBC and SQLJ C for COBOL O for OS/390 U for UNIX (AIX) N for Windows NT S for standard E for enhanced
These Java package names are shown in full in Table 4 below. The Java package names in bold italics are included in the sample code that accompanies this book (see Appendix B, Sample code, DDL, and preparation scripts on page 287).
Table 4. Sample Code Java package names
API
Platform
JDBC
ACMEJOS ACMEJUS ACMEJNS ACMESOS ACMESUS ACMESNS ACMEBOS ACMEBUS ACMEBNS ACMECOS
N/A N/A
ACMEJUE ACMEJNE
ACMESOE
SQLJ
ACMESUE ACMESNE
ACMEBOE ACMEBUE ACMEBNE
COBOL
ACMECOE
N/A N/A
22
In addition, client applications invoking these stored procedures were written in Java and COBOL. For the Java client applications, there is a JDBC version and a separate SQLJ version.
J for JDBC S for SQLJ B for Both JDBC and SQLJ C for COBOL S for standard
f spname
23
For DB2 UDB for OS/390 V6 and DB2 UDB for UNIX, Windows, OS/2 (the enhanced feature level in our examples), we were able to use schemas to qualify the stored procedure name, with the schema name being set to the Java package name that the example belonged to.
24
25
// find the next customer number to use //////////////////////////////////////////////////////// mark[0] = "Add_customer: createStatement"; Statement stmt = con.createStatement(); stmt.execute("set schema = ACMES"); mark[0] = "Add_customer: Get high cust no"; sql = "SELECT HI_CUST_NO+1 " + "FROM HI_CUST_NO"; res = stmt.executeQuery(sql); //////////////////////////////////////////////////////// // there will be only one number so use next() to // get the first row //////////////////////////////////////////////////////// res.next(); new_cust_no = res.getInt(1); //////////////////////////////////////////////////////// // update the table -- note that this should be // modified in a multi-user application //////////////////////////////////////////////////////// mark[0] = "Add_customer: Update high cust no"; sql = "UPDATE HI_CUST_NO " + "SET HI_CUST_NO = ?"; pstmt = con.prepareStatement(sql); pstmt.setInt(1, new_cust_no); updateCount = pstmt.executeUpdate(); //////////////////////////////////////////////////////// // insert a new customer using the calculated cust no //////////////////////////////////////////////////////// mark[0] = "Add_customer: Insert new cust row"; sql = "INSERT INTO CUSTOMER " + "( " + "CUST_NO, " + "CUST_FIRSTNAME, " + "CUST_LASTNAME, " + "CUST_ADDRESS " + ") " + "VALUES" + "( " + "? , " + "'"+ in_cust_firstname + "' , " + "'"+ in_cust_lastname + "' , " + "'"+ in_cust_address + "'" + " )"; pstmt = con.prepareStatement(sql);
26
pstmt.setInt(1, new_cust_no); updateCount = pstmt.executeUpdate(); out_cust_no[0] = new_cust_no; mark[0] = "Add_customer: Complete"; if (stmt != null) stmt.close(); if (con != null) con.close(); } // try catch (SQLException e) { mark_error_text[0] = "SQLException raised, SQLState = " + e.getSQLState() + " SQLCODE = " + e.getErrorCode() + " :" + e.getMessage(); } catch (Exception e) { mark_error_text[0] = "Add_customer: major exception caught: " + e.getMessage(); } } // add_customer }
public class Add_customer { public static void add_customer ( String in_cust_firstname, String in_cust_lastname, String in_cust_address, int[] out_cust_no, String[] mark, String[] mark_error_text
27
) throws SQLException, Exception { System.out.println("Add_customer: start - SQLJ version"); try { //////////////////////////////////////////////////////// // mark_error_text and mark are used to report // errors trapped in the catch block //////////////////////////////////////////////////////// int new_cust_no; mark_error_text[0] = "OK"; mark[0] = "Add_customer: Get context"; System.out.println("Add_customer: about to getDefaultContext" ); DefaultContext ctx = DefaultContext.getDefaultContext(); mark[0] = "Add_customer: insert into customer"; #sql { INSERT INTO CUSTOMER ( CUST_FIRSTNAME, CUST_LASTNAME, CUST_ADDRESS ) VALUES ( :in_cust_firstname, :in_cust_lastname, :in_cust_address ) }; // #sql ///////////////////////////////////////////////////////////// // get the value of the identity column which is passed back ///////////////////////////////////////////////////////////// mark[0] = "Add_customer: retrieve cust no"; #sql { SELECT CUST_NO INTO :new_cust_no FROM GTT_CUST_NO }; //#sql out_cust_no[0] = new_cust_no; mark[0] = "Add_customer: complete"; } // try catch (SQLException e)
28
{ mark_error_text[0] = "Add_Customer: SQLException raised: " + "SQLState = " + e.getSQLState() + " SQLCODE = " + e.getErrorCode() + " :" + e.getMessage(); System.out.println("Add_customer: caught sqlexception"); System.out.println("Add_customer: "+ mark_error_text[0]); e.printStackTrace(); } catch (Exception e) { mark_error_text[0] = "Add_customer: major exception caught: " + e.getMessage(); System.out.println("Add_customer: caught java exception"); System.out.println("Add_customer: "+ mark_error_text[0]); e.printStackTrace(); } } // add_customer }
29
02 77 77 77 77
ERROR-TEXT-LEN PIC S9(9) ERR-CODE ERR-MINUS LINE-EXEC PIC 9(8) PIC X PIC X(20)
OCCURS 3 TIMES INDEXED BY ERROR-INDEX. COMP VALUE +80. VALUE 0. VALUE SPACE. VALUE SPACE.
LINKAGE SECTION. 01 CUST-FNAME PIC X(20). 01 CUST-LNAME PIC X(20). 01 CUST-ADDR PIC X(30). 01 CUST-NO PIC S9(9) COMP. 01 MARK PIC X(40). 01 MARK-ERROR-TEXT PIC X(240). * ***************************************************** * Procedure Division * ***************************************************** * PROCEDURE DIVISION USING CUST-FNAME, CUST-LNAME, CUST-ADDR, CUST-NO, MARK, MARK-ERROR-TEXT. EXEC SQL WHENEVER SQLERROR GOTO SQL-ERROR END-EXEC.
DISPLAY "ADD_CUSTOMER: START". MOVE "OK" TO MARK-ERROR-TEXT. * * Get new customer number * * MOVE "ADD_CUSTOMER: GET HIGH CUSTOMER NO" TO MARK. DISPLAY "ADD_CUSTOMER: GET HIGH CUSTOMER NO". EXEC SQL SELECT HI_CUST_NO+1 INTO :NEW-CUST-NO FROM HI_CUST_NO END-EXEC. * * Update high customer number * * MOVE "ADD_CUSTOMER: UPDATE HIGH CUSTOMER NO" TO MARK. DISPLAY "ADD_CUSTOMER: UPDATE HIGH CUSTOMER NO". EXEC SQL UPDATE HI_CUST_NO
30
SET HI_CUST_NO = :NEW-CUST-NO END-EXEC. * * Insert into Customer table * MOVE "ADD_CUSTOMER: INSERT INTO CUSTOMER" TO MARK. DISPLAY "ADD_CUSTOMER: INSERT INTO CUSTOMER". EXEC SQL INSERT INTO CUSTOMER (CUST_NO, CUST_FIRSTNAME, CUST_LASTNAME, CUST_ADDRESS) VALUES (:NEW-CUST-NO, :CUST-FNAME, :CUST-LNAME, :CUST-ADDR) END-EXEC. MOVE NEW-CUST-NO TO CUST-NO. MOVE "ADD_CUSTOMER: COMPLETE" TO MARK. DISPLAY "ADD_CUSTOMER: COMPLETE". EXIT-PROG. GOBACK.
SQL-ERROR. MOVE SQLCODE TO ERR-CODE . IF SQLCODE < 0 THEN MOVE '-' TO ERR-MINUS. DISPLAY "ADD_CUSTOMER: NEGATIVE SQLCODE ENCOUNTERED". DISPLAY "ADD_CUSTOMER: SQLCODE = " ERR-MINUS ERR-CODE. CALL 'DSNTIAR' USING SQLCA ERROR-MESSAGE ERROR-TEXT-LEN. IF RETURN-CODE < 8 PERFORM ERROR-PRINT VARYING ERROR-INDEX FROM 1 BY 1 UNTIL ERROR-INDEX GREATER THAN 3 STRING ERROR-TEXT(1) ERROR-TEXT(2) ERROR-TEXT(3) DELIMITED BY SIZE INTO MARK-ERROR-TEXT ELSE DISPLAY "ADD_CUSTOMER: BAD RETURN CODE FROM DSNTIAR" DISPLAY "ADD_CUSTOMER: " RETURN-CODE. GO TO EXIT-PROG. ERROR-PRINT. DISPLAY "ADD_CUSTOMER: " ERROR-TEXT (ERROR-INDEX).
31
public class Add_customer { public static void add_customer ( String in_cust_firstname, String in_cust_lastname, String in_cust_address, int[] out_cust_no, String[] mark, String[] mark_error_text ) throws SQLException, Exception { try { //////////////////////////////////////////////////////// // mark_error_text and mark are used to report // errors trapped in the catch block //////////////////////////////////////////////////////// ResultSet res; String sql; int new_cust_no; mark_error_text[0] = "OK"; new_cust_no = 0;
//////////////////////////////////////////////////////// // get default contect and connection //////////////////////////////////////////////////////// mark[0] = "Add_customer: Set context"; DefaultContext ctx = DefaultContext.getDefaultContext(); mark[0] = "Add_customer: getConnection"; Connection con = DriverManager.getConnection( "jdbc:default:connection");
32
mark[0] = "Add_customer: createStatement"; Statement stmt = con.createStatement(); mark[0] = "Add_customer: Get high cust no"; //////////////////////////////////////////////////////// // determine high customer number using JDBC //////////////////////////////////////////////////////// sql = "SELECT HI_CUST_NO+1 " + "FROM ACMES.HI_CUST_NO"; res = stmt.executeQuery(sql); while (res.next()) { new_cust_no = res.getInt(1); } mark[0] = "Add_customer: Update high cust no"; //////////////////////////////////////////////////////// // update the table using SQLJ //////////////////////////////////////////////////////// #sql { UPDATE HI_CUST_NO SET HI_CUST_NO = :new_cust_no }; // #sql mark[0] = "Add_customer: Insert new cust row"; //////////////////////////////////////////////////////// // now can update the Customer table, using SQLJ //////////////////////////////////////////////////////// #sql { INSERT INTO CUSTOMER ( CUST_NO, CUST_FIRSTNAME, CUST_LASTNAME, CUST_ADDRESS ) VALUES ( :new_cust_no , :in_cust_firstname , :in_cust_lastname , :in_cust_address ) }; // #sql
33
out_cust_no[0] = new_cust_no; //set output cust no mark[0] = "Add_customer: Complete"; } // try catch (SQLException e) { mark_error_text[0] = "Add_Customer: SQLException raised: " + "SQLState = " + e.getSQLState() + " SQLCODE = " + e.getErrorCode() + " :" + e.getMessage(); } catch (Exception e) { mark_error_text[0] = "Add_customer: major exception caught: " + e.getMessage(); } } // add_customer }
34
// 4) handling nulls returned from a query // // NOTE: if this stored procedure fails hard (dumps) // it may be because you have not created // a TMP directory on NT //////////////////////////////////////////////////// package ACMEJNE ; import import import import import import import import java.sql.*; java.math.*; java.io.*; java.io.StringWriter; java.io.PrintWriter; java.text.DateFormat; java.util.Date; java.text.SimpleDateFormat;
public class Query_oi_summ { public static void query_oi_summ ( String in_cust_no, String in_order_no, String[] mark, String[] mark_error_text, ResultSet[] out_rs ) throws SQLException, Exception { PrintWriter pwx = null; // declare outside try for catch to close final boolean dbg = true; // this could be set by an input parm try { //////////////////////////////////////////////////////// // establish debugging file: name is timestamped //////////////////////////////////////////////////////// Date debugDate = new Date(); DateFormat dateFormat = DateFormat.getDateTimeInstance(); ((SimpleDateFormat)dateFormat).applyPattern("MM_dd_HH_mm_ss"); String debugdf = dateFormat.format(debugDate); if (dbg) { pwx = new PrintWriter( new FileWriter("/tmp/" + debugdf + ".txt"), true); } //////////////////////////////////////////////////////// // mark_error_text and mark are used to report
35
// errors trapped in the catch block //////////////////////////////////////////////////////// mark_error_text[0] = "OK"; mark[0] = "Query_oi_summ: getConnection"; Connection con = DriverManager.getConnection("jdbc:default:connection"); //////////////////////////////////////////////////////// // establish where clause: either an order number is // sent in or a customer number is sent in //////////////////////////////////////////////////////// String where_clause = ""; if (null != in_cust_no) where_clause = " where OI.ord_item_prod_no = P.prod_no " + " and OI.ord_item_ord_no = O.ord_no " + " and O.ord_cust_no = C.cust_no " + " and C.cust_no = " + in_cust_no; else where_clause = " where OI.ord_item_ord_no = " + in_order_no + " and OI.ord_item_prod_no = P.prod_no" ; //////////////////////////////////////////////////////// // construct SQL statement and execute the Query //////////////////////////////////////////////////////// String sql = "select sum(OI.ORD_ITEM_QTY) Total_Qty ," + " P.prod_no Product#," + " P.prod_desc DESCRIPTION " + " from acmee.order_item OI, acmee.product P," + " acmee.order O, acmee.customer C" + where_clause + " group by P.prod_no, P.prod_desc " + " order by P.prod_desc "; if (dbg) pwx.println("sql =>" + sql + "<="); if (dbg) pwx.println("in_cust_no=" + in_cust_no); if (dbg) pwx.println("in_order_no=" + in_order_no); mark[0] = "Query_oi_summ: createStatement"; if (dbg) pwx.println(mark[0]); Statement stmt = con.createStatement(); mark[0] = "Query_oi_summ: executeQuery"; if (dbg) pwx.println(mark[0]); ResultSet rs = stmt.executeQuery(sql); if (dbg) pwx.println("post stmt.executeQuery"); String insert_vals = ""; Statement stmt2 = con.createStatement(); ////////////////////////////////////////////////////////
36
// walk thru the result set, using the returned values // to insert to the correct category in the // summary table //////////////////////////////////////////////////////// if (rs == null) { mark_error_text[0] = "Query_oi_summ: query failed for " + sql; } else { while (rs.next()) { if (dbg) pwx.println("rs=" + rs.getString(1) + "," + rs.getString(2) + "," + rs.getString(3)); if (rs.getInt(1) < 6) insert_vals = " 'X' , ' ', ' ' "; else if (rs.getInt(1) < 11) insert_vals = " ' ' , 'X', ' ' "; else insert_vals = " ' ' , ' ', 'X' "; ////////////////////////////////////////////////////////////// // determine if production description is SQL null, in // which case we specifically tell JDBC that we are // inserting a null ////////////////////////////////////////////////////////////// String ins_prod_desc = ""; String ret_prod_desc = rs.getString(3); if (rs.wasNull()) ins_prod_desc = "NULL"; else ins_prod_desc = "'" + rs.getString(3) + "'" ; ////////////////////////////////////////////////////////////// // finally have all the calculated pieces to build the // full insert statement and execute it ////////////////////////////////////////////////////////////// String sql2 = "insert into acmee.order_item_summ " + "(prod_desc, qty_1_to_5,QTY_6_TO_10,QTY_11_PLUS) " + "values(" + ins_prod_desc + "," + insert_vals + ")"; if (dbg) pwx.println("sql2=" + sql2); stmt2.executeUpdate(sql2); } // while
37
} // else stmt.close(); stmt2.close(); if (dbg) pwx.println("stmt and stmt2 close"); //////////////////////////////////////////////////////// // get the summarized information into a ResultSet // to return to the client //////////////////////////////////////////////////////// Statement stmt3 = con.createStatement(); if (dbg) pwx.println("stmt3 executeQuery"); out_rs[0] = stmt3.executeQuery("select * from acmee.order_item_summ"); if (con != null) con.close(); if (dbg) pwx.println("graceful end"); if (dbg) pwx.close(); } // try catch (IOException e) { mark_error_text[0] = "Query_oi_summ: IOException: " + e.getMessage(); StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); e.printStackTrace(pw); mark_error_text[0] += ":printStackTrace=" + sw.toString() ; if (dbg) pwx.close(); } catch (SQLException e) { mark_error_text[0] = "Query_oi_summ: " + "SQLException raised, SQLState = " + e.getSQLState() + " SQLCODE = " + e.getErrorCode() + " :" + e.getMessage(); StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); e.printStackTrace(pw); mark_error_text[0] += ":printStackTrace=" + sw.toString() ; if (dbg) pwx.close(); } catch (Exception e) { mark_error_text[0] = "Query_oi_summ: Exception: " + e.getMessage(); StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); e.printStackTrace(pw); mark_error_text[0] += ":printStackTrace=" + sw.toString() ;
38
if (dbg) } } // query_oi_summ }
pwx.close();
////////////////////////////////////////// // iter1 is a named iterator // iter2 is a positional iterator ////////////////////////////////////////// #sql iterator Defined_iter1 (int Total_Qty , int Product_no , String Description); #sql iterator Defined_iter2 (String, int, int, int); public class Query_oi_summ { public static void query_oi_summ ( String in_cust_no, String in_order_no,
39
) { PrintWriter pwx = null; final boolean dbg = false; String all_errs; try { Defined_iter1 iter1 = null; //////////////////////////////////////////////////////// // establish debugging file: name is timestamped //////////////////////////////////////////////////////// Date debugDate = new Date(); DateFormat dateFormat = DateFormat.getDateTimeInstance(); ((SimpleDateFormat)dateFormat).applyPattern("MM_dd_HH_mm_ss"); String debugdf = dateFormat.format(debugDate); if (dbg) { pwx = new PrintWriter( new FileWriter("/tmp/" + debugdf + ".txt"),true ); } if (dbg) pwx.println("Query_oi_summ: SQLJ version"); //////////////////////////////////////////////////////// // mark_error_text and mark are used to report // errors trapped in the catch block //////////////////////////////////////////////////////// mark_error_text[0] = "OK"; //////////////////////////////////////////////////////// // query based either upon the input customer number // or the input order number //////////////////////////////////////////////////////// if (null != in_cust_no) { int int_in_cust_no = Integer.parseInt(in_cust_no.trim()); if (dbg) pwx.println("Query_oi_summ: in_cust_no not null, =" + in_cust_no); #sql iter1 = { select sum(OI.ORD_ITEM_QTY) Total_Qty , OI.ord_item_prod_no Product_no, P.prod_desc Description from acmee.order_item OI, acmee.product P,
40
acmee.order O, acmee.customer C where OI.ord_item_prod_no = P.prod_no and OI.ord_item_ord_no = O.ord_no and O.ord_cust_no = C.cust_no and C.cust_no = :int_in_cust_no group by OI.ord_item_prod_no, P.prod_desc order by OI.ord_item_prod_no }; // #sql } else { int int_in_order_no = Integer.parseInt(in_order_no.trim()); if (dbg) pwx.println("Query_oi_summ: in_order_no not null, =" +in_order_no); #sql iter1 = { select sum(OI.ORD_ITEM_QTY) Total_Qty , OI.ord_item_prod_no Product_no, P.prod_desc Description from acmee.order_item OI, acmee.product P where OI.ord_item_prod_no = P.prod_no and OI.ord_item_ord_no = :int_in_order_no group by OI.ord_item_prod_no, P.prod_desc order by OI.ord_item_prod_no }; // #sql } // else //////////////////////////////////////////////////////// // walk thru the iterator, using the returned values // to insert to the correct category in the // summary table //////////////////////////////////////////////////////// if (dbg) pwx.println("Query_oi_summ: post selects"); if (null == iter1) { mark_error_text[0] = "Query_oi_summ: query failed"; if (dbg) pwx.println("Query_oi_summ:" + mark_error_text[0]); } else { while (iter1.next()) { if (dbg) pwx.println("iter1=" + iter1.Total_Qty() + "," +
41
iter1.Product_no() + "," + iter1.Description()); String five_or_below = " "; String six_to_ten = " "; String eleven_and_above = " "; if (dbg) pwx.println("about to get total variable"); int total = iter1.Total_Qty(); if (total < 6) five_or_below = "X"; else if (total < 11) six_to_ten = "X"; else eleven_and_above = "X"; if (dbg) pwx.println("just set X marks");
String ins_prod_desc = ""; String ret_prod_desc = iter1.Description(); ins_prod_desc = ret_prod_desc ; ////////////////////////////////////////////////////////////// // finally have all the calculated pieces to build the // full insert statement and execute it ////////////////////////////////////////////////////////////// if (dbg) pwx.println("about to insert to ois with " + "/" + ins_prod_desc + "/" + five_or_below + "/" + six_to_ten + "/" + eleven_and_above + "/" ); #sql { insert into acmee.order_item_summ (prod_desc, qty_1_to_5, QTY_6_TO_10, QTY_11_PLUS) values (:ins_prod_desc, :five_or_below , :six_to_ten , :eleven_and_above) }; // #sql } // while } // else iter1.close(); //////////////////////////////////////////////////////// // get the summarized information into an Iterator // to return to the client //////////////////////////////////////////////////////// if (dbg) pwx.println("Query_oi_summ: about to do iter2"); Defined_iter2 iter2; #sql iter2 = { select prod_desc, qty_1_to_5, QTY_6_TO_10, QTY_11_PLUS
42
from acmee.order_item_summ }; // #sql out_rs[0] = iter2.getResultSet(); //////////////////////////////////////////////////////// // walk thru iterator here -- data will not be available // in client (according to design) after viewing here //////////////////////////////////////////////////////// if (dbg) { ResultSet tmp_rs = iter2.getResultSet(); if (dbg) pwx.println("Query_oi_summ: tmp_rs has data"); ResultSetMetaData stmtInfo = tmp_rs.getMetaData(); int numOfColumns = stmtInfo.getColumnCount(); //////////////////////////////////////// // print column labels //////////////////////////////////////// for( int i=1; i <= numOfColumns; i++ ) { if (dbg) pwx.print(stmtInfo.getColumnLabel(i)); if( i != numOfColumns ) { if (dbg) pwx.print(" , "); } } if (dbg) pwx.println(""); //////////////////////////////////////// // print data in table //////////////////////////////////////// while( tmp_rs.next() ) { for( int i=1; i <= numOfColumns; i++ ) { String tmp_get_desc = tmp_rs.getString(i); if (tmp_rs.wasNull()) { if (dbg) pwx.print("Null Description } else { if (dbg) pwx.print(tmp_get_desc); } if( i != numOfColumns ) { if (dbg) pwx.print(" , "); } } //for
");
43
if (dbg) pwx.println(""); } // while } // else if (dbg) //iter2.close(); if (dbg) pwx.println("Query_oi_summ: graceful end"); if (dbg) pwx.close(); } // try catch (IOException e) { all_errs = "Query_oi_summ: IOException: " + e.getMessage(); StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); e.printStackTrace(pw); all_errs += ":printStackTrace=" + sw.toString() ; if (dbg) pwx.println(all_errs); if (dbg) pwx.close(); mark_error_text[0] = all_errs.substring(0,199); } catch (SQLException e) { all_errs = "Query_oi_summ: " + "SQLException raised, SQLState = " + e.getSQLState() + " SQLCODE = " + e.getErrorCode() + " :" + e.getMessage(); StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); e.printStackTrace(pw); all_errs += ":printStackTrace=" + sw.toString() ; if (dbg) pwx.println(all_errs); if (dbg) pwx.close(); mark_error_text[0] = all_errs.substring(0,199); } catch (Exception e) { all_errs = "Query_oi_summ: Exception: " + e.getMessage(); StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); e.printStackTrace(pw); all_errs += ":printStackTrace=" + sw.toString() ; if (dbg) pwx.println(all_errs); if (dbg) pwx.close(); mark_error_text[0] = all_errs.substring(0,199); } } // query_oi_summ }
44
This sample ran on NT. A UNIX version would require no change. An OS/390 version requires changes to the driver name and to the URL. If the stored procedure is to be run under Version 5 of DB2 for OS/390, the source code would need to be modified where the schema name is used, because schemas were not a valid construct in Version 5.
import java.sql.*; ////////////////////////////////////////////////////////////////////////// / // jscall_Add_customer // // Simple Java application that calls the Add_customer stored procedure. // UNIX and NT version. // // example: java jscall_Add_customer ACMEJNS lastname firstname address ////////////////////////////////////////////////////////////////////////// / class jscall_Add_customer { static { try { Class.forName("COM.ibm.db2.jdbc.app.DB2Driver"); } catch (Exception e)
45
{ System.out.println("\nError loading DB2 Driver...\n"); e.printStackTrace(); } } // static public static void main(String argv[]) { Connection con = null; String url; String procName = ""; CallableStatement callStmt; try { if (argv.length < 4) { String usage_stmt = "Usage: java jscall_Add_customer schema lastname firstname address"; System.out.println(usage_stmt); System.exit(0); } // argv.length /////////////////////////////////////// // connect /////////////////////////////////////// System.out.println("Trying to connect..."); url = "jdbc:db2:ACMES"; con = DriverManager.getConnection(url); con.setAutoCommit(false); ///////////////////////////////////////////////// // prepare the call to the stored procedure ///////////////////////////////////////////////// System.out.println("Preparing call..."); procName = argv[0] + ".Add_customer"; String sql = "CALL " + procName + "(?,?,?,?,?,?)"; callStmt = con.prepareCall(sql); /////////////////////////////////////// // register the output parameters /////////////////////////////////////// System.out.println("Preparing parms..."); callStmt.registerOutParameter (4, Types.INTEGER); // cust nbr callStmt.registerOutParameter (5, Types.CHAR); // mark callStmt.registerOutParameter (6, Types.CHAR); // mark_error_text ///////////////////////////////////////
46
// set input parameters /////////////////////////////////////// callStmt.setString (1, argv[1]); // lastname callStmt.setString (2, argv[2]); // firstname callStmt.setString (3, argv[3]); // address /////////////////////////////////////// // call the stored procedure /////////////////////////////////////// System.out.println ("\nCall stored procedure named " + procName); callStmt.execute(); /////////////////////////////////////// // retrieve output parameters /////////////////////////////////////// int returned_cust_no = callStmt.getInt(4); String returned_mark = callStmt.getString(5); String returned_mark_error_text = callStmt.getString(6); //////////////////////////////////////// // report results and commit or rollback //////////////////////////////////////// if (returned_mark_error_text.trim().equals("OK")) { System.out.println ("returned_cust_no: " + returned_cust_no ); con.commit(); } else { System.out.println ("returned_mark: " + returned_mark ); System.out.println ("returned_mark_error_text:" + returned_mark_error_text.trim() ); con.rollback(); } /////////////////////////////////////// // tidy up /////////////////////////////////////// callStmt.close (); con.close (); } // try catch (Exception e) { System.out.println ("catch Exception being executed" ); try { con.close(); } catch (Exception x) { }
47
Note that the call is to CS_Add_Customer. This version was written for OS/390 DB2 Version 5 which does not support schemas. This client source code could be modified to take advantage of schemas in a Version 6 system. See 3.3.1, DB2 naming conventions on page 23 for more details.
IDENTIFICATION DIVISION. PROGRAM-ID. "CSCALLAC". ***************************************************** * * * ACME Software Company - Driver for proc ADDCUST * * * * This program calls the Add_customer stored * * procedure (COBOL version). * * * * The file PREPCALL contains the preparation JCL * * for this program. * * * ***************************************************** ENVIRONMENT DIVISION. DATA DIVISION. WORKING-STORAGE SECTION. EXEC SQL INCLUDE SQLCA END-EXEC. * PARM TO RECEIVE THE SQLCODE ERROR MESSAGES 01 ERROR-MESSAGE. 02 ERROR-LEN PIC S9(4) COMP VALUE +960. 02 ERROR-TEXT PIC X(120) OCCURS 8 TIMES INDEXED BY ERROR-INDEX. 77 ERROR-TEXT-LEN PIC S9(8) COMP VALUE +120.
48
77 77 77 01 01 01 01 01 01 01
ERR-CODE ERR-MINUS LINE-EXEC CUST-FNAME CUST-LNAME CUST-ADDRESS CUST-NO MARK MARK-ERROR-TEXT INDARRAY. 05 INDVAR1 05 INDVAR2 05 INDVAR3 05 INDVAR4 05 INDVAR5 05 INDVAR6
PIC 9(8) PIC X PIC X(20) PIC PIC PIC PIC PIC PIC PIC PIC PIC PIC PIC PIC
X(20). X(20). X(30). S9(9) COMP. X(80). X(240). COMP. COMP. COMP. COMP. COMP. COMP.
* ***************************************************** * Procedure Division * ***************************************************** * PROCEDURE DIVISION. DISPLAY "PROGRAM CSCALLAC STARTED" MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE MOVE 0 TO INDVAR1. 0 TO INDVAR2. 0 TO INDVAR3. 0 TO INDVAR4. 0 TO INDVAR5. 0 TO INDVAR6. "JOHN" TO CUST-FNAME. "SMITH" TO CUST-LNAME. "FROM VERSION ACMECOS" TO CUST-ADDRESS. 0 TO CUST-NO. SPACES TO MARK. SPACES TO MARK-ERROR-TEXT.
EXEC SQL CALL CS_ADD_CUSTOMER (:CUST-FNAME:INDVAR1, :CUST-LNAME:INDVAR2, :CUST-ADDRESS:INDVAR3, :CUST-NO:INDVAR4, :MARK:INDVAR5, :MARK-ERROR-TEXT:INDVAR6) END-EXEC.
49
MOVE SQLCODE TO ERR-CODE . IF SQLCODE < 0 THEN MOVE '-' TO ERR-MINUS PERFORM SQL-ERROR THRU END-SQL-ERROR. DISPLAY "SQLCODE FROM CALL = " ERR-MINUS ERR-CODE. DISPLAY "RETURN VALUES: " DISPLAY "Customer no: " Cust-no. DISPLAY "CALL RESULT 1: " MARK. DISPLAY "CALL RESULT 2: " MARK-ERROR-TEXT. EXIT-PROG. GOBACK. SQL-ERROR. CALL 'DSNTIAR' USING SQLCA ERROR-MESSAGE ERROR-TEXT-LEN. IF RETURN-CODE = ZERO PERFORM ERROR-PRINT VARYING ERROR-INDEX FROM 1 BY 1 UNTIL ERROR-INDEX GREATER THAN 8 ELSE DISPLAY "BAD RETURN CODE FROM DSNTIAR:" RETURN-CODE. END-SQL-ERROR. ERROR-PRINT. DISPLAY ERROR-TEXT (ERROR-INDEX).
50
{ System.out.println(" sscall_Add_customer"); Class.forName("COM.ibm.db2.jdbc.app.DB2Driver"); } catch (Exception e) { System.out.println("\nError loading DB2 Driver...\n"); e.printStackTrace(); } } // static public static void main(String argv[]) { String url; String procName = ""; try { if (argv.length != 3) { System.out.println("Usage: " + "java call_Add_customer lastname firstname address"); System.exit(0); } // argv.length /////////////////////////////////////// // connect /////////////////////////////////////// url = "jdbc:db2:ACMES"; Connection con = DriverManager.getConnection(url); con.setAutoCommit(false); SACCTX myconn = new SACCTX (con); SACCTX.setDefaultContext(myconn); String lastname = argv[0]; String firstname = argv[1]; String address = argv[2]; if (address.equalsIgnoreCase("null")) { System.out.println("setting address to null"); address = null; } int cust_no = 0; String returned_mark = "OK"; String returned_mark_error_text = "OK"; #sql[myconn]{ CALL ACMEJNS.Add_customer
51
(:IN lastname,:IN firstname,:IN address,:OUT cust_no, :OUT returned_mark,:OUT returned_mark_error_text)}; //////////////////////////////////////// // report results and commit or rollback //////////////////////////////////////// if (returned_mark_error_text.trim().equals("OK")) { System.out.println ("returned cust_no =" + cust_no); con.commit(); } else { System.out.println ("returned_mark: " + returned_mark ); System.out.println ("returned_mark_error_text:" + returned_mark_error_text.trim() ); con.rollback(); } /////////////////////////////////////// // tidy up /////////////////////////////////////// con.close (); } // try catch (Exception e) { System.out.println ("catch Exception being executed" e.printStackTrace (); } // catch } // main }
);
52
static { try { System.out.println("test Query_oi_summ"); Class.forName("COM.ibm.db2.jdbc.app.DB2Driver"); } catch (Exception e) { System.out.println("\nError loading DB2 Driver...\n"); e.printStackTrace(); } } // static public static void main(String argv[]) { Connection con = null; String url; String procName = ""; CallableStatement callStmt; if (argv.length != 3) { System.out.println("\nUsage: "); System.out.println(" java call_Query_oi_summ schema cust# order#"); System.out.println(" where one of them equals the string null"); System.out.println(" and the other a number. Example:"); System.out.println(" java call_Query_oi_summ ACMESUE 1 null"); System.exit(0); } // argv.length /////////////////////////////////////// // connect /////////////////////////////////////// try { System.out.println("Trying to connect..."); url = "jdbc:db2:ACMEE"; con = DriverManager.getConnection(url); con.setAutoCommit(false); ///////////////////////////////////////////////// // prepare the call to the stored procedure ///////////////////////////////////////////////// System.out.println("Preparing call..."); procName = argv[0] + ".Query_oi_summ"; String sql = "CALL " + procName + "(?,?,?,?)";
53
callStmt = con.prepareCall(sql); /////////////////////////////////////// // register the output parameters /////////////////////////////////////// System.out.println("Preparing parms..."); callStmt.registerOutParameter (3, Types.CHAR); // mark callStmt.registerOutParameter (4, Types.CHAR); // mark_error_text /////////////////////////////////////// // set input parameters /////////////////////////////////////// if (argv[1].equalsIgnoreCase("null")) callStmt.setNull (1, Types.CHAR); // null cust no else callStmt.setString (1, argv[1].trim()); // cust no if (argv[2].equalsIgnoreCase("null")) callStmt.setNull (2, Types.CHAR); // null order no else callStmt.setString (2, argv[2].trim()); // order no
/////////////////////////////////////// // call the stored procedure /////////////////////////////////////// System.out.println ("\nCall stored procedure named " + procName); callStmt.execute(); /////////////////////////////////////// // retrieve output parameters /////////////////////////////////////// String returned_mark = callStmt.getString(3); String returned_mark_error_text = callStmt.getString(4); //////////////////////////////////////// // report results and commit or rollback //////////////////////////////////////// if (returned_mark_error_text.trim().equals("OK")) { System.out.println ("returned OK" ); ResultSet rs = callStmt.getResultSet(); if (null == rs) { System.out.println("Oh oh, rs was null"); System.exit(1); }
54
ResultSetMetaData stmtInfo = rs.getMetaData(); if (null == stmtInfo) System.out.println("Oh oh, stmtInfo was null"); int numOfColumns = stmtInfo.getColumnCount(); //////////////////////////////////////// // print column labels //////////////////////////////////////// for( int i=1; i <= numOfColumns; i++ ) { System.out.print(stmtInfo.getColumnLabel(i)); if( i != numOfColumns ) System.out.print(" , "); } System.out.println(""); //////////////////////////////////////// // print data in table //////////////////////////////////////// while( rs.next() ) { for( int i=1; i <= numOfColumns; i++ ) { String get_desc = rs.getString(i); if (rs.wasNull()) System.out.print("Null Description "); else System.out.print(get_desc); if( i != numOfColumns ) System.out.print(" , "); } System.out.println(""); } con.commit(); } else { System.out.println ("returned_mark: " + returned_mark ); System.out.println ("returned_mark_error_text:" + returned_mark_error_text.trim() ); con.rollback(); } /////////////////////////////////////// // tidy up /////////////////////////////////////// callStmt.close (); con.close ();
55
} // try catch (Exception e) { System.out.println ("catch Exception being executed" e.printStackTrace (); } // catch } // main } // class
);
56
4.1.1 Prerequisites
To be able to use Java stored procedures on the S/390 platform, the following prerequisites exist: OS/390 V2 R6 or above, with UNIX Systems Services (USS) enabled. Java for OS/3901 , implementing JDK 1.1.8 (a non-priced OS/390 feature that can be downloaded from the Web or ordered directly from IBM).
It is possible to remove this prerequisite, provided you perform application development and some of your program preparation steps on another platform. However, we assume in this book that if you are developing stored procedures for the OS/390 platform, you will want to develop and prepare them there as well.
57
DB2 UDB for OS/390 Version 5 and above. For Version 5 and 6 with JDBC, SQLJ and Java stored procedure support are enabled, as shown in Table 5.
Table 5. DB2 for OS/390 Java APAR enhancements
Version
Version 5
Feature
APAR / PTF
PQ36643/UQ43898
JDBC and SQLJ driver including support for Visual Age Java'
Java Stored Procedures
Version 6
JDBC and SQLJ driver including support for Visual Age Java'
Java Stored Procedures
The prerequisites for VisuaAge for Java Enterprise Edition for OS/390 are in Table 6.
Table 6. VisualAge for Java Enterprise Edition for OS/390
Version
Version 2.0
Feature
VisualAge for Java, Enterprise Edition for OS/390
APAR / PTF
APAR PQ38178/ UQ43439 Rel. 2.01 APAR PQ38179/UQ43443 Rel. 2.02
Implementation of SQLJ support for both Version 5 and Version 6 will result in JDBC Type 2 drivers being installed. For the OS/390 platform and Java stored procedure support, the Type 2 drivers must be made available. This is done when you apply the APAR PQ36644. You can only support one JDBC driver at a time in OS/390, so the JDBC Type 1 driver will not exist in your system anymore! The Enterprise Toolkit for OS/390, part of VisualAge for Java, Enterprise Edition. This product provides the HPJ compiler needed for Java stored procedures on the OS/390 platform. OS/390 Recoverable Resource Services (RRS) and Workload Manager (WLM) Java stored procedures can only be run in a WLM-established stored procedure address space, so implementation of OS/390 Recoverable Resource Services (RRS) is necessary.
58
We recommend that you apply the USS APAR OW41492, which significantly improves performance of the multi-context support in the Type 2 driver.
Part of the install process for JDBC support involves running the db2genJDBC utility, which creates 4 generic DBRMs for use by JDBC programs (and JDBC stored procedures). We recommend that you bind these 4 DBRMs into DB2 packages belonging to a suitably named collection (we used DSNJDBC). This makes it simpler to ensure that these DB2 packages are picked up at execution time, as described in 9.1, DB2 plans and packages on page 167). 1. Design your library structure and naming standards. Java stored procedure support requires libraries to be set up both within the USS and the native OS/390 environment, and your job will be made much easier if you decide upon these in advance. 2. Tailor the .profile script for the stored procedure developers, to ensure that the necessary USS environment variables are being defined. 3. Set up the RRS environment for support of WLM-established stored procedures (if you have not already done so). 4. Set up a new WLM application environment for Java stored procedures, and the associated address space JCL.
WLM environments
While it is not strictly necessary for you to do so, we strongly advise you to set up at least one separate WLM application environment and JCL procedure to handle your Java stored procedures. 5. Create high performance Java versions of the JDBC/SQLJ drivers.
59
6. Set up the JAVAENV data set, and add an associated DD card to the WLM stored procedure address space JCL. JAVAENV contains the USS environmental variables (such as CLASSPATH and LIBPATH) that will be allocated within the WLM stored procedure address space. 7. Tailor the contents of the SQLJ properties file and cursors file, to ensure that correct values are being set. These tasks are described in more detail in the sections that follow.
Type
USS
Description
Sample Name
/USR/LPP/HPJ/LIB
HPJ base libraries. Contains all HPJ libraries (installed as part of ET/390 see 4.1.1, Prerequisites on page 57).
Must be in included in CLASSPATH environment variable of the Java SP environment data set (see Figure 8 on page 70).
SQLJ/JDBC base libraries. Contains all SQLJ and JDBC classes, libraries and binaries. Delivered as part of base SQLJ/JDBC support (installed as part of SQLJ support see 4.1.1, Prerequisites on page 57).
The LIB directory must be in included in LIBPATH environment variables of the Java SP environment data set (see Figure 8 on page 70).
/USR/LPP/DB2/DB2nnn/CLASSES /USR/LPP/DB2/DB2nnn/BIN /USR/LPP/DB2/DB2nnn/LIB where nnn is release level (510, 610, and so on). See set environmental variables for SQLJ/JDBC on Page 65, and include the HPJ and SQLJ
libraries in the environmental variables
on Page 65.
60
Type
Description
Sample Name
/u/ssss/links/ where ssss is the DB2 subsystem ID or data sharing group attached name.
Links directory. Contains all USS links to PDSE load libraries that contain compiled Java routines.
Must be in included in LIBPATH environment variable of the Java SP environment data set (see Figure 8 on page 70). Must be the HOME path for the Java SP procedure owner (see Figure 7 on page 66). The SQLJ properties file: db2sqljjdbc.properties and the cursor definitions file db2jdbc.cursors must also be installed in this directory. The SQLJ properties file must be referenced by the DB2SQLJPROPERTIES environment variable (see define where the SQLJ run-time properties file is located on Page 64).
Serialized profiles directory. Contains all of the serialized profiles generated by the sqlj precompiler (used as input to db2profc, the profile customizes).
The JDBC serialized profile: DSNJDBC_JDBCProfile.ser, should be moved in this directory. Must be included in the CLASSPATH environment variable of the Java SP environment data set (see Figure 8 on page 70).
61
Table 8 provides a summary of the OS/390 libraries required, together with the settings we used in our environment.
Table 8. Sample OS/390 library structure
Type
OS/390
Description
Sample Name
Site specific. One library per subsystem recommended. Site specific. One library per subsystem/testing level recommended. Site specific. One library per WLM environment recommended.
SQLJ load library. Contains HPJ compiled versions of JDBC/SQLJ classes. See Figure 4. Application load library. Contains HPJ compiled versions of Java stored procedure code. See Figure 5.
JAVAENV data set. Contains settings for Java environment variables used within the stored procedures address space. See Figure 6.
DBRM library. Contains DBRMs generated by db2profc step for SQLJ procedures. See DB2SQLJDBRMLIB parameter in Figure 9 on page 72.
The SQLJ load library must be defined as a PDSE library. Figure 4 shows an example of this data set definition:
Data Set Name . . . : HPJ.SDSNJDBC.DBZ2 General Data Management class . . : **None** Storage class . . . : **None** Volume serial . . . : TOTDB1 Device type . . . . : 3380 Data class . . . . . : **None** Organization . . . : PO Record format . . . : U Record length . . . : 0 Block size . . . . : 24760 1st extent tracks . : 5 Secondary tracks . : 5 Data set name type : LIBRARY
The application load library must be defined as a PDSE library. Figure 5 shows an example of this data set definition.
62
Data Set Name . . . : USER.HPJSP.PDSE.DBZ2 General Data Management class . . : **None** Storage class . . . : **None** Volume serial . . . : TOTDB1 Device type . . . . : 3380 Data class . . . . . : **None** Organization . . . : PO Record format . . . : U Record length . . . : 0 Block size . . . . : 24760 1st extent tracks . : 5 Secondary tracks . : 5 Data set name type : LIBRARY
The JAVAENV data set must be defined as a variable blocked sequential data set, as in Figure 6 below:
Data Set Name . . General Data Volume serial . . Device type . . . Organization . . Record format . . Record length . . Block size . . . 1st extent tracks Secondary tracks
63
In the UNIX world it is standard practice to establish a .profile script for every USS user. It is equivalent to the ISPF logon proc, in that it establishes the initial environment for the user. Some shops may wish to create a centralized script that establishes the basic DB2 environment. Each users .profile would then execute that centralized script within their .profile. If a centralized script is used, be sure to dot the command within the .profile. For example, if the centralized script is called /usr/apps/db2/db25/profile, then each .profile script would execute it using the following command.....notice the period followed by a space followed by the script.....this executes the script within the current process instead of forking a separate process:
. /usr/apps/db2/db25/profile
Here is a example of the .profile used for our sample users. (We did not use a centralized script).
#---------------------------------------------------------------------# Profile for the common EC environment to compile SQLJ and JDBC code #---------------------------------------------------------------------echo off cls I=0 while test $I = 0 do echo "5 For DB21 V5 properties file" echo "6 For DBZ2 V6 properties file" echo "enter number for DB2 properties file" read DBPROP case $DBPROP in 5) I=1 export SSID=DB21 export SSIDHFS=db2510 SSIDLIB=DB2V510;; 6) I=1 export SSID=DBZ2 export SSIDHFS=db2610 SSIDLIB=DSN610;; *) echo "Huh? Did not enter 5 or 6 entered > $DBPROP";; esac done echo "SSID = $SSID SSIDHFS = $SSIDLIB SSIDLIB = $SSIDHFS" #-----------------------------------------------------# define where the SQLJ run-time properties file is located #-----------------------------------------------------export DB2SQLJPROPERTIES=/u/$SSID/links/db2sqljjdbc.properties ##### Added for tso -t from telnet
64
# Assign the DD names to allocate # export TSOALLOC=sysexec # # Allocate the OpenMVS EXEC data set to SYSEXEC # export sysexec=SYS1.OS390.EXEC #end# Added for tso -t from telnet #-----------------------------------------------------# set environmental variables for HPJ #-----------------------------------------------------export IBMHPJ_HOME="/usr/lpp/hpj" export IBMHPJ_RTL="CEE.SCEELKED:CEE.SCEELKEX:CEE.SCEEOBJ:CEE.SCEECPP" #-----------------------------------------------------# set environmental variables for DSNAOINI data set #-----------------------------------------------------export DSNAOINI=DB2V610.$SSID.DSNAOINI #-----------------------------------------------------# set environmental variables for SQLJ/JDBC #-----------------------------------------------------export SQLJ_HOME=/usr/lpp/db2/$SSIDHFS export JDBC_HOME=/usr/lpp/db2/$SSIDHFS # # Java_HOME is where the current JDK is installed #export Java_HOME=/usr/lpp/Java/J1.1 # Java_COMPILER is used to turn the JIT OFF export Java_COMPILER= # Tell make and others we are NOT using Optimized versions unset SQLJ_OPTIMIZED #-----------------------------------------------------# include the HPJ and SQLJ libraries in the environmental variables #-----------------------------------------------------export CLASSPATH=.:$JDBC_HOME/classes/db2sqljclasses.zip:\ $Java_HOME/lib/classes.zip:\ $SQLJ_HOME/classes/db2sqljruntime.zip:\ $SQLJ_HOME/classes/db2jdbcclasses.zip:\ /u/$SSID/links:\ /u/$SSID/ser:\ $Java_HOME/lib:$IBMHPJ_HOME/lib export PATH=$PATH:$SQLJ_HOME/bin:$IBMHPJ_HOME/bin:$PATH export LIBPATH=$SQLJ_HOME/lib:$JDBC_HOME/lib:\ $Java_HOME/lib/mvs/native_threads:$IBMHPJ_HOME/lib:$LIBPATH # export STEPLIB=$SSIDLIB.sdsnload.test:$STEPLIB ix export STEPLIB=$SSIDLIB.sdsnload:$STEPLIB export STEPLIB=$SSIDLIB.sdsnlink:$STEPLIB export LD_LIBRARY_PATH=.:$SQLJ_HOME/bin:$JDBC_HOME/lib:\
65
$Java_HOME/lib/mvs/native_threads #-----------------------------------------------------# print out Java and hpj versions #-----------------------------------------------------Java -version hpJava -version export EDITOR=vi set -o vi echo '*---------------------------------------------------------------' echo ' profile executed for HPJ, Java and SQLJ ' echo '*---------------------------------------------------------------'
Then you create a profile in the STARTED class names DBZ2Java.* for the WLM Java address space, as follows:
66
Finally, since STARTED is a RACLISTed class, you must do a RACF refresh using the following command:
setropts raclist(started) refresh
4.1.6.2 JCL procedure of a Java WLM-established address space Here is an example of a JCL procedure for starting the WLM-established address space with Java support:
//DBZ2Java PROC RGN=0K,APPLENV=WLMJavaDBZ2,DB2SSN=DBZ2, // NUMTCB=1,TME=NOLIMIT //DBZ2Java EXEC PGM=DSNX9WLM,REGION=&RGN,TIME=&TME, // PARM=&DB2SSN,&NUMTCB,&APPLENV //STEPLIB DD DISP=SHR,DSN=DB2V610V.RUNLIB.LOAD // DD DISP=SHR,DSN=SYS1.SCEERUN // DD DISP=SHR,DSN=DSN510.SDSNLOAD // DD DISP=SHR,DSN=USER.HPJSP.PDSE.DBZ2 #1 // DD DISP=SHR,DSN=HPJ.SDSNJDBC.DBZ2 #2 // DD DISP=SHR,DSN=HPJ.SHPJMOD #3 // DD DISP=SHR,DSN=HPJ.SHPOMOD #4 //JAVAENV DD DISP=SHR,DSN=HPJ.JAVAENV.DBZ2 #5 //JSPDEBUG DD SYSOUT=A #6 //DSSPRINT DD SYSOUT=A //UTPRINT DD SYSOUT=A //SYSPRINT DD UNIT=SYSDA,SPACE=(4000,(20,20),,,ROUND) //SYSUDUMP DD SYSOUT=A
This procedure contains the following statements: 1. DD statement for the high performance Java compiled stored procedure PDSE load library. 2. DD statement for the high performance Java JDBC/SQLJ library. 3. DD statement for the high performance Java SHPJMOD library. 4. DD statement for the high performance Java SHPOMOD library. 5. JAVAENV DD statement for the work load managed Java stored procedure runtime environment options. This data set applies to the entire WLM environment, not just individual stored procedures. See 4.1.8, Step 6: Set up the JAVAENV data set on page 69 for more details. JSPDEBUG DD statement for Java stored procedure debug information. This is a critical source of information when debugging Java stored procedures in an S/390 environment (see 6.5, Debugging on page 103)
67
We modified the external HFS link to PDSE member DLL to our /u/DBZ2/links directory as follows:
rm -f /u/DBZ2/links/libdb2os390vaj.so ln -e DSNAQDLL /u/DBZ2/links/libdb2os390vaj.so
We modified the build PDSE Java DLL for the output as follows:
-o "//'HPJ.SDSNJDBC.DBZ2(DSNAQJLL)'" \
This step requires a large amount of storage, so when you log onto TSO, make sure you have set the logon region size to 1100000. Failure to do so will result in messages such as:
HPJ3115(S) Unable to fetch module "HPJ3TBY".
After running installVAJDLLs, the directory /u/DBZ2/links will contain the following:
/u/DBZ2/links/
68
COM ibm libdb2os390vaj.so -> DSNAQDLL sqlj sqlj.jll -> DSNAQJLL /u/DBZ2/links/sqlj mesg.jll runtime runtime.jll util /u/DBZ2/links/sqlj/runtime error.jll profile profile.jll ref.jll /u/DBZ2/links/sqlj/runtime/profile ref.jll util.jll /u/DBZ2/links/sqlj/util io.jll
Applying maintenance
This step must be repeated when any related maintenance has been applied to the system that effects the JDBC/SQLJ drivers. In addition, there are other considerations that you have to keep in mind; see 4.1.11, Maintenance considerations on page 75.
69
SQLJ contains sqlj .so dynamic load libraries. JDBC contains jdbc .so dynamic load libraries. HPJ contains hpj .so dynamic load library. The USS directories containing these libraries must be referenced in the LIBPATH environment variables. See Figure 8 on page 70 on how LIBPATH is used.
CLASSPATH CLASSPATH contains all the directories that contain the required SQLJ and JDBC class files .zip:
CLASSPATH must also point to the directory used to store your SQLJ serialized
profiles and JDBC cursors and SQLJ properties files (see 4.1.9, Step 7: Verify JDBC cursor and SQLJ properties files on page 71). Finally, the location where you will store the external links for your stored procedure modules must also be referenced.
TZ
TZ is used to set the local time zone. It is an optional parameter.
4.1.8.2 Sample contents Figure 8 shows an example of the contents of a JAVAENV data set.
ENVAR("CLASSPATH=.:/usr/lpp/hpj/lib:/u/DBZ2/ser", "LIBPATH=/usr/lpp/hpj/lib:/usr/lpp/db2/db2610/lib:/u/DBZ2/links")
Figure 8. JAVAENV data set contents
Note: This data set is supplied on the CD-ROM in directory SAMPLES\S390 UTILITIES\INSTALLATION\JAVAENV. See Appendix E, Using the additional
70
Note:
The current restriction for the total length of the ENVAR variable is 255 characters. You must be careful when structuring your libraries to ensure that this limit is not exceed. No error messages are issued if the limit is exceeded: any characters beyond position 255 will be ignored, which may lead to errors such as failure to load classes.
A sample cursor definition file called db2jdbc.cursors is created as part of the base JDBC/SQLJ installation. This contains 250 cursor definitions (125 cursors WITH HOLD and 125 without). This file can be amended (or an alternative version defined) if you wish to have more cursors available, or to rename the cursors that JDBC will use. Because the cursors file is used as input to the db2genJDBC utility that creates the generic JDBC DBRMs used by all JDBC programs, you need to re-run db2genJDBC after amending the cursors file. Refer to 4.1.11, Maintenance considerations on page 75 for some further actions you should take after doing this.
4.1.9.2 SQLJ properties file The SQLJ run-time properties file contains parameters that specify any program preparation or run-time information that is not in environmental variables. Use the environmental variable DB2SQLJPROPERTIES in your . PROFILE to point to this file. For Example:
export DB2SQLJPROPERTIES=/u/DBZ2/links/db2sqljjdbc.properties
71
As the SQLJ properties file contains information such as the plan used for all SQLJ/JDBC client programs that execute under USS, you may want to consider defining multiple properties files (for different groups of users, or different applications, for instance) and tailoring your .profile scripts to point to each as necessary. See 9.1.5, Usage recommendations on page 170 for more details. Here is a sample of the contents of an SQLJ properties file. This sample can also be found in file DB2SQLJDBC.PROPERTIES on the CD-ROM in directory SAMPLES\S390 UTILITIES\INSTALLATION\. See Appendix E, Using the additional material on page 347 for more details.
These parameters are discussed in the sections that follow. For a full explanation of these and other parameters, please refer to the Application Programming Guide and Reference for Java, SC26-9018.
DB2SQLJSSID Specifies the name of the DB2 subsystem to which a JDBC or an SQLJ application connects. DB2SQLJPLANNAME Specifies the name of the plan that is associated with JDBC and SQLJ serialized profile. This is used by Java clients that run in the USS environment and JDBC dynamic SQL Java stored procedures programs. DB2SQLJATTACHTYPE Specifies the attachment facility that a JDBC or an SQLJ application program uses to connect to DB2. DB2SQLJJDBCPROGRAM Specifies the name of a JDBC connected profile that is used by SQLJ run-time environment.
72
DB2SQLJDBRMLIB Specifies the fully-qualified name of the OS/390 partition data set into which DBRMs are placed. DBRMs are generated by the creation of a JDBC profile and the customization step of the SQLJ program preparation process.
4.1.10.2 Data sharing and HFS In a data sharing environment, you are sharing the catalog, directory, and all databases among all members of the group. You will only have one copy of these data sets in the sysplex environment. However, the USS HFS is unique for each member of the sysplex under OS/390 V2 R8.
*** Note ***
OS/390 V2 R8 will require you to do some special planning on how to set up and use the HFS for each member. You will have to duplicate the HFS directory structure in each member of the sysplex. This will allow you to bring any DB2 member of the group up in any OS/390 sysplex member and to run the Java store procedure in the other members of the group. Using the group name for the higher directory level for the links and user directories will make it easier to duplicate and to migrate to OS/390 V2 R9 and above. This will allow you to use the same HOME path name for the WLM stored procedure address space and the same owner name across the sysplex. The following are steps that you will have to do to duplicate the work done on one sysplex member in each other sysplex member or members that run DB2 members of the data sharing group: Follow Step 1: Design library structure on page 60. Follow Step 2: Provide .profile for users on page 63.
73
Follow Step 5: Install JDBC/SQLJ driver for OS/390 on page 68. Follow Step 7: Verify JDBC cursor and SQLJ properties files on page 71. Transmit all of the related Java program class files over to the other sysplex member or members HFS. This is input to the HPJ compiler to create the LINKs. You will need to run the HPJ compiler over on the other sysplex member or members to create the LINKs into the /u/DB2Groupname/links path. This will restrict you to do all of your Java development on only one sysplex member within the sysplex. Figure 10 shows a diagram of a DB2 data sharing group called DBZ1 with two members, DBZ1 and DBZ2. The WLM application environment for the Java stored procedures that run in this group are set up to use a started task procedure named DBZ1JAVA. The RACF owner for this STC is the procedure name DBZ1JAVA with an OMVS Home path set to /u/DBZ1/links. You can see that each OS/390 member in the sysplex has its own OS/390 USS HFS and shares the same OS/390 DASD.
74
MVSPLEX V2 R8
os/390 Shared Dasd
DBZ1 Cat & Directory DBZ1 Tables DBZ1 Logs DBZ1 BSDS HPJ.JAVAENV.DBZ! HPJ.SQLJ.PDSE USER.JAVA.PDSE.DBZ1
MVS1
DBZ1MSTR STC DBZ1DBM1 STC DBZ1IRLM STC DBZ1JAVA DBZ1JAVA Home=/u/DBZ1/links
MVS2
DBZ2MSTR STC DBZ2DBM1 STC DBZ2IRLM STC DBZ1JAVA DBZ1JAVA Home=/u/DBZ1/links
Figure 10. DB2 data sharing group with Java stored procedures
The db2genJDBC utility resides in the bin subdirectory of the USS directory where your SQLJ/JDBC support has been located (for example, /usr/lpp/db2/db2610/bin). It is used at the time JDBC is installed, to generate the generic JDBC DBRMs that will be needed by all JDBC stored procedures and clients. See the Application Programming Guide and Reference for Java , SC26-9018 for more details.
75
Re-bind all DB2 packages that use the generic JDBC DBRMs (DSNJDBC1, DSNJDBC2, DSNJDBC3 and DSNJDBC4).
Symptom:
An out-of-storage error message is issued during HPJ compile:
Class missing for error: Java/lang/OutOfMemoryError
Possible resolution:
Increase TSO region size if logged on via TSO. We recommend a value of 1100000.
4.1.12.2 Unable to load HPJ module during HPJ compile
Symptom:
A message is issued during HPJ compile indicating that an HPJ module cannot be fetched:
HPJ3115(S) Unable to fetch module "HPJ3TBY".
Possible resolution:
Increase TSO region size if logged on via TSO. We recommend a value of 1100000.
4.1.12.3 00E79107 Unable to find user class
Symptom:
The reason code 00E79107 is encountered when attempting to invoke a Java stored procedure.
Additional SQLCA information provided with the message has the name of the class that could not be found.
Possible resolution:
76
Make sure that all classes have been bound into the PDSE data set. Make sure external links are to packages.
4.1.12.4 Unable to find user method
Symptom:
00E79107 or 00E79108 reason code on -471 when calling a complied Java stored procedure. Additional SQLCA information provided with the message has signature provided by SQL types.
Possible resolution:
Make sure the PARAMETERS column maps to JDBC types. Check the Java signature using Javap -s -private <classname> Remember, result sets are in the signature, but not in the PARAMETERS column.
4.1.12.5 CEE5207E The signal SIGABRT was received
Symptom:
This message is printed out in the Java SP address space and the client receives a -965. SQLCODE back.
invoking class: ACMEJOS/Add_customer, method: add_customer Add_customer: start - JDBC version Add_customer: getConnection CEE5207E The signal SIGABRT was received.
Possible resolution:
Either the db2jdbc.cursors or db2sqljjdbc.properties file was not found in the HOME path of the Java stored procedure environment (/u/DBZ2/links). Make sure these two files are included in the HOME PATH.
4.1.12.6 ICH408I USER(uuuu) GROUP(ggggg) NAME(nnnn) 928
Symptom:
77
This message is shown on the OS/390 console log. The client application receives a SQLCODE of -965 and the Java stored procedure shows an error loading the JDBC driver.
PROC= DBZ2Java ASID= 0085 WLM_ENV= WLM_Java_DBZ2 DSNX906I =DBZ2 DSNX9CAC PROCEDURE JS_ADD_CUSTOMER 927 TERMINATED ABNORMALLY. THE PROCEDURE HAS BEEN STOPPED. ASID= 0085 WLM_ENV= WLM_Java_DBZ2 ICH408I USER(DB2STC ) GROUP(SYS1 ) NAME(Java DB2 STCS ) 928 /u/DBZ2/links CL(DIRSRCH ) FID(01E3E2D4E2F4F100690C000000000003) INSUFFICIENT AUTHORITY TO LOOKUP ACCESS INTENT(--X) ACCESS ALLOWED(GROUP ---) --TIMINGS (MINS.)--
Possible resolution:
The HFS /u/DBZ2 was not built with the proper permission setting to allow search of directories down from /u/DBZ2. Make sure that the directory is set with 755. To make sure your directories are set at 755, use the UNIX command ls -l to verify that it is set, as follows:
drwxr-xr-x 2 DB2RES3 DBZ2 8192 Mar 16 13:44 aa
Use the chmod command to set the permissions to 755 on directory DBZ2, executing the following UNIX commands: - cd /u - chmod 755 DBZ2 - ls -l
4.2.1 Prerequisites
Windows NT Version 4 or above A JDK any one of the following will suffice: - The Java Development Kit (JDK) and Java Runtime Environment (JRE) for Win32 (version 1.1.7 or above) from IBM. These are shipped with DB2 for Windows NT. - The Java Development Kit (JDK) Version 1.1 or later for Win32 from Sun Microsystems - Microsoft Software Developer's Kit for Java, Version 3.1.
78
A comprehensive set of sample applications is supplied with DB2, and you may want to try running some of these before writing your own code to verify that the environment is properly configured. The samples can be found in the sqllib\samples\Java directory.
Symptom:
The following error message is produced when you try to use any of the DB2 preparation utilities (SQLJ, DB2PROFC, etc.):
Error in sqlj: path or file name "Java" not found.
Possible resolution:
Ensure that Windows NT PATH variable includes the directory that contains the JDK binaries (usually c:\sqllib\Java\jdk\bin). See 4.2.2, Installation tasks on page 79 for more details. Try building a simple Java application at the DOS command level to make sure that Java works. Simple Java examples can be found on Web sites that introduce the language to novice Java programmers.
79
4.3.1 Prerequisites
For AIX, use JDK 1.1.8 Fixpak 4 or later. For other UNIX variations, obtain the most recent JDK that has been tested by IBM as being compatible. The list of JDKs can be found at:
http://www-4.ibm.com/software/data/db2/Java/index.html
The userid owning DB2 must establish some environment variables to tell DB2 where the JDBC and SQLJ runtime support can be found. This can be done in the .profile file. This includes the following tasks: Establishing the general DB2 environment variables, typically done by executing the sqllib/db2profile, which is in the directory of the install userid. Setting Java_HOME. Setting CLASSPATH to include the classes and ZIP files containing JDBC and SQLJ functionality. Setting the PATH variable to use the bin directory for DB2. Setting LIBPATH and LD_LIBRARY_PATH to use the libraries shipped with DB2.
80
Each developer wishing to create Java stored procedures would use the same .profile information with a minor change for the location of the db2profile script.
81
82
5.1.1 Naming
There are a number of interrelationships between the various components used in a Java stored procedure environment. Therefore, it is a good idea to come up with some naming standards as soon as possible in the design process. The following sections provide some general naming recommendations for a Java stored procedure environment (see Figure 13 on page 95 for a discussion of how the various programming objects interact). Remember that there are some issues surrounding case sensitivity with many of these names. Be consistent in your use of case, and implement some site conventions for everybody to follow.
5.1.1.1 Relationships between stored procedure components Figure 11 shows the interrelationship between the various components in a Java stored procedure environment:
Each stored procedure is implemented as a Java method, and there is a one-to-one relationship between a method and a stored procedure. One or more methods belong to a Java class. There is a one-to-one relationship between a Java class and a Java source file. One or more classes reside in a Java package. There is a one-to-one relationship between a Java package and an operating system directory (which stores all of the Java source files for that package). One or more Java packages reside within an OS/390 executable module (on the OS/390 platform) or within a JAR file (on the UNIX and NT platforms).
83
Most code management products and procedures operate at source code file level. Therefore, we felt that storing any more than one stored procedure within a single source code file can cause version management issues. For this reason, we chose to implement a single method per class, which resulted in a single stored procedure per source file. We also implemented a single Java package per OS/390 executable or JAR file, to keep the size of these objects manageable. This approach is summarized in Figure 12.
Note
As with any other naming conventions, there are no definitive right and wrong ways to name components. Within this section we present the conventions that we used during the production of this book. This approach seemed to provide a good compromise between flexibility and manageability. However, your mileage may vary: you must define your own conventions based upon any existing standards and the particular environment that you are working within.
84
5.1.1.2 Stored procedure name If you already use non-Java stored procedures, you will probably have standards in place for stored procedure names (the name you specify in the SQL CALL statement to invoke the stored procedure).
Remember that you have a full 18 characters to use, so make the name as meaningful as possible in relation to the stored procedures function. For example, Add_customer, Promote_employee, and Bill_client are all good descriptive names. DB2 UDB for OS/390 Version 6 and DB2 UDB for UNIX, Windows NT, and OS/2 support 2-part stored procedure names, which give you still more flexibility in your naming convention.
5.1.1.3 Java method name There is a one-to-one relationship between a method name and a stored procedure name. Although the names can be dissimilar, for ease of understanding, we suggest that the stored procedure and the method be named the same.
85
5.1.1.4 Java class name A Java class contains one or more methods. We found it easiest to place one method in a class and to name the method the same as the class, changing the initial character of the class name to upper case.
In our example, the Java method called add_customer is the only method in a Java class called Add_customer.
5.1.1.5 JDBC source file / SQLJ Source File There is a one-to-one relationship between a Java class and the file the source is stored in. Therefore, we recommend that you name the source file after the Java class it contains.
So, if you are following our previous recommendation of one method (stored procedure) per Java class, you can name the source file after the stored procedure name. In our example, the stored procedure Add_customer would be implemented as a method called add_customer, within a class called Add_customer, and stored in a file called Add_customer.java (for a JDBC procedure) or Add_customer.sqlj (for a SQLJ procedure).
How many stored procedures per source file?
We feel that the approach we have described above provides the greatest flexibility in a typical development environment, where version management and concurrent development requirements would make the placement of multiple stored procedures within each source file much more difficult to manage. However, there is nothing to stop you from setting up your environment in such a way as to place multiple stored procedures in each .java source file if you wish. In this case, each stored procedure becomes a separate method within the class represented by the source file. You will need to create a meaningful name for the source file that encompasses the stored procedures within it.
5.1.1.6 Java package The Java package name is the basic grouping unit within the Java stored procedures environment, allowing you to associate related stored procedures with each other.
86
Some of the items you may wish to include in your standard for Java package are listed below: An application identifier, if you are grouping your procedures into packages by application (PAYROLL, for example). An environment identifier, if you will be mixing several development environments within the same system (for example, development, unit test, or system test).
How many Java packages per load module or JAR?
In our tests, we created a discrete OS/390 load module (on the S/390 platform) or JAR file (on UNIX and Windows NT) for each Java package. However, you may incorporate several Java packages into a single HJP load module or JAR file if you wish. The remainder of this discussion assumes a one-to-one relationship between the Java package and the OS/390 load module or JAR.
The source files for all stored procedures that belong to a given Java package should be grouped together in a single USS directory named after the Java package. For example, the Add_customer and Add_order SQLJ procedures both belong in the ACME package. Therefore, the ACME directory contains the source files Add_customer.sqlj and Add_order.sqlj.
87
As we are suggesting that you implement a one-to-one relationship between Java packages and OS/390 load modules, you may be tempted (as we were initially) to simply name the OS/390 load module after the Java package. This should be avoided, as it has a number of disadvantages: It imposes a limit of 8 characters on your Java package names (the maximum length of a PDSE member name), making them less descriptive. It can lead to case sensitivity problems with Java package names, due to the fact that the OS/390 load module name is always in upper-case. For instance, two Java packages named package1 and PACKAGE1 will be completely discrete within the USS environment, but will both result in a load module name of PACKAGE1 with the PDSE dataset. This may lead to existing modules being overwitten during the program preparation process. For these reasons, we recommend that your program preparation scripts use different names for the Java package and the PDSE member name. The sample scripts described in 7.2, OS/390 Java stored procedure preparation on page 119 reflect this.
5.1.1.7 OS/390 load module The HPJ load module contains an optimized, OS/390 specific, compiled version of all of the stored procedures within one or more Java packages.
We recommend the use of a single Java package per OS/390 load module. However, as the OS/390 load module can only be a maximum of 8 characters in length, you will probably need to create a suitable means of shortening or transforming the Java package name to fit.
5.1.1.8 JAR file In a DB2 UDB for UNIX, Windows, OS/2 environment, the JAR file is used to contain all of the .class files associated with a particular Java package. Therefore, it is functionally equivalent to a HPJ executable module on the S/390 platform.
We recommend that you name your JAR file the same as your Java package name to ease problem solving. There is no technical limitation requiring the JAR name to be named the same as the Java package name.
88
5.1.1.9 DB2 package The program preparation process for each SQLJ procedure will result in 4 DB2 packages being produced (one for each isolation level). Therefore, if you have 2 SQLJ procedures in a Java package, that Java package will have 8 DB2 packages associated with it (the terminology is a little confusing here make sure you are clear about the differences between Java packages and DB2 packages).
DB2 package names must be limited to 7 characters, as the db2profc process appends a number (between 1 and 4) after the supplied name to generate the 4 packages. You must therefore create a reasonable 7-character abbreviation for your 18-character stored procedure name. For example, for the Add_Customer stored procedure, you could decide to use a package name of ADDCUST, which would cause db2profc to generate DBRMs to bind into packages ADDCUST1, ADDCUST2, ADDCUST3, and ADDCUST4. For JDBC stored procedures, a generic set of DB2 packages (DSNJDBC1,
DSNJDBC2, DSNJDBC3, and DSNJDBC4) are used.
5.1.1.10 DB2 package collection Once again, you will probably already have some standards set up for collection naming within your organization.
Unless your existing site standards dictate otherwise, we suggest that you use one DB2 package collection for each Java package, and name that collection after it. So, for Java package ACME containing SQLJ stored procedures Add_customer (DB2 package name ADDCUST) and Add_order (DB2 package name ADDORD), you may have a package collection called ACME, containing 8 DB2 packages (ADDCUST1 to ADDCUST4 and ADDORD1 to ADDORD4). See 9.1, DB2 plans and packages on page 167 for details on the relationship between client plans and Java stored procedure package colelctions.
89
For DB2 UDB for UNIX, Windows, OS/2, an earlier, more proprietary, solution for making Java stored procedures is known by the name Parameter Style DB2GENERAL. It was developed before industry standards had been established.
The stored procedure in this example has the name of Add_customer. The method to be invoked is add_customer.
90
Note
If you use an output parameter in a SELECT statement, be sure to enclose the entire name, including the [0], with parantheses. Failure to do will result in a syntax error. Example: SET HI_CUST_NO = :(out_cust_no[0])
If it is important to you to be able to easily port your stored procedure code between OS/390 and other platforms, we recommend that you code all of your stored procedures using Java packages. For this reason, all of the Windows NT and UNIX examples in this book use the Java package statement.
From a design perspective, use of Java packages helps organize stored procedures into application groups. Most shops host more than one
91
application on a machine, consequently, we recommend using Java packages for your stored procedures. A Java program becomes part of a Java package if it has the token package followed by the Java package name at the top of the source file. Example:
package ACMESOS;
For recommendations regarding Java package, module, and JAR naming standards, see 5.1.1, Naming on page 83.
92
- Java is not a language used to build one of the stored procedures - All the procedures must be fenced and catalogued.
93
Larger, less-used procedures should stand by themselves in order to allow them to be paged out of memory when not being used. Whenever possible, package the most frequently used of the remaining procedures together.
94
SQLJ Source
Program Preparation Process
DB2 Packages
ACMESOS/ Add_customer.sqlj
USS Directory
via PDSE link
ACMESOS
PDSE Link
ACMESOS
via CLA SSP ATH
via ST E PLIB
ADD_CUSTOMER
JAVAENV Dataset
2 NAME
ADD_CUSTOMER
via JAVAENV DD
WLMJAVA
SP WLM Address Space
SYSROUTINES (V6)
EXTERNAL_NAME
ACMESOS/Add_customer.add_customer
WLM_ENV
WLMJAVA
...
Client
... CALL ADD_CUSTOMER (FIRSTNAME, ....) ...
SYSPROCEDURES (V5)
1 PROCEDURE
ADD_CUSTOMER
RUNOPTS
ACMESOS/Add_customer.add_customer
WLM_ENV
WLMJAVA
...
1. The client issues a call to the stored procedure ADD_CUSTOMER. 2. Depending upon the version of DB2 for OS/390 being used, either the RUNOPTS column of SYSIBM.SYSPROCEDURES or the EXTERNAL_NAME column of SYSIBM.SYSROUTINES is used to determine the Java package, class, and method associated with the call. This is defined within the catalog according to standard Java syntax:
package/classname.methodname
3. The JAVAENV data set specified in the procedure JCL for the selected WLM environment (also obtained from SYSPROCEDURES or SYSROUTINES) is used to obtain the value of the CLASSPATH parameter. The USS libraries specified in CLASSPATH are searched to find a link named after the Java package name
95
specified in the SYSROUTINES or SYSPROCEDURES definition (ACMESOS in our example). 4. The link is used to obtain the PDSE member name containing the HPJ compiled stored procedure load module for the Java package being used. 5. This load module is loaded into the relevant WLM stored procedure address space. 6. DB2 searches for the stored procedures DB2 packages in the collection that the clients plan/package belongs to (or looks in the collection specified in the COLLID keyword on the CREATE PROCEDURE command).
96
97
These parameters were defined to match the DDL for the table:
create table test1 ( PROD_NO integer not null, PROD_DESC char(30), QTY_ON_HAND integer )
Notice that QTY_ON_HAND is nullable (under the business assumption that at a point in time it may not be known how many items of that product are available). Because the SQL field is defined as an integer, it appears to make sense to define the stored procedure parameter as an integer. Unfortunately, this will fail when trying to invoke the stored procedure with a null value. A Java int field is a base type and thus cannot be set to an actual null value. To work around this issue, define the parameter as a String. This gives you the ability to assess if the String is a null object.
Trim a Numeric String
If you use a String to pass a numeric value, be sure to trim the spaces from the string.
Example:
98
For example:
public class Query_test1 { public static void query_test1 ( int in_prod_no, String prod_desc, String in_qty_on_hand ) . . . int local_in_qty_on_hand; if (null == in_qty_on_hand) { //do special handling for when it is null } else local_in_qty_on_hand = Integer.parseInt(in_qty_on_hand.trim());
99
")"; stmt2.executeUpdate(sql2);
This example builds upon the previous example, which calculated the ins_prod_desc field either to the value in the third column of the ResultSet surrounded by single quotes, or to the value NULL.
Requirement
Calling a stored procedure from an SQLJ client Using a base Java type as a parameter
Restrictions
When calling a stored procedure from an SQLJ client, you can send a null Java object. It is not possible to set a base Java type to null and have it actually understood by downstream processing as a null. Instead, you can cast parameters to a String type (or other Java type subclassed from Object) which can then be set to null. A SQLJ stored procedure can receive a null Java object as a parameter. SQLJ understands that when a Java object is null and it is being inserted to the database that a null value is to be placed in the associated nullable column in the table. The host variable is set to Java null when a select statement reads an SQL null value into that host variable.
Receiving a null in an SQLJ stored procedure Inserting a null from an SQLJ stored procedure
100
There are two types of Iterators: Positional refers to the fields by position Named refers to the fields by name
There are two reasons why you might choose to return ResultSets instead of Iterators. First, on the UNIX and Windows NT platforms, the system has been designed to recognize only ResultSets, not Iterators. (This may change some time in the future). Secondly, on the OS/390 platform, although it has been tested as being able to return Iterators, it is less efficient than using ResultSets.
101
102
To return the printStackTrace to the client, use StringWriter and PrintWriter methods to get the output into a string. For example:
mark_error_text[0] = "Query_oi_summ: " + "SQLException raised, SQLState = " + e.getSQLState() + " SQLCODE = " + e.getErrorCode() + " :" + e.getMessage(); StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); e.printStackTrace(pw); mark_error_text[0] += ":printStackTrace=" + sw.toString() ;
6.5 Debugging
Sadly, our computers often remind us that, unlike them, we are not perfect! Our programs rarely work correctly the first time. Stored procedures can be difficult to debug, due to the limitation that they run underneath the control of a separate process, perhaps on a different machine than that of the invoking client.
103
6.5.3.2 System.out.println The developer may choose to put statements in the source code of the Java stored procedure to say, Here is where I am right now, and this is the value of a questionable variable. This technique is quite similar to the use of COBOL Display statements or the C printf statements.
These statements show in the WLM output (as pointed to by the JSPDEBUG DD) of the job executing the Java stored procedures. Your systems programmer can tell you the name of the data set on your system. These statements must be used with care, and only on the development platform if they get pushed out to production, the performance of the production system may be negatively impacted.
6.5.3.3 Writing to an output file A technique for writing stored procedure output to a file is described in 6.5.4, UNIX and Windows NT debugging on page 104. This technique also works on OS/390. The file is created on the UNIX Systems Services file system, because a USS environment is created within the WLM address space.
In the following example, a file is created with a date and time stamp for the file name. (Note that Java is smart enough to convert the /tmp to \tmp on the Windows NT platform.)
At the time of writing, the ET/390 manuals did not have formal IBM publication numbers. However, they can be downloaded from the Web in PDF format at http://www-4.ibm.com/software/ad/vajava/library.htm.
104
//////////////////////////////////////////////////////// // establish debugging file: name is timestamped //////////////////////////////////////////////////////// Date debugDate = new Date(); DateFormat dateFormat = DateFormat.getDateTimeInstance(); (SimpleDateFormat)dateFormat).applyPattern("MM_dd_HH_mm_ss"); String debugdf = dateFormat.format(debugDate); PrintWriter pwx = new PrintWriter( new FileWriter("/tmp/" + debugdf + ".txt"),true ); pwx.println("sql =>" + sql + "<=");
An example file name on Windows NT created from this process is \tmp\03_16_09_25_59.txt , which indicates that the stored procedure ran on March 16 at 9:25AM at 59 seconds past the minute. The pwx.println statement at the end of the code fragment writes what the stored procedure considers to be the value of the sql variable to this debugging file. Observe these two cautions: 1. If the stored procedure fails, the pwx.close() statement (not shown) will not have executed; a DB2 process will still own this file in an open mode, thus the file cannot be deleted until the database is brought down. A better approach is to put the pwx.close() not only in the main body of the stored procedure, but also in the catch blocks, as seen in some of the examples, to close the file. 2. Never allow this debugging technique to go onto the production system. It will hurt performance and possibly bring down the system.
105
6.6.1.1 Testing existing stored procedures One of the most attractive benefits to the SPB is that it gives you the ability to test an already-built stored procedure.
You need not make the source available on the platform upon which the SPB runs; the SPB reads the catalog definitions to build the window that asks for the input parameters. This facility frees you from the requirement to write a specific client driver program for each stored procedure when testing. DB2 Connect is required for being able to invoke stored procedures located within DB2 databases on other platforms, such as OS/390 or UNIX.
Symptom
HPJ compile issues this error message:
HPJ3115(S) Unable to fetch module "HPJ3TBY".
Possible Solution
Increase region size.
6.7.1.2 Class Not Found at runtime
Symptom
This error message is issued at runtime:
class not found in classpath: ACME/ADD_CUSTOMER to String string from error is: java.lang.NoSuchMethodError
106
Possible Solution
The PDSE member created by the HPJ compiler will have its name folded into upper case (OS/390 does not support lower case PDSE member names). Check that the USS link to the PDSE member in your links directory points to an upper case version of the PDSE member name. If this has been incorrectly specified as a lower case name, the link will not work, and this error message will be returned. See 5.1.9, Case sensitivity on page 92 for more details.
6.7.1.3 Method Not Found at runtime
Symptom
This error message is issued at runtime:
error GetStaticMethodID class name: ACMESOE/Add_customer func name: Add_customer toString string from error is: java.lang.NoSuchMethodError: Add_customer
Possible Solutions
Ensure case of method name in SYSPROCEDURES or SYSROUTINES matches that defined in SP Ensure that SP code has method defined as public static, with void return type Ensure that parameter definition in SYSPROCEDURES or SYSROUTINES matches CALL definition.
6.7.1.4 SQLCODE -104 At DB2 Package Bind
Symptom
SQLCODE -104 is issued at package bind;
DSNX200I =DBZ2 BIND SQL ERROR USING DB2RES2 AUTHORITY PLAN=(NOT APPLICABLE) DBRM=ADDCUST1 STATEMENT=1 SQLCODE=-104 SQLSTATE=42601 TOKENS=;-<END-OF-STATEMENT CSECT NAME=DSNHPARS RDS CODE=0
107
Possible Solutions
Ensure that you havent put semicolons within the #SQLJ curly brackets at end of SQL statements (normal Java statement terminator semicolons are still required outside the #SQLJ curly brackets).
6.7.1.5 SQLCODE -113 when executing from a Java client
Symptom
SQLCODE -113 is issued when executing from a Java client. The error looks something like this:
java.sql.SQLException: DB2JDBCSection Received Error in Method execute_call:SQLCODE==> -113 SQLSTATE ==> 42602 Error Tokens ==> <<DB2/OS390 V5.1 ANSI SQLJ-0/JDBC 1.0>> Add_customer 000 at COM.ibm.db2os390.sqlj.jdbc.DB2SQLJJDBCSection.setError(DB2SQLJJDBCSection. java:1049) at COM.ibm.db2os390.sqlj.jdbc.DB2SQLJJDBCSection.execute_call(DB2SQLJJDBCSect ion.java:874) at COM.ibm.db2os390.sqlj.runtime.DB2SQLJRTStatement.execute(DB2SQLJRTStatemen t.java:987) at sqlj.runtime.ExecutionContext$StatementFrame.execute(ExecutionContext.java :741) at sqlj.runtime.ExecutionContext.execute(ExecutionContext.java:419) at acmecl.sscall_Add_customer.main(sscall_Add_customer.java:169)
Solution
Define the stored procedure in SYSPROCEDURES to be known by an uppercase name. This uppercase name now becomes the name used by the Java client to invoke the stored procedure. Please note that the stored procedure itself can still be written with lowercase letters: it is the indirection in SYSPROCEDURES that makes it visible as uppercase.
6.7.1.6 SQLCODE -440 when trying to invoke a stored procedure
Symptom
108
DB2 is not able to find the stored procedure or the caller does not have execute authority on stored procedure.
Solution
One thing DB2 checks is whether the stored procedure was created after the original bind of the CALL statement. This can only happen during autobind. The calling DB2 package has to be explicitly rebound in this case.
Solution
Another check is whether the caller has execute authority to the stored procedure. The owner of the stored procedure needs to issue a GRANT EXECUTE ON PROCEDURE to this user. Callers of stored procedures that were migrated from V5 and have not been dropped and recreated do not need this authority, as they have no OWNER.
Solution
The most common error is that a procedure by this name with this number of parameters was not found in the catalog table. To resolve this, you should obtain the result of a SELECT of all columns of SYSIBM.SYSROUTINES for the SP that you want to invoke. First, verify that the number of parameters sent on the CALL statement, or described in the SQLDA if it is a USING DESCRIPTOR call, matches the number of parameters column in SYSIBM.SYSROUTINES. If this is correct, then it's a problem with the stored procedure name. Now you need to determine exactly what name was specified on the SQL CALL statement. The name can be either explicitly specified, or contained in a host variable. If you are running on a distributed client using a workstation development tool that uses ODBC or JDBC, then you are definitely running the SQL CALL statement with the name specified in a host variable. Either way, the name can be a 1-part, 2-part, or 3-part name. A 3-part name is LOCATION.SCHEMA.PROCNAME. In this case, make sure that LOCATION is the current location. and SCHEMA and PROCNAME match what is in SYSIBM.SYSROUTINES, which was filled in by CREATE PROCEDURE. Similarly, a 2-part name is SCHEMA.PROCNAME, so make sure that they match what is in SYSROUTINES. For a 1-part name, only PROCNAME is specified, and in this case, DB2 must determine the schema name. DB2 uses a combination of CURRENT SQLID and CURRENT PATH to look for a match, so you need to make sure that the schema
109
name in SYSIBM.SYSROUTINES is in the concatenation of schemes used to resolve the SP name. It is different for call with a literal than call with a host variable:
CALL <literal> SQL statements are resolved at bind time. The PATH bind option is used to determine schema name. CALL <host variable> SQL statements are resolved at run time. The CURRENT_PATH special register is used to determine the list of potential
schema names.
Note
With APAR PQ39037 is applied, this situation changes. Refer to the APAR text for further details.
P1 doesn't exist at the local site. This doesn't fail on the BIND in V5, but does in V6. The way to fix this is to handle it exactly the same way as you would handle a reference to a remote table, which will get a -204 if you try to bind the DBRM locally with VALIDATE(BIND). Here are some suggestions: 1. Don't bind the calling DB2 package locally, i.e., don't use MEMBER(x) on the BIND PLAN, use pklist(location.collection.x). This only works if DBRM x doesn't contain SQL to access the local location. 2. Use VALIDATE(RUN) on the BIND. This is the recommended approach, and what is usually done for other remote objects, like tables. Don't worry, VALIDATE(RUN) has no overall performance degradation on the local SQL statements. It only affects those specific SQL statements that cannot be bound during the static BIN. because the objects or auth aren't found at that time -- like SQL referencing remote objects (non 3-part names), including this specific type of CALL statements.
110
3. Use SQLERROR(CONTINUE) on the BIND. SQLERROR(CONTINUE) is usually used only if the DB2 package uses an SQL statements that DB2 390 doesn't support but the application will only execute the statements after a CONNECT to a non -390 DB2 server. 4. Modify the calling application to use a 3-part name on the CALL statement. A 3-part name in V6, when the DB2 package is bound with DBPROTOCOL(DRDA), uses DRDA to implicitly connect to the remote location. 5. Issue a CREATE PROCEDURE P1 at the local site to act as a dummy entry and get past BIND errors.
Symptom
When running a client the following error is seen:
java.sql.SQLException: DB2SQLJConnection error in native method: constructor: LOCATION NAME NOT LISTED IN CDB SQLSTATE=42705 and SQLCODE=-950
Solution
The wrong location name was argued in the connect statement, therefore DB2 attempts to find the remote DB2, however, one is not listed. Details described at 9.2.1, General client coding considerations on page 170.
6.7.1.8 SQLCODE==> -113 SQLSTATE ==> 42602 Error Tokens ==> <
Symptom
111
Solution
Remove hidden whitespace characters that somehow were introduced into the sample. (Speculation: perhaps FTPing between platforms introduces this kind of error). Carefully remove or retype what looks like blanks, especially at the ends of lines.
Symptom
When trying to execute a Java stored procedure, an error message says there was a Java Interpreter start-up or communication failure. For example:
db2inst3@azov:[/u/db2inst3/apps/test1/samples]>java DB2SpCli Java Stored Procedure Sample debug: drop procedure debug: completed drop procedure
112
Registering Java stored procedure SAMPLESTOREDPROC as DB2Stp!salaryModification in not fenced mode debug: starting prepareCall debug: completed prepareCall Calling stored procedure: SAMPLESTOREDPROC COM.ibm.db2.jdbc.app.DB2Exception: [IBM][CLI Driver][DB2/6000] SQL4301N Java interpreter startup or communication failed, reason code "0". SQLSTATE=58004 at java.sql.SQLException.<init>(Compiled Code) at COM.ibm.db2.jdbc.app.DB2Exception.<init>(Compiled Code) at COM.ibm.db2.jdbc.app.SQLExceptionGenerator.throw_SQLException(Compiled Code) at COM.ibm.db2.jdbc.app.SQLExceptionGenerator.check_return_code(Compiled Code) at COM.ibm.db2.jdbc.app.DB2CallableStatement.execute2(Compiled Code) at COM.ibm.db2.jdbc.app.DB2PreparedStatement.execute(Compiled Code) at DB2SpCli.callStoredProc(Compiled Code) at DB2SpCli.main(Compiled Code)
Solution
Reconfigure the DB2 instance to point to the correct JDK on the machine. For example, it may be in /usr/jdk_base, although it could be installed anywhere, as in /usr/lpp/J1.8.1. Your DBA reconfigures this value. It can be seen doing a get dbm cfg, DB2 command, or by looking at the Instance configuration values from Control Center.
6.7.2.2 SQL10013N The specified library could not be loaded
Symptom
When trying to execute a Java stored procedure, an error message says the <DB2HOME>/sqllib/function/<Java class name> could not be loaded. Example:
COM.ibm.db2.jdbc.app.DB2Exception: [IBM][CLI Driver][DB2/6000] SQL10013N The specified library "/u/db2inst3/sqllib/function/Add_customer" could not be loaded.
113
at java.sql.SQLException.<init>(Compiled Code) at COM.ibm.db2.jdbc.app.DB2Exception.<init>(Compiled Code) at COM.ibm.db2.jdbc.app.SQLExceptionGenerator.throw_SQLException(Compiled Code) at COM.ibm.db2.jdbc.app.SQLExceptionGenerator.check_return_code(Compiled Code) at COM.ibm.db2.jdbc.app.DB2CallableStatement.execute2(Compiled Code) at COM.ibm.db2.jdbc.app.DB2PreparedStatement.execute(Compiled Code) at call_Add_customer_with_userid.main(Compiled Code)
Solution
The JAR or class has not been made available to the database. If you are using JAR files, you must use the sqlj.install_jar routine. If you are not using JAR files, you copy the .class to location specified in the statement.
6.7.2.3 SQL20201N JAR name is invalid during sqlj.install_jar
Symptom
An error message is produced when trying to insert a valid JAR name.
Example
The command: call sqlj.install_jar('file:/u/db2inst3/apps/ACMESUS/ACMESUS.jar','ACMESUS'); Produced the error message: SQL20201N The install, replace or remove of "ACMES the jar name is invalid. SQLSTATE=46002
.ACMESUS" failed as
Solution
The JAR is already defined to the database. You need to remove it or replace it.
114
Symptom
When issuing any sqlj.xxxxxx command from Windows NT, such as:
call sqlj.refresh_classes(void)
Solution
This is a maintenance issue, which has been resolved in Version 7 Fixpak 1. Note that despite this message, the command actually works.
6.7.2.5 The sqlj command hangs
Symptom
The sqlj command hangs after producing .java and .ser files.
Possible Solution
Try using the -compile=false option to split the precompile step from the Java compile. Often, sqlj will complete successfully and a subsequent javac will reveal Java errors that need to be corrected in your program source.
6.7.2.6 SQLCODE -818 when executing SQLJ stored procedure
Symptom
Client receives SQLCODE -818 (timestamp mismatch error) when trying to invoke an SQLJ stored procedure on the Windows NT or AIX platform, even after the program preparation process has been completely re-run.
Possible Solution
Check the subdirectories within the SQLLIB/function directory to ensure that an old version of the .jar file containing your stored procedure code has not found its way into another directory. If this happens, DB2 may pick up the old version, generating the -818 error. Try to remove the old version using the sqlj.remove_jar command; if that fails, simply delete the culprit.
115
6.7.2.7 SQL4304N .. could not load Java class reason code "1"
Symptom
When trying to execute a Java stored procedure that appears to have installed correctly, the following error message returns to the client:
COM.ibm.db2.jdbc.app.DB2Exception: [IBM][CLI Driver][DB2/6000] SQL4304N Java stored procedure or user-defined function "ACMEBUS .ADD_CUSTOMER", specific name "SQL000322080850190" could not load Java class "ACMEBUS/Add_customer", reason code "1". SQLSTATE=42724
Solution
This is typically caused by forgetting to change the Java package name in the Java source code after having copied source code from one directory to another. Everything compiles and installs fine. However, during execution the stored procedure actually has a different Java package name. It is peculiar that the mismatch is not found during the javac step.
6.7.2.8 SQLCODE==> -965 SQLSTATE ==> 51021
Symptom
The system cannot find a matching method (stored procedure), even if you were able to install it in the database with no errors.
java.sql.SQLException: DB2JDBCSection Received Error in Method execute_call:SQLCODE==> -965 SQLSTATE ==> 51021 Error Tokens ==> <<DB 2/OS390 V5.1 ANSI SQLJ-0/JDBC 1.0>> QUERY_OI_SUMM java.lang.NoSuchMethodError: query_oi_summ ^20^L ^20^L ^20^L ^20^L ^20^L at COM.ibm.db2os390.sqlj.jdbc.DB2SQLJJDBCSection.setError(DB2SQLJJDBCSection. java:1049) at COM.ibm.db2os390.sqlj.jdbc.DB2SQLJJDBCSection.execute_call(DB2SQLJJDBCSect ion.java:874) at COM.ibm.db2os390.sqlj.jdbc.DB2SQLJCallableStatement.execute(DB2SQLJCallabl eStatement.java:116) at jecall_Query_oi_summ.main(jecall_Query_oi_summ.java:86)
116
Solution
The number of parameters the client sent to DB2 does not match the number of parameters that DB2 understands the stored procedure to contain. This often is caused by forgetting to set the number of ResultSets when defining the stored procedure. This is somewhat perplexing when comparing source code against the stored procedure definition. The source code may show, for example, 5 parameters, yet the stored procedure definition shows 4. The difference is in the ResultSets value of the definition. Consequently, (the number of parameters in the source code) should equal ((the number of parameters in the stored procedure definition) + (the number of ResultSets in the stored procedure definition)).
6.7.2.9 SQLCODE==> -471 SQLSTATE ==> 55023
Symptom
The client returns an error message similar to this:
ava.sql.SQLException: DB2JDBCSection Received Error in Method execute_call:SQLCODE==> -471 SQLSTATE ==> 55023 Error Tokens ==> <<DB 2/OS390 V5.1 ANSI SQLJ-0/JDBC 1.0>> QUERY_OI_SUMM 00E79001 ^20^L at COM.ibm.db2os390.sqlj.jdbc.DB2SQLJJDBCSection.setError(DB2SQLJJDBCSection. java:1049) at COM.ibm.db2os390.sqlj.jdbc.DB2SQLJJDBCSection.execute_call(DB2SQLJJDBCSect ion.java:874) at COM.ibm.db2os390.sqlj.jdbc.DB2SQLJCallableStatement.execute(DB2SQLJCallabl eStatement.java:116) at jecall_Query_oi_summ.main(jecall_Query_oi_summ.java:86)
Solution
Recognize where the error is being seen: at the client, or when trying to invoke the stored procedure. The SQLSTATE value (the Class Code value of 55) implies that the object is not in the prerequisite state. From a stored procedure perspective, it means that a previous incarnation of the stored procedure ended badly in the database, putting it into a state that prevents it from being executed. Contact your DBA to determine the best method to make it available again.
117
Symptom
Error message from db2profc similar to:
[IBM][SQLJ Driver] SQJ0001W Customizing profile "sscall_Add_customer_SJProfile0" JNI panic: JNI received a null class at COM.ibm.db2.sqlj.DB2SQLJInstaller.customizeProfile(DB2SQLJInstaller.j ava:263) at COM.ibm.db2.sqlj.DB2SQLJInstaller.main(DB2SQLJInstaller.java:1204) Solution
One cause may be special characters embedded within the SQL, such as newlines. Carefully replace all whitespace within the SQL (or delete the whitespace).
6.7.2.11 Cannot call a schema-qualified stored procedure
Symptom
During db2profc, an error message returns indicating that several stored procedures match the name. (However, the source code has qualified the call with a Schema). The error message looks like:
sscall_Add_customer.sqlj:76.1-79.6: Error: Unable to resolve stored procedure ACMESNS.ADD_CUSTOMER - 2 declarations match this call. Total 1 error. Solution
There may be a fix available for this error....investigate the IBM DB2 Web site for availability. Alternatively, use a unique stored procedure name that is not shared across schemas.
118
119
For JDBC stored procedures, all that is required are the 4 generic JDBC DB2 packages that are bound at the time JDBC support is installed (called DSNJDBC1, DSNJDBC2, DSNJDBC3 and DSNJDBC4). For SQLJ stored procedures, 4 application specific DB2 packages will be produced as part of the program preparation process. See 9.1, DB2 plans and packages on page 167 for a discussion on how these are used when binding client program plans.
Authorization checking is performed at the time the SQLJ DB2 packages for the stored procedure are bound to DB2 (see 7.2.4, OS/390 SQLJ program preparation process on page 129), and you may use any of the usual BIND parameters (such as OWNER and QUALIFIER) to achieve the security environment you need. The authorization ID binding the client plan will require EXECUTE authority on the stored procedure DB2 packages (see 9.1, DB2 plans and packages on page 167).
7.2.2.2 JDBC stored procedures As JDBC stored procedures use dynamic SQL, the authorization issues become a lot more complex.
When trying to understand the DYNAMICRULES options discussed below, you should remember that DB2 first attempts to use the option specified for the generic JDBC stored procedure DB2 packages. If DYNAMICRULES is not specified for the packages, DB2 will use the value specified in the client plan. If you do not explicitly code a value for the DYNAMICRULES option at the time you bind the JDBC generic DB2 packages (DSNJDBC1, DSNJDBC2, DSNJDBC3, and DSNJDBC4) or the client plan, then by default DB2 will use run behavior.
120
Authorization checking for any dynamic SQL statements executed by the JDBC stored procedure will be conducted using the CURRENT SQLID of the client application (which is set to the clients primary authorization ID unless explicitly changed with a SET CURRENT SQLID statement prior to the stored procedure call). Therefore, all client authorization IDs must be given the necessary access to any tables that may be used by the stored procedure, which can be undesirable from a security and administration perspective. Use of DYNAMICRULES(BIND) when binding the JDBC generic DB2 packages or the client plan causes DB2 to use bind behavior. The authorization ID of the DB2 package owner will be used for authorization checking, which removes the requirement to give table access to each client authorization ID. Note that use of this option will prevent the stored procedure from being able to use the SQL GRANT, REVOKE, CREATE, ALTER, DROP and RENAME statements. Two new options in DB2 for OS/390 V6 provide even more flexibility, due to the implementation of stored procedure schema support. Specifying DYNAMICRULES(DEFINEBIND) when binding the JDBC generic DB2 packages or the client plan causes DB2 to use define behavior. The authorization ID of the owner (or schema) of the stored procedure will be used for authorization checking. This allows a number of alternative security strategies to be considered (for example, you could create the stored procedure in the same schema as your DB2 tables, which would implicitly give the stored procedure access to any tables in that schema).
DYNAMICRULES(DEFINERUN)
For stored procedure DB2 packages, use of the DYNAMICRULES(DEFINERUN) option is equivalent to DYNAMICRULES(DEFINEBIND). Specifying DYNAMICRULES(INVOKEBIND) when binding the JDBC generic DB2 packages or the client plan causes DB2 to use invoke behavior. If the CURRENT SQLID is set to the primary authorization ID of the client process at the time of the stored procedure call, both the primary authorization ID and all secondary authorization IDs are used for authorization checking. Otherwise, just the CURRENT SQLID is used.
121
DYNAMICRULES(INVOKERUN)
For stored procedure DB2 packages, use of the DYNAMICRULES(INVOKERUN) option is equivalent to DYNAMICRULES(INVOKEBIND). For a full explanation of the DYNAMICRULES BIND option, refer to DB2 UDB for OS/390 Command Reference , SC26-9006.
Source
Java Bytecode
Other CLASS files
4
CREATE PROCEDURE or INSERT into SYSPROCEDURES
prog.JAVA
prog.CLASS
External Link
JLL in PDSE
Optional Step
1. From within USS, Java-compile the source code (using the javac command). This produces one or more .class files, which represent the Java bytecode for your procedure. 2. If you wish, you may package multiple .class files into a single .jar file via the jar command. This step is entirely optional, and as we are already packaging multiple .class files into a single OS/390 executable in the HPJ step next anyway, we elected to omit it.
122
3. HPJ-compile the .class files produced in step 2 to create an OS/390 Java DLL. This module resides in a PDSE data set, but HPJ also creates an external link to the module, to allow it to be referenced from within the USS environment. 4. Define the stored procedure to DB2 (via an INSERT into SYSIBM.SYSPROCEDURES for DB2 for OS/390 V5, or via CREATE PROCEDURE if you are using DB2 UDB for OS/390 V6). Unlike DB2 UDB for UNIX and DB2 UDB for Windows NT, DB2 for OS/390 allows you to perform this step before the stored procedure exists.
Use of COLLID
We recommend that you explicitly specify the DB2 package collection that your stored procedure DB2 packages will reside in. For JDBC stored procedures, you will specify the DB2 package collection that the 4 generic JDBC packages belong to (these generic packages will have been created when JDBC support was installed, using the db2genJDBC utility - see JDBC Support on page 59). The way in which you can accomplish this depends upon the release of DB2 UDB for OS/390 you are using: - For DB2 UDB for OS/390 V5, you can provide a value for the COLLID column when performing the INSERT into SYSIBM.SYSPROCEDURES. - For DB2 UDB for OS/390 V6, you can specify the COLLID keyword on the CREATE PROCEDURE statement. If you do not do this, you will be forced to bind the 4 JDBC DBRMs into DB2 packages belonging to the same collection as the clients DB2 package. See 9.1, DB2 plans and packages on page 167 for more details).
Development platform
Steps 1 and 2 of this process can be performed on any platform that contains a suitable JDK. We performed them within UNIX Systems Services (USS) within an S/390 environment. Steps 3 and 4 must be performed on the S/390 platform.
123
7.2.3.1 OS/390 JDBC detailed preparation example The example JDBC stored procedure has been coded with this Java package statement:
package ACMEJOS;
The use of package statements is obligatory on the S/390 platform. To build this program, go up one directory from the source. For example, if your source was in /U/DB2RES3/ACMEJOS/Add_customer.java, then you change directory to /U/DB2RES3 to execute the build statements. Start by compiling your Java source using the javac Java command, as follows:
javac ACMEJOS/Add_customer.java
The resulting .class files are placed in the ACMEJOS subdirectory. Next, you need to perform the HPJ compile. Here is the command as we used:
hpj -o "//'SG245945.HPJSP.PDSE(ACMEJOS)'" -alias ACMEJOS.jll -O -jll -nofollow -t /u/sysadm/links ACMEJOS/Add_customer >hpj.map 2>&1 \ \ \ \ \ \ \
Refer to the VisualAge for Java Version 2.0 ET/390 Reference for a full explanation of the hpj command parameters. Here is a brief description of the main ones used in the command above: -o specifies the output PDSE data set that will contain the OS/390 executable. This data set must be allocated to your WLM address space (see JCL procedure sample shown in 4.1.6.2, JCL procedure of a Java WLM-established address space on page 67). -alias specifies the name of the alias to be created in the output PDSE data set. This must correspond with the Java package name within your stored procedure code.
124
-t specifies the name of the USS directory used to store links to the PDS data set. Upon completion of the compile, you should have an OS/390 executable and alias within your PDSE data set, and a link to the executable within your USS links library. For an overview of the runtime environment for an SQLJ stored procedure, see Figure 13 on page 95. If you have not done so already, you now need to define your stored procedure to DB2. The location of your stored procedure is specified using the format <package>.<class>.<method>, where <package> is the Java package name, and <class> and <method> are the class and method names defined in your code. DB2 for OS/390 Version 5 requires you to manually insert a row into SYSIBM.SYSPROCEDURES:
INSERT INTO SYSIBM.SYSPROCEDURES (PROCEDURE,AUTHID,LUNAME,LOADMOD,LINKAGE,COLLID, LANGUAGE,ASUTIME,STAYRESIDENT,IBMREQD, RUNOPTS, PARMLIST, RESULT_SETS,WLM_ENV,PGM_TYPE, EXTERNAL_SECURITY,COMMIT_ON_RETURN) VALUES( 'JS_ADD_CUSTOMER', '', '', '', 'N', 'DSNJDBC', 'COMPJAVA', 900, '','N', 'ACMEJOS/Add_customer.add_customer', 'CHAR(20) IN, CHAR(20) IN, CHAR(30) IN, INTEGER OUT, CHAR(40) OUT, CHAR(240) OUT', 0,'WLM_JAVA_DB21','S','N','N' );
Note
For DB2 for OS/390 Version 5, the RUNOPTS column of SYSPROCEDURES is used to store the procedure name, and the LOADMOD column is ignored. This is due to the fact that LOADMOD can only hold 8 characters. DB2 UDB for OS/390 Version 6 provides full DDL and schema support for stored procedures, so the equivalent command would be as follows:
CREATE PROCEDURE ACMEJOE.ADD_CUSTOMER ( IN FIRSTNAME CHAR(20), IN LASTNAME CHAR(20), IN ADDRESS CHAR(30), OUT CUSTNO INTEGER,
125
OUT MARK CHAR(40) OUT MARK_ERROR_TEXT CHAR(200) ) FENCED MODIFIES SQL DATA LANGUAGE COMPJAVA EXTERNAL NAME(ACMEJOE.Add_customer.add_customer) PARAMETER STYLE JAVA COLLID DSNJDBC WLM ENVIRONMENT DBS1JAVAWLM DYNAMIC RESULT SETS 0 PROGRAM TYPE SUB;
Use of COLLID
In the example above, we have specified a DB2 package collection of DSNJDBC for the JDBC stored procedure. This is the name of the collection we bound the 4 generic JDBC DBRMs into at the time JDBC support was installed. See JDBC Support on page 59 for further details. The stored procedure is now ready for execution.
7.2.3.2 Sample program preparation scripts We used the scripts below for JDBC program preparation. Note: These scripts can be found on the CD-ROM, in the SAMPLES\S390 UTILITIES\PROGRAM PREPARATION directory. Refer to Appendix E, Using the
additional material on page 347 for more information. The entire process is invoked from the USS command line using a syntax such as:
javaspj Add_customer ACMEJOS ACMEJOS acmes ACMEJOS
Script javaspj prepare JDBC stored procedure This script performs the main program preparation tasks, and calls script hpjsp to perform the HPJ compile.
# JDBC stored procedure with no SQLJ # phase 1 javac # phase 2 hpj # # Call format for shell is => javaspj pgm pkg mem qualifier pdsemem
126
# Example => javaspj $1 $2 $3 $4 # $1= Java class name # $2= Java package name # << $3 Not used for JDBC only >> # $3= Member package name used for binds - limit 7 # $4= Table qualifier # $5= OS/390 PDSE member name - uppercase limit 8 # pgm=$1 # pgm is the Java class name. # pkg=$2 # pkg is the used for the SP package collection, JAVA package, # directory where the JAVA code is. # mem=$3 # Member package name used for binds - limit to 7 characters # qual=$4 # qual is the table qualifier pdse=$5 # pdse is the OS/390 PDSE member name - uppercase limit to 8 characters # # set directory to Java code #cd $pkg #pgmuln=$1'_SJProfile0' #echo $pgmuln echo "Starting phase 1 - JDBC javac for" $pkg $pgm javac $pkg/${pgm}.java echo "Starting phase 2 - JDBC hpj compile" hpjsp $pkg $pdse # echo "JDBC build for" $pkg $pgm "complete"
127
Script hpjsp perform HPJ compile This script executes the HPJ compile process, to create an OS/390 executable module from the Java classes.
echo "Starting hpj for $1 $2" U2=`echo $2 | tr 'a-z' 'A-Z'` echo "current dir is `pwd`" echo "building member in SG245945.HPJSP.$SSID.PDSE($U2)" echo "building links in /u/$SSID/links" CLASSES_TO_USE=`ls $1/*.class | sed 's/.class//'` echo "using classes $CLASSES_TO_USE " # -classpath .:/usr/lpp/hpj/lib/classes.zip \ hpj -o "//'SG245945.HPJSP.$SSID.PDSE($U2)'" \ -alias $1.jll \ -O \ -jll \ -nofollow \ -t /u/$SSID/links \ $CLASSES_TO_USE \ >hpj$1.map 2>&1 echo 'Ended hpj for ' $1 $2 ' - results' more hpj$1.map
128
SQLJ Source
prog.JAVA prog.SQLJ
SQLJ Translator
prog.CLASS
prog_ SJProfileKeys.class
JAR
prog_ SJProfile0.ser
Serialized Profile
DBRM DBRM
HPJ Compiler
.JAR file
Optional Step
External Link
JLL in PDSE
7
CREATE PROCEDURE or INSERT into SYSPROCEDURES
DB2 Catalog
1. From USS, translate your source code using the sqlj command. This will extract all of the embedded SQL from your code and place it in an SQLJ serialized profile (a kind of generic, database independent DBRM). Serialized profiles are stored in .ser files. Your source code will be modified, and placed in a .java file. 2. Java-compile the source code (using the javac command). This will produce at least two .class files one containing your code and one containing the SQLJ access stub.
129
Note
there is no need to perform this step separately. 3. If you wish, you may package multiple .class (or .jar) files into a single .jar file via the jar command. This step is entirely optional, and as we are already packaging multiple .class files into a single OS/390 executable in the HPJ step next anyway, we elected to omit it. 4. HPJ-compile the .class files produced in step 2 to create an OS/390 executable module. This module resides in a PDSE data set, but HPJ also creates an external link to the module, to allow it to be referenced from within the USS environment. 5. Execute the DB2 profile customizer using the db2profc command. This translates the generic serialized profile created in step 1 into a set of 4 DB2 for OS/390 DBRMs (one for each type of isolation level: repeatable read, read stability, cursor stability and uncommitted read). 6. Bind the 4 DBRMs produced by db2profc into DB2 packages using standard DB2 for OS/390 BIND PACKAGE commands. The DB2 packages can belong to any DB2 package collection - in our examples we named the DB2 package collection after the Java package name. 7. Define the stored procedure to DB2 (via an INSERT into SYSIBM.SYSPROCEDURES for DB2 for OS/390 V5, or via CREATE PROCEDURE if you are using DB2 UDB for OS/390 V6).
130
Use of COLLID
We recommend that you explicitly specify the DB2 package collection that your stored procedure DB2 packages will reside in. For SQLJ stored procedures, you will specify the DB2 package collection that you bound your 4 application specific DBRMs into earlier. The way in which you can accomplish this depends upon the release of DB2 UDB for OS/390 you are using; - For DB2 UDB for OS/390 V5, you can provide a value for the COLLID column when performing the INSERT into SYSIBM.SYSPROCEDURES. - For DB2 UDB for OS/390 V6, you can specify the COLLID keyword on the CREATE PROCEDURE statement. If you do not do this, you will be forced to bind the 4 SQLJ DBRMs into DB2 packages belonging to the same collection as the clients DB2 package. See 9.1, DB2 plans and packages on page 167 for more details).
Development platform
Steps 1 to 3 of this process can be done on any platform that contains a suitable JDK. We performed them within UNIX Systems Services (USS) in an S/390 environment. Steps 4 to 7 must be performed on the S/390.
7.2.4.1 OS/390 SQLJ detailed preparation example The SQLJ stored procedure has been coded with this Java package statement:
package ACMESOS;
The use of package statements is obligatory on the S/390 platform. To build this program, go up one directory from the source. For example, if your source was in /U/DB2RES3/ACMESOS/Add_customer.java, then you change directory to /U/DB2RES3 to execute the build statements. Start by precompiling your SQLJ source program using the sqlj command, as follows:
131
sqlj ACMESOS/Add_customer.sqlj
Due to an oddity in our environment, we were forced to fully qualify the location of the sqlj routine in order to get it to work with SQLJ source files that were located in subdirectories. The command we used was:
/usr/lpp/db2/db2510/bin/sqlj ACMESOS/Add_customer.sqlj
This can be made more generic by using the whence command to return the location of sqlj in your environment, like this:
`whence sqlj` $pkg/$pgm.sqlj
This is the command that appears in our sample preparation scripts. By default, sqlj will also invoke javac (the Java compiler) to save you from having to do this separately afterwards (to disable this and run javac yourself, use the -compile=false option). Assuming that you elected to automatically run javac as part of sqlj, the output of the command will be: A .java file containing a modified version of your source. As this will be immediately input to javac to produce .class files, the .java file plays no further part in the program preparation process and may be considered an intermediate temporary file. At least two Java .class files (one for your stored procedure code and one, called <classname>_SJProfileKeys.class, for the SQLJ stub). A serialized profile, called <classname>_SJProfile0.ser. This contains the SQL statements extracted by the sqlj process, in a generic database independent format. Next, we need to perform the HPJ compile. Here is the command we used during our tests:
hpj -o "//'SG245945.HPJSP.PDSE(ACMESOS)'" -alias ACMESOS.jll -O -jll -nofollow -t /u/sysadm/links ACMESOS/Add_customer ACMESOS/Add_customer_SJProfileKeys >hpj.map 2>&1 \ \ \ \ \ \ \ \
132
Refer to the VisualAge for Java Version 2.0 ET/390 Reference1, for a full explanation of the hpj command parameters. Here is a brief description of the main ones used in the commands above: -o specifies the output PDSE data set that will contain the OS/390 executable. This data set must be allocated to your WLM address space (see JCL procedure sample shown in 4.1.6.2, JCL procedure of a Java WLM-established address space on page 67). -alias specifies the name of the alias to be created in the output PDSE data set. This must correspond with the Java package name within your stored procedure code. -t specifies the name of the USS directory used to store links to the PDS data set.
Including the correct class files
You need to include all of the .class files produced by the sqlj step in the hpj compile, including the <classname>_SJProfileKeys.class stub. Upon completion of the compile, you should have an OS/390 executable and alias within your PDSE data set, and a link to the executable within your USS links library. For an overview of the runtime environment for an SQLJ stored procedure, see Figure 13 on page 95. Next, you need to execute db2profc, which takes the serialized profile created by sqlj above and creates four DB2 for OS/390 DBRMs. Below is an example of how to invoke the db2proc:
db2profc -pgmname=ACMESOS ACMESOS/Add_customer_SJProfile0.ser
In our example, the DBRMs that would be generated are called ACMESOS1, ACMESOS2, ACMESOS3 and ACMESOS4.These DBRMS are used to represent the different isolation levels that could be used (UR, CS, RS and RR for ACMESOS1 to 4 respectively). The DBRMs will be placed in the PDS specified in the DB2SQLJDBRMLIB parameter of your SQLJ properties data set (see 4.1.8, Step 6: Set up the JAVAENV data set on page 69). In the examples below, the PDS is
SG246945.SAMPLIB.DBRM.
Now we have our DBRMs, we can BIND them. The DB2 packages we bind can belong to any DB2 package collection. In our example we are using a DB2
At the time of writing, the ET/390 manuals did not have formal IBM publication numbers. However, they can be downloaded from the Web in PDF format at http://www-4.ibm.com/software/ad/vajava/library.htm.
1
133
package collection named after the Java package referenced in our stored procedure:
BIND PACKAGE(ACMESOS) MEMBER(ACMESOS1) ACT(REP) ISOLATION(UR) VALIDATE(BIND) LIBRARY('SG246945.SAMPLIB.DBRM') QUALIFIER(ACMES) BIND PACKAGE(ACMESOS) MEMBER(ACMESOS2) ACT(REP) ISOLATION(CS) VALIDATE(BIND) LIBRARY('SG246945.SAMPLIB.DBRM') QUALIFIER(ACMES) BIND PACKAGE(ACMESOS) MEMBER(ACMESOS3) ACT(REP) ISOLATION(RS) VALIDATE(BIND) LIBRARY('SG246945.SAMPLIB.DBRM') QUALIFIER(ACMES) BIND PACKAGE(ACMESOS) MEMBER(ACMESOS4) ACT(REP) ISOLATION(RR) VALIDATE(BIND) LIBRARY('SG246945.SAMPLIB.DBRM') QUALIFIER(ACMES)
If you have not done so already, you now need to define your stored procedure to DB2. The location of your stored procedure is specified using the format <package>.<class>.<method>, where <package> is the Java package name, and <class> and <method> are the class and method names defined in your code. DB2 for OS/390 Version 5 requires you to manually insert a row into
SYSIBM.SYSPROCEDURES; INSERT INTO SYSIBM.SYSPROCEDURES (PROCEDURE,AUTHID,LUNAME,LOADMOD,LINKAGE,COLLID, LANGUAGE,ASUTIME,STAYRESIDENT,IBMREQD,
134
RUNOPTS, PARMLIST, RESULT_SETS,WLM_ENV,PGM_TYPE, EXTERNAL_SECURITY,COMMIT_ON_RETURN) VALUES( 'SS_ADD_CUSTOMER', '', '', '', 'N', 'ACMESOS', 'COMPJAVA', 900, '','N', 'ACMESOS/Add_customer.add_customer', 'CHAR(20) IN, CHAR(20) IN, CHAR(30) IN, INTEGER OUT, CHAR(40) OUT, CHAR(240) OUT', 0,'WLM_JAVA_DB21','S','N','N' );
Note
For DB2 for OS/390 Version 5, the RUNOPTS column of SYSPROCEDURES is used to store the procedure name. This is due to the fact that the LOADMOD column can only hold 8 characters. DB2 UDB for OS/390 Version 6 provides full DDL and schema support for stored procedures, so the equivalent command would be as follows:
CREATE PROCEDURE ACMESOE.ADD_CUSTOMER ( IN FIRSTNAME CHAR(20), IN LASTNAME CHAR(20), IN ADDRESS CHAR(30), OUT CUSTNO INTEGER, OUT MARK CHAR(40) OUT MARK_ERROR_TEXT CHAR(200) ) FENCED MODIFIES SQL DATA LANGUAGE COMPJAVA EXTERNAL NAME(ACMEJOE.Add_customer.add_customer) PARAMETER STYLE JAVA COLLID ACMESOS WLM ENVIRONMENT DBS1_JAVA_WLM DYNAMIC RESULT SETS 0 PROGRAM TYPE SUB;
135
directory. Refer to Appendix E, Using the additional material on page 347 for more information. The entire process is invoked from the USS command line using a syntax such as:
javasp Add_customer ACMESOS addcust acmes ACMESOS
Script javasp prepare SQLJ stored procedure This script performs the main program preparation tasks, and calls scripts hpjsp to perform the HPJ compile and bindsp to create and execute the necessary BIND statements.
# java stored procedure with SQL # phase 1 SQLJ translator # phase 2 db2profc create DBRMs # phase 3 HPJ compile # phase 4 bind packages # phase 5 copy *.ser files # # Call format for shell is => javasp nam pkg mem qualifier pdsemem # Example => javasp $1 $2 $3 $4 # $1= Java class name # $2= Java package name # $3= Member package name used for binds - limit 7 # $4= Table qualifier # $5= OS/390 PDSE member name - uppercase limit 8 # pgm=$1 # pgm is the Java class name. pkg=$2 # pkg is the used for the SP package collection, JAVA package, # directory where the JAVA code is, HPJ module name and DB2 package # collection name mem=$3 # mem package name used for binds - limit to 7 characters qual=$4 # qual is the table qualifier pdse=$5 # pdse is the OS/390 PDSE member name - uppercase limit to 8 characters # pgmuln=$1'_SJProfile0' echo $pgmuln echo "Starting phase 1 - SQLJ translator" $pkg $pgm
136
`whence sqlj` $pkg/$pgm.sqlj echo "Starting phase 2 db2profc -pgmname=$mem echo "Starting phase 3 hpjsp $pkg $pdse # echo "Starting phase 4 - db2profc" $pkg/$pgmuln.ser - HPJ compile"
- bind plans"
bindsp.rexx $mem $pkg $qual umem=`echo $mem | tr 'a-z' 'A-Z'` cat bind$SSID$umem.out | sed 's/ *$//' # # copy *.ser files to /u/$SSID/ser # echo "Starting phase 5 - copying *.ser files to /u/$SSID/ser" cp $pkg/*.ser /u/$SSID/ser/$pkg chmod 777 /u/$SSID/ser/$pkg/* echo "Build for" $pkg $pgm "complete"
Script hpjsp perform HPJ compile See Script hpjsp perform HPJ compile on page 128. Script bindsp.rexx generate/execute BIND PACKAGE commands This script builds the bind statements and passed them to the TSO REXX exec OEBIND.
/* /* /* /* /* /* /* /* /* /* /* /* /* /* /* /* rexx Unix System Services (USS) bindsp.rexx MEM PKG qual called by JAVA prep shell scripts to bind the stored procedure packages. */ */ */ */ */ Licensed Materials - Property of IBM */ */ (C) COPYRIGHT International Business Machines Corp. 1995, 1997 */ All Rights Reserved. */ */ US Government Users Restricted Rights - Use, duplication or */ disclosure restricted by GSA ADP Schedule Contract with IBM Corp. */ Written 03/05/200 by Michael J. Fischer */ */ Input parms: 3 */ MEM package base name */
137
/* /* /* /* /* /* /* /* /* /* /* /* /* /*
name) */ unqualified tables. */ PDSE library */ */ unqualified tables. */ */ Calls TSOE rexx program "OEBIND" to run DSN in TSOE */ environment. This was done so the JAVA prep shell scripts */ can run in the OMVS or telnet environment. DSN will not run */ under telnet. */ */ To display help enter bindsp.rexx ? or bindsp.rexx '?' */ */ Note: In USS the ? is converted to a 2 */
Collection name (java Package Table qualifier name used for DBRM member name used for the Package name for bind. Table qualifier name used for
arg MEM PKG qual if MEM = "?" | MEM = 2 then do do i = 1 while substr(sourceline(i),1,2) = "/*" say sourceline(i) end return 0 end if length(MEM) > 7 then do say "ERROR**** Package base name must be 7 characters or less" say "Unable to create BIND statements" return 999 end x=0 /* Find the DB2SQLJPROPERTIES environment variable and set it. */ /* If no DB2SQLJPROPERTIES variable set then default to */ /* db2sqljjdbc.properties in working directory */ do I = 1 to __environment.0 if substr(__environment.i,1,17) = 'DB2SQLJPROPERTIES' then do DB2SQLJPROPERTIES = substr(__environment.i,19,length(__environment.i)-18) x=1 end if substr(__environment.i,1,5) = 'TERM=' then do termenv = substr(__environment.i,6,length(__environment.i)-5) end end if x=0 then DB2SQLJPROPERTIES = 'db2sqljjdbc.properties' /* Pick up the DB2 subsystem ID and DBRMLIB to use for the Binds */
138
/* from the DB2SQLJPROPERTIES file. address syscall "readfile (DB2SQLJPROPERTIES) file." if retval < 0 then do say "ERROR*** The" DB2SQLJPROPERTIES "file does not exist" say "Unable to create BIND statements" return 999 end else do i = 1 to file.0 if substr(file.i,8,4) = 'SSID' then ssid = substr(file.i,13,length(file.i)-12) if substr(file.i,8,7) = 'DBRMLIB' then dbrmlib = substr(file.i,16,length(file.i)-15) if substr(file.i,8,8) = 'PLANNAME' then planname = substr(file.i,17,length(file.i)-16) end /* /* Build the BIND statements and save them in file BINDssidINPUT /*
*/
*/ */ */
say '****** NOTE: ******' say 'If this JAVA SP is called by a JAVA USS client make sure' say 'collection' PKG||'.* is in PLAN' planname '. If this collection' say 'is new to this plan, rebind it after adding collection.' say '*******************' b.0 = 5 b.1 ="BIND PACKAGE("PKG") MEMBER("MEM"1) ACT(REP) (BIND) LIBRARY('"DBRMLIB"') QUALIFIER("QUAL")" b.2 ="BIND PACKAGE("PKG") MEMBER("MEM"2) ACT(REP) (BIND) LIBRARY('"DBRMLIB"') QUALIFIER("QUAL")" b.3 ="BIND PACKAGE("PKG") MEMBER("MEM"3) ACT(REP) (BIND) LIBRARY('"DBRMLIB"') QUALIFIER("QUAL")" b.4 ="BIND PACKAGE("PKG") MEMBER("MEM"4) ACT(REP) (BIND) LIBRARY('"DBRMLIB"') QUALIFIER("QUAL")" b.5 ="END" input = "BIND"||ssid||"INPUT" address syscall "writefile ("||input||") 777 b." if retval=-1 then do "error*** writing bind input file" input return 999 end address syscall "getcwd cwd"
139
if retval=-1 then do "error*** getting current directory to save" return 999 end /* /* Call DSN on the tsoe os/390 to run. /* if termenv = 'vt100' then /* telnet "tso -t oebind" ssid cwd input mem else "tso oebind" ssid cwd input mem */ */ */ */
/* /* Remove input file with BIND statements in /* "rm" input /* /* make sure the directory exist for ser files in /u/ssid/ser/ /* address syscall "chdir /u/"ssid"/ser/"pkg if retval=-1 then do "chdir /u/"ssid"/ser/" if retval=-1 then do say "error*** getting directory /u/"ssid"/ser" return 999 end "mkdir" pkg 777 if retval=-1 then do say "error*** making directory /u/"ssid"/ser/"pkg return 999 end end /* reset current directory "chdir" cwd if retval=-1 then do say "error*** reseting directory" cwd "to current" return 999 end RETURN
*/ */ */
*/ */ */
*/
REXX exec OEBIND The REXX exec executes the BIND statements and send the bind output back to the USS HFS.
140
/* rexx TSOE BIND ssid path input */ /* */ /* Called from Unix System Services (USS) rexx programs "bindsp.rexx"*/ /* and 'bindcl_plan.rexx that built the BIND statements for the */ /* JAVA client or stored procedure programs. */ /* */ /* Licensed Materials - Property of IBM */ /* */ /* (C) COPYRIGHT International Business Machines Corp. 1995, 1997 */ /* All Rights Reserved. */ /* */ /* US Government Users Restricted Rights - Use, duplication or */ /* disclosure restricted by GSA ADP Schedule Contract with IBM Corp. */ /* Written 03/05/200 by Michael J. Fischer */ /* */ /* Input parms: 3 */ /* ssid DB2 subsystem group or member name. */ /* path USS HFS path name to store output file to. */ /* input USS HFS path and file name for BIND input file. */ /* pkg Java package name */ /* */ /* This REXX program will read the HFS file of BIND statements */ /* and put them to the REXX stack. It will then start the DB2 */ /* "DSN" program for the subsystem passed to process the Bind */ /* statements from the REXX stack. It will trap the output from */ /* the BINDs and copy them to a HFS file back on USS */ /* */ /* To call this REXX exec from OS/390 Unix System Services running*/ /* telnet, add the following statements to your .profile. */ /* */ /* .profile */ /* ##### Added for tso -t from telnet */ /* # Assign the DD names to allocate */ /* # */ /* export TSOALLOC=sysexec */ /* # */ /* # Allocate the OpenMVS EXEC data set to SYSEXEC */ /* # */ /* export sysexec=SYS1.OS390.EXEC <== library where you stored */ /* # this exec. */ /* */ /* For help enter: OEBIND ? or OEBND '?' */ parse arg ssid path input pkg . if ssid = "?" | ssid = "'?'" then do do i = 1 while substr(sourceline(i),1,2) = "/*" say sourceline(i)
141
end return 0 end l='abcdefghijklmnopqrstuvwxyz' u='ABCDEFGHIJKLMNOPQRSTUVWXYZ' ssid = translate(ssid,u,l) say "SSID is " ssid patho = "'"||path||"/bind"||ssid||pkg||".out'" input = "'"||path||"/"||input||"'" /* allocate bind output file "alloc fi(bindout) da(dsn.bindout) unit(sysallda) new reuse, space(16,16) tracks recfm(f,b) lrecl(131) blksize(13100)" /* allocate bind input file to copy bind statements to "alloc fi(bindin) da(dsn.bindin) unit(sysallda) new reuse, space(1,1) tracks recfm(v,b) lrecl(1024) blksize(13100)" /* allocate bind input hfs file with bind statements in 'alloc ddname(hfsin) path('input') pathopts(ordwr,ocreat)', 'pathmode(sirusr,siwusr)' 'ocopy indd(hfsin) outdd(bindin) text convert(no)' 'free fi(hfsin)' (STEM in. FINIS" */
*/
*/
/* turn on outtrap to capture bind output statements from DSN x = OUTTRAP('VAR.') "DSN SYSTEM("ssid")" y = OUTTRAP('OFF') /*write bind output statement to a file to copy to hfs file "EXECIO" var.0" DISKW bindout (STEM var. FINIS" /* allocate bind output hfs file for bind 'alloc ddname(hfsout) path('patho') pathopts(ordwr,ocreat)', 'pathmode(sirusr,siwusr)'
*/
*/
*/
142
/* copy bind output to hfs file from bind run */'ocopy indd(bindout) outdd(hfsout) text convert(no)' 'free fi(hfsout)'
7.2.5.1 If you are OS/390 fluent If you are fluent in OS/390, you may need to learn a minimum set of UNIX commands. The technical investigation for this book was completed by two people fluent in OS/390 and one person fluent in UNIX. The OS/390 people were able to do most of their work with the following set of UNIX commands:
Also necessary is an understanding of environment variables such as CLASSPATH and how they are set in .profile.. More information about using these and other USS commands can be found in the OS/390 UNIX System Users Guide, SC28-1891. Alternatively, the early adaptors in your organization will have opportunities to develop mechanizations to hide UNIX from pure OS/390 devotees.
143
7.2.5.2 If you are UNIX fluent If you are UNIX fluent and are being asked to work on USS to access OS/390 DB2, most of your UNIX skillset will transfer immediately. The messages may look a little different, but for the most part it behaves like any other UNIX. You will be able to telnet or login into USS to use your favorite editor vi.
Your biggest difficulty may consist of those commands that must execute on OS/390. DSN was a major stumbling block for our group, requiring the construction of an extensive Kshell and Rexx procedure. The early adaptors in your organization will have opportunities to develop mechanizations to hide OS/390 from pure UNIX devotees.
The examples used in this section are for the Windows NT platform. Some minor changes (for example, the use of forward slashes (/) instead of back slashes (\) for directory names) will need to be made for the AIX platform.
2 From a programmers perspective, all work and all statements can be executed on a personal workstation. The define of the procedure, the install of the JAR, and so on, can be executed through a connection to a remote database. The one hitch is that the install and replace JAR routines require the JAR file to reside on the remote server.
144
Source
Java Bytecode
prog.JAVA
prog.CLASS
JAR
3
package.JAR
JAR File in sqllib/function
SQLJ.INSTALL_JAR
package.JAR
JAR File
Can run on any JDK platform
CREATE PROCEDURE
DB2 Catalog
1. Java Compile the source code (using the javac command). This produces one or more .class files, which represent the Java bytecode for your procedure. 2. Package the class file(s) produced in the previous into a single .jar file via the jar command. This step is mandatory for applications using the Java package statement. 3 3. Install the JAR file in the database using the sqlj.install_jar command. This provides a DB2 name for the JAR file, enters details of the classes contained within it to the SYSIBM.SYSJARCONTENTS catalog table, and copies the file to a standard location so that DB2 is able to access it at run time. 4. Define the stored procedure to DB2 using the CREATE PROCEDURE statement. Note that the stored procedure cannot be defined until its associated JAR file exists.
It is possible to avoid use of JAR files by leaving out the package statement in the JAVA source. The resulting class files are copied directly to the <DB2>/sqllib/function directory, as seen in the examples shipped with the database. However, as discussed earlier in Chapter 5, Designing Java stored procedures on page 83, this creates a flat namespace that may cause conflicts between different applications. We recommend using JAVA packages and JARs to segregate applications.
145
DB2 UDB for UNIX, Windows, OS/2 is very particular about the order in which these steps are conducted when it comes to JAR files. For example, it will not allow a procedure to be created until it exists in the referenced JAR file, or allow you to remove or refresh a JAR file while procedures are defined that refer to it. We found that the safest way to go about performing steps 3 and 4 above was to do the following; 1. Drop all procedures in the Java package via the SQL DROP PROCEDURE statement. 2. Call sqlj.remove_jar followed by sqlj.install_jar to re-install the JAR file in the correct location. 3. Re-create the procedures via the SQL CREATE PROCEDURE statement. This is the process that is used in our sample code. The process can be reliably rerun when re-preparing amended procedures. However, as all procedures in a given Java package have to be placed in the same JAR file, using this process means that you have to build the Java package gradually, procedure by procedure, in order to satisfy DB2s many consistency checks. For example, lets assume that we want to produce two procedures called
Add_customer and Add_order in a Java package called ACMEJNE.
We write the first procedure, Add_customer, and go through the SQLJ program preparation process. Using the steps above we first drop the procedure (which will not yet exist), remove the JAR definition (which will not exist), install the JAR (which should work) and then define the Add_customer procedure to DB2 via SQL CREATE PROCEDURE statement. When we write the second procedure, Add_order, we will need to drop both procedures, remove and re-install the JAR definition, and then define both procedures to DB2. If we try to perform the steps in any other order, or if we try to create the Add_order procedure before there is a definition for it within the JAR file, the process will fail.
146
7.3.1.1 NT / AIX JDBC preparation example In the DB2 UDB for UNIX, Windows, or OS/2 JDBC detailed preparation example, the JDBC stored procedure has been coded with this Java package statement:
package ACMEJNS;
Note
Although use of Java packages is not essential on the UNIX or Windows platforms, it is currently required on the OS/390 platform. If Java stored procedure portability is important to you, we recommend that you use Java packages when you code your stored procedures. To build this program, go up one directory from the source. For example, if your source was in C:\apps\ACMEJNS\Add_customer.java, then you change directory to C:\apps to execute the build statements. Start by compiling your Java source using the javac Java command:
javac ACMEJNS\Add_customer.java
The resulting .class files are placed in the ACMEJOS subdirectory. Create the JAR file to be made available to the database, as follows:
jar cvf ACMEJNS.jar ACMEJNS\*.class
Note
We use *.class to ensure that we pick up the class files for any other procedures within the Java package that may have been prepared
Note
Issue the following statements from a DB2 Command Line Processor (CLP) session. Drop all procedures in the Java package:
DROP PROCEDURE ACMESNE.Add_customer ; DROP PROCEDURE ACMESNE.Add_order ;
Install the JAR file in the database. As a precaution, we recommend that you drop it first, to allow for re-runs:
CALL SQLJ.REMOVE_JAR('ACMEJNS.ACMEJNS');
147
The first parameter of sqlj.install_jar or sqlj.replace_jar defines the location of the JAR file you created previously. The second parameter provides an identifer that you will use when referring to the JAR file from within DB2 commands. Note that we have qualified this identifier DB2 uses this qualifier to determine which subdirectory it will copy the JAR file to. In our example, DB2 will register the JAR file and copy it to sqllib\function\jar\ACMEJNS\ACMEJNS.jar. Now that DB2 knows about the JAR, we can define the stored procedure to DB2. Note that trying to define the procedure before the JAR has been registered will result in an error.
CREATE PROCEDURE ACMEJNS.Add_customer ( IN IN_CUST_FIRSTNAME CHAR(20), IN IN_CUST_LASTNAME CHAR(20), IN IN_CUST_ADDRESS CHAR(30), OUT OUT_CUST_NO INT, OUT MARK CHAR(40), OUT MARK_ERROR_TEXT CHAR(200) ) EXTERNAL NAME 'ACMEJNS.ACMEJNS:ACMEJNS.Add_customer.add_customer' RESULT SETS 0 LANGUAGE JAVA PARAMETER STYLE JAVA FENCED NO DBINFO ;
Note
As we dropped all of the procedures in the Java package earlier, you must remember to recreate all of them here, not just the one you are working on! The stored procedure is now ready for execution.
7.3.1.2 Sample program preparation scripts Although not nearly as sophisticated as the examples we created for the OS/390 platform, we did create some scripts for performing this program preparation process for Windows NT and UNIX. Samples can be found in the appendix.
148
Modfied Source
Java Bytecode
SQLJ Source
prog.JAVA prog.SQLJ
SQLJ Translator
prog.CLASS
prog_ SJProfileKeys.class
JAR
prog_ SJProfile0.ser
Serialised Profile
5
package.jar
JAR File
package.JAR
JAR File in sqllib/function
SQLJ.INSTALL_JAR
DB2 Catalog
CREATE PROCEDURE
1. Precompile your source code using the sqlj command. This will extract all of the embedded SQL from your code and place it in an SQLJ serialized profile (a kind of generic, database independent DBRM). Serialised profiles are stored in .ser files. Your source code will be modified, and placed in a .java file. 2. Java-compile the source code (using the javac command). This will produce at least two .class files one containing your code and one containing the SQLJ access stub.
149
Note
Unless you specifically request otherwise by specifying the -compile=false option, javac will be automatically executed by sqlj and there is no need to perform this step separately. However, you may wish to split these processes if you are encountering problems with the sqlj process (see 6.7.2.5, The sqlj command hangs on page 115) 3. Package the class file(s) produced in the previous into a single .jar file via the jar command. This step is mandatory if using the Java package statement. 4. Execute the DB2 profile customizer using the db2profc command. This takes the generic serialized profile created in step 1 and binds it directly to the DB2 database you specify.
Note
If you wish, you can specify the bindfile option in the -prepoptions parameter for db2profc. This will result in a standard .bnd file being produced, which you can then use to manually bind to DB2. By default, db2profc will execute the bind directly. 5. Install the JAR in the database (using the sqlj.install_jar command). This provides a DB2 name for the JAR file, enters details of the classes contained within it to the SYSIBM.SYSJARCONTENTS catalog table, and copies the file to a standard location4 so that DB2 is able to access it at run time. 6. Define the stored procedure to DB2 using the CREATE PROCEDURE statement. Note that the stored procedure cannot be defined until its associated JAR file exists.
The path is specified by the DB2INSTPROF parameter. The default value for this is sqllib/function.
150
DB2 UDB for UNIX, Windows, OS/2 is very particular about the order in which these steps are conducted when it comes to JAR files. For example, it will not allow a procedure to be created until it exists in the referenced JAR file, or allow you to remove or refresh a JAR file while procedures are defined that refer to it. We found that the safest way to go about performing steps 5 and 6 above was to do the following; 1. Drop all procedures in the Java package via the SQL DROP PROCEDURE statement 2. Call sqlj.remove_jar followed by sqlj.install_jar to re-install the JAR file in the correct location. 3. Re-create the procedures via the SQL CREATE PROCEDURE statement This is the process that is used in our sample code. The process can be reliably rerun when re-preparing amended procedures. However, as all procedures in a given Java package have to be placed in the same JAR file, using this process means that you have to build the Java package gradually, procedure by procedure, in order to satisfy DB2s many consistency checks. For example, lets assume that we want to produce two procedures called
Add_customer and Add_order in a Java package called ACMEJNE.
We write the first procedure, Add_customer, and go through the SQLJ program preparation process. Using the steps above we first drop the procedure (which wont yet exist), remove the JAR definition (which wont exist), install the JAR (which should work), and then define the Add_customer procedure to DB2 via CREATE PROCEDURE. When we write the second procedure, Add_order, we will need to drop both procedures, remove and re-install the JAR definition, and then define both procedures to DB2. If we try to perform the steps in any other order, or if we try to create the Add_order procedure before there is a definition for it within the JAR file, the process will fail.
151
Note
Steps 1 to 3 of this process can be done on any platform that contains a suitable JDK. We performed them within UNIX Systems Services (USS) in an S/390 environment. Steps 4 to 6 must be performed on the AIX or Windows NT platform you will be deploying the stored procedure on.
7.3.2.1 NT / AIX SQLJ detailed preparation example The example SQLJ stored procedure has been coded with this Java package statement:
package ACMESOS;
Note
Although use of Java packages is not essential on the Windows or UNIX platforms, it is currently required on the OS/390 platform. If Java stored procedure portability is important to you, we recommend that you use Java packages when you code your stored procedures. To build this program, go up one directory from the source. For example, if your source was in C:\apps\ACMESOS\Add_customer.sqlj, then you change directory to C:\apps to execute the build statements. Start by precompiling your SQLJ source file. By default, the sqlj command also executes javac to Java compile your procedure. The resulting files (Java .class files and an SQLJ serialized profile) are placed in the same directory as your source.
sqlj ACMESOS\Add_customer.sqlj
If you want to save the output messages, redirect them to files as in the following example. The > references standard output , the 2> references standard error.
sqlj ACMESOS\Add_customer.sqlj > outsqlj.txt 2>outsqlj2.txt
Execute db2profc, which takes the serialized profile created by the sqlj command and binds the SQL it contains to DB2.
db2profc -prepoptions="qualifier acmes package using addcust" -url=jdbc:db2:ACMES ACMESNS\Add_customer_SJProfile0
152
Use of the qualifier precompile option allows you to specify an identifier for DB2 to use for all unqualified table references in the procedure. The package using option allows you to name the DB2 package that db2profc will generate, which is essential if you have multiple procedures within one package. Other precompile options (such as specifying the plan owner) can also be used refer to the PRECOMPILE PROGRAM command in the DB2 UDB Command Reference. Create the JAR file to be made available to the database (note that we are including multiple class files and the serialized profile in the JAR).
jar cvf ACMESOS/ACMESOS.jar ACMESOS\*.class ACMESOS\*.ser .Note
We use *.class to ensure that we pick up the class files for any other procedures within the Java package that may have been prepared
Note
Issue the following statements from a DB2 Command Line Processor (CLP) session. Drop all procedures in the Java package:
DROP PROCEDURE ACMESNE.Add_customer ; DROP PROCEDURE ACMESNE.Add_order ;
Install the JAR file in the database. As a precaution, it is a good idea to drop it first to allow for re-runs:
CALL SQLJ.REMOVE_JAR('ACMESNS.ACMESNS'); CALL SQLJ.INSTALL_JAR('file:s:/sg245945/ACMESNS/ACMESNS.jar', 'ACMESNS.ACMESNS');
The first parameter of sqlj.remove_jar or sqlj.install_jar defines the location of the JAR file you created previously.
153
The second parameter provides an identifer that you will use when referring to the JAR file from within DB2 commands. Note that we have qualified this identifier DB2 uses this qualifier to determine which subdirectory it will copy the JAR file to. In our example, DB2 will register the JAR file and copy it to sqllib\function\jar\ACMEJOS\ACMESNS.jar. Now that DB2 knows about the JAR, we can define the stored procedure to DB2. Note that trying to define the procedure before the JAR has been registered will result in an error.
CREATE PROCEDURE ACMESNS.Add_customer ( IN IN_CUST_FIRSTNAME CHAR(20), IN IN_CUST_LASTNAME CHAR(20), IN IN_CUST_ADDRESS CHAR(30), OUT OUT_CUST_NO INT, OUT MARK CHAR(40), OUT MARK_ERROR_TEXT CHAR(200) ) EXTERNAL NAME 'ACMESNS.ACMESNS:ACMESNS.Add_customer.add_customer' RESULT SETS 0 LANGUAGE JAVA PARAMETER STYLE JAVA FENCED NO DBINFO NULL CALL MODIFIES SQL DATA;
Note
As we dropped all of the procedures in the Java package earlier, you must remember to recreate all of them here, not just the one you are working on! The stored procedure is now ready for execution.
7.3.2.2 Sample program preparation scripts Although not nearly as sophisticated as the examples we created for the OS/390 platform, we did create some scripts for performing this program preparation process for Windows NT and UNIX. These can be found in the appendix.
154
The JAR files register to the database via the sqlj ar routines. These JAR files then can be seen at sqllib\function\jar\<schema>. Never delete a JAR file manually. Always remove a JAR file using the sqlj.remove_jar routine.
Log in as schema owner
Within Command Center, the sqlj jar routines fail to recognize a set schema ACMES. You must connect at the beginning using the schema, as in 'connect to sample user ACMES'.
EXTERNAL NAME in create procedure statement
The EXTERNAL NAME clause in create procedure is case-sensitive. The first part of the name refers to the schema. In the following example, ACMES is the schema:
EXTERNAL NAME '"ACMES"."ACMESOS":ACMESOS.Add_customer.add_customer'
155
156
8.1 Deployment
One of the great advantages of developing stored procedures in Java is the fact that you are able to write and test them on one platform, then easily deploy them on another with few or no changes being required. Even if you are developing and deploying on a single platform, you will probably want separate development and production environments, and there are issues you need to be aware of and manage.
157
These two approaches are discussed in the following sections. In both cases, only the application specific aspects of the migration process are considered it has been assumed that the system setup (as described in 4.1, OS/390 system setup on page 57) has been addressed for both the source and target environments.
8.1.1.1 Source-centric migration The migration process using the source-centric approach is relatively simple, as shown in Figure 18.
Development Environment
Source
prog.JAVA
Production Environment
prog.JAVA
Source
Java Compiler
Java Compiler
Java Bytecode
prog.CLASS
prog.CLASS
Java Bytecode
HPJ Compiler
HPJ Compiler
External Link
JLL in PDSE
JLL in PDSE
External Link
DB2 Catalog
DDL
DDL
DB2 Catalog
In this situation, all that needs to be migrated is: The Java source code for the procedure. This can be accomplished using a simple FTP command to copy the source from the development HFS system to the production one. Note that Java source files should be FTPed in text format.
158
The DDL containing the CREATE PROCEDURE (for Version 6) or INSERT INTO SYSPROCEDURES (for Version 5) statements, plus any other DDL associated with the application. Assuming that the development and production environments use shared DASD, this can be accomplished with a simple IEBCOPY or a dedicated DB2 object management tool. , Once these two items have been moved, all that would be required is to re-perform the program preparation process within the production environment to create a new executable, and submit the necessary DDL to define the procedure to DB2.
SQLJ procedures
Figure 18 on page 158 shows a JDBC migration for simplicity. Migration of an SQLJ procedure would use an identical approach, with only the program preparation steps differing.
8.1.1.2 Executable-centric migration The migration process for the executable-centric migration approach is simpler still, as shown in Figure 19.
The following items must be copied from the source to the target environment: The HPJ compiled executable module. As this is a simple PDSE member, this can be accomplished using a utility such as IEBCOPY. The DDL containing the CREATE PROCEDURE (for Version 6) or INSERT INTO SYSPROCEDURES (for Version 5) statements, plus any other DDL associated with the application. Again, this can be accomplished with a simple IEBCOPY or a dedicated DB2 object management tool. , Once these items have been moved, all that would be required is the creation of a external link in the relevant HFS directory, to point to the newly moved PDSE executable. This can be accomplished using the USS ln command, as shown in the example below:
ln -e ACMESOS ACMESOS.jll
159
Development Environment
Source
prog.JAVA
Production Environment
Java Compiler
Java Bytecode
prog.CLASS
JLL in PDSE
JLL in PDSE
DB2 Catalog
DDL
DDL
DB2 Catalog
SQLJ procedures
Figure 19 shows a JDBC migration for simplicity. Migration of an SQLJ procedure would use a very similar approach, but the DBRMs generated by the db2profc process on the target system would also have to be moved to the target environment, and then bound to the production DB2 system.
160
8.1.2.1 Source-centric migration The source-centric migration uses the same concepts as shown previously. You can move the JDBC or SQLJ source files from the source environment to the target environment along with the necessary INSTALL_JAR and CREATE PROCEDURE statements (using FTP or some other utility), and then re-run the entire program preparation process on the target platform. 8.1.2.2 Executable-centric migration For JDBC procedures, you can migrate between environments by executing the following steps:
1. Move the JAR file containing the procedure code and the DDL defining the procedures to the target environment. 2. Define the JAR file to DB2 using the sqlj.install_jar statement. 3. Execute the CREATE PROCEDURE commands to define the procedures to DB2. The process for SQLJ is slightly more involved: 1. Move the JAR file containing the procedure code, the DDL defining the procedures and the serialized profile generated by the sqlj command to the target environment. 2. Define the JAR file to DB2 using the sqlj.install_jar statement. 3. Execute the CREATE PROCEDURE commands to define the procedures to DB2. 4. Execute db2profc in the target environment to create the necessary DB2 packages in the target DB2 system.
161
8.1.3.1 Changing Class.forName method and connection As there is no need for specific references to drivers or connections within stored procedures themselves, they can be ported with absolutely no amendments to the code. We proved this several times in the development of the examples within this book.
However, client code will have such references, so a couple of minor changes will be necessary. The Class.forName method is used to load a specific driver, which differs between UNIX/NT and OS/390 as follows: COM.ibm.db2os390.sqlj.jdbc.DB2SQLJDriver for OS/390 COM.ibm.db2.jdbc.app.DB2Driver for AIX and Windows NT Similarly, the connection URL used within JDBC clients differs as follows: jdbc:db2os390sqlj:DB21 for OS/390 Here, DB21 is the subsystem name. jdbc:db2:ACMES for AIX and Windows NT Here, ACMES is the database name.
8.1.3.2 Code translation There are some issues associated with the translation of certain ASCII and EBCDIC characters between the environments that will be well known to C and C++ programmers.
Detailed exploration of this issue is beyond the scope of this book, but here are a couple of practical pointers: Java code makes extensive use of square brackets ([ and ]). When a program is ported to the USS environment, these characters appear to be corrupted, as there is no EBCDIC equivalent for them (they appear as xAD and xBD respectively in USS). However, although this issue makes the code look somewhat messy within the USS environment, it has absolutely no impact on the execution of Java programs from within a JVM or HPJ environment. Good coding practices encourage the use of tabs in source code as a readability aid. Unfortunately, these are not always translated correctly and often appear as unprintable characters in USS. Again, this can be ignored, but it is a good idea to format code using hard space characters rather than tabs if you will be frequently porting between platforms.
162
8.2 Execution
The following sections describe some execution considerations, depending on which platform you are using.
Do this to refresh a Java stored procedure after changes have been made: 1. Re-prepare the stored procedure, as described in 7.2, OS/390 Java stored procedure preparation on page 119. 2. Issue a V WLM,APPLENV=xxx,REFRESH command on the system console to refresh the .jlls containing the code (where applenv is the WLM application environment name).
To refresh a Java stored procedure after changes have been made, do the following: 1. Re-prepare the stored procedure, as described in 7.3, NT / AIX Java stored procedure preparation on page 144. 2. Issue the following command to replace the JAR file:
call sqlj.replace_jar ('file:/aaakirk/Acme/Acme.jar','Acme');
163
164
165
166
which is the name of the plan DB2 uses when running the client (we used the default name of SQLJPLAN). For simplicity, we will refer to this plan as SQLJPLAN in the following paragraphs.
167
package collection called CLIENT, for example) and including this DB2 package collection in the DB2 package list for SQLJPLAN. In addition, you need to ensure that SQLJPLAN contains the necessary references to the DB2 packages for the stored procedure you will be invoking (if necessary). See 9.1.3, Stored procedure requirements on page 168 for details.
9.1.4 Summary
Table 10 contains a summary of the requirements for SQLJPLAN according to the type of client and stored procedure, if our recommendations concerning the use of COLLID are followed.
Table 10. Contents of SQLJPLAN by client and SP type using COLLID
168
Table 11 contains a summary of the requirements for SQLJPLAN according to the type of client and stored procedure, if COLLID is not explicitly supplied when defining the stored procedures. This approach is considerably more restrictive.
Table 11. Contents of SQLJPLAN by client and SP type not using COLLID
SQLJ Client
Collection (any name), containing the 4 packages produced by db2profc when preparing the SQLJ client. Same collection must also contain the 4 generic JDBC packages DSNJDBC1, DSNJDBC2, DSNJDBC3 and DSNJDBC4.
Collection (any name), containing the 4 packages produced by db2profc when preparing the SQLJ client. Same collection must also contain the 4 packages produced by db2profc when preparing the SQLJ stored procedure.
169
The last component of the connection string (DBZ1 in the example) should refer to the location name of the system you are trying to connect to (which is defined in the DDF Communication Record in the BSDS for that subsystem).
170
You may either specify a local location name (for a subsystem on the same OS/390 system as the client) or a remote one (for a subsystem on different OS/390 system). If you specify a remote system, that system must be defined in the communications database (CDB) for the local DB2. Refer to section 3.3 of DB2 Application Programming Guide and Reference for Java, SC26-9018-01 for further information.
9.2.1.2 The SQL CALL statement Due to an oddity in the drivers we used, we were forced to code all stored procedure names within CALL statements in upper case, as shown in the following JDBC and SQLJ examples:
procName = "ADD_CUSTOMER"; String sql = "CALL " + procName + "(?,?,?,?,?,?)"; #sql [myconn] { CALL ADD_CUSTOMER ( :IN lastname, :IN firstname, :IN address, :OUT cust_no, :OUT returned_mark, :OUT returned_mark_error_text) };
Attempts to use any lower case characters in the stored procedure name resulted in a -113 SQLCODE, indicating invalid characters in the prepared statement string. So, using the following statements:
procName = "add_customer"; String sql = "CALL " + procName + "(?,?,?,?,?,?)";
or:
#sql [myconn] { CALL add_customer ( :IN lastname, :IN firstname, :IN address, :OUT cust_no, :OUT returned_mark, :OUT returned_mark_error_text) };
171
Therefore, we recommend that you code all client calls using upper case names only.
COBOL clients
This issue did not appear to affect COBOL clients, and we able to successfully invoke Java stored procedures from within COBOL clients using a mixture of upper and lower case names.
5. Executing the call to the stored procedure 6. Retrieving the vales of the output parameters The code fragments shown in the following sections illustrate these steps.
9.2.2.1 Create SQL string First, a string must be defined containing the SQL CALL statement to invoke the stored procedure. The syntax of the CALL statement is normal, other than the fact that each reference to a parameter (normally represented by a host variable of some sort) is replaced by a ? character. In the example below, we are invoking a procedure called JS_ADD_CUSTOMER which has 6 parameters (3 input parameters and 3 output parameters).
procName = "JS_ADD_CUSTOMER"; String sql = "CALL " + procName + "(?,?,?,?,?,?)";
Note that the stored procedure name in the call is in upper case see 9.2.1.2, The SQL CALL statement on page 171.
172
9.2.2.2 Prepare string for execution Now that we have built the SQL string, it needs to be passed to DB2 for preparation. This is done using the prepareCall method, as shown in the example below:
callStmt = con.prepareCall(sql);
9.2.2.3 Set input parameters Next, we need to tell DB2 what values to pass for the input parameters when the stored procedure is invoked. The following lines of code allocate the three parameters passed to the client program to parameters 1, 2 and 3 of the stored procedure, using the argv function.
callStmt.setString (1, argv[0]); callStmt.setString (2, argv[1]); callStmt.setString (3, argv[2]); // firstname // lastname // address
Note that in common with many other aspects of Java, the argv function defines the first parameter as argv[0], even though the setString method refers to the first stored procedure parameter as number 1.
9.2.2.4 Register output parameters In order to access the output parameters after the call, they must be associated with the call statement using the registerOutParameter method. In the example below, we are defining parameters 4, 5 and 6 according to their respective data types:
callStmt.registerOutParameter (4, Types.INTEGER); callStmt.registerOutParameter (5, Types.CHAR); callStmt.registerOutParameter (6, Types.CHAR); // generated Cust no // mark // mark_error_text
9.2.2.5 Call stored procedure Now, we are ready to call the stored procedure using the simple syntax shown below:
callStmt.execute();
9.2.2.6 Retrieve output parameters Finally, we need to retrieve the previously registered output parameters and place them into host variables so that they are accessible to the client program:
int returned_cust_no = callStmt.getInt(4); String returned_mark = callStmt.getString(5); String returned_mark_error_text = callStmt.getString(6);
173
Note that the stored procedure name in the call is in upper case see 9.2.1.2, The SQL CALL statement on page 171.
174
Refer to the description of the CALL statement in the DB2 UDB for OS/390 SQL Reference, SC26-9014 for a full description.
additional material on page 347 for more information. The entire process is invoked from the USS command line using a syntax such as:
javacl sscall_Add_customer acmecl sscalac acmes
175
echo "Starting phase 1 - SQLJ translator" $pgm $pkg `whence sqlj` $pkg/$pgm.sqlj echo "Starting phase 2 - db2profc" db2profc -pgmname=$mem $pkg/$pgmuln.ser echo "Starting phase 3 - bind plans" # bindcl.rexx $mem $pkg $qual $spcol bindsp.rexx $mem $pkg $qual umem=`echo $mem | tr 'a-z' 'A-Z'` cat bind$SSID$umem.out | sed 's/ *$//' echo "Build for" $pgm $pkg "complete"
176
/* /* Note: In USS a ? is converted to a 2. arg MEM PKG qual spcol . if MEM = "?" | MEM = 2 then do do i = 1 while substr(sourceline(i),1,2) = "/*" say sourceline(i) end return 0 end
*/ */
if length(MEM) > 7 then do say "ERROR**** Member name can not be greater then 7 characters" say "Unable to create BIND statements" return 999 end x=0 /* */ /* Find the DB2SQLJPROPERTIES environment variable and set the */ /* rexx DB2SQLJPROPERTIES variable to it. */ /* If no DB2SQLJPROPERTIES variable set then default to */ /* db2sqljjdbc.properties in working directory */ /* */ do I = 1 to __environment.0 if substr(__environment.i,1,17) = 'DB2SQLJPROPERTIES' then do DB2SQLJPROPERTIES = substr(__environment.i,19,length(__environment.1)-18) x=1 end if substr(__environment.i,1,5) = 'TERM=' then do termenv = substr(__environment.i,6,length(__environment.i)-5) end end if x=0 then DB2SQLJPROPERTIES = 'db2sqljjdbc.properties' /* Pick up the DB2 subsystem ID and DBRMLIB to use for the Binds /* db2sqljplanname /* from the DB2SQLJPROPERTIES file. address syscall "readfile (DB2SQLJPROPERTIES) file." if retval < 0 then do say "ERROR*** The" DB2SQLJPROPERTIES "file does not exist" say "Unable to create BIND statements" return 999 end */ */ */
177
else do i = 1 to file.0 if substr(file.i,8,4) = 'SSID' then ssid = substr(file.i,13,length(file.i)-12) if substr(file.i,8,7) = 'DBRMLIB' then dbrmlib = substr(file.i,16,length(file.i)-15) if substr(file.i,8,8) = 'PLANNAME' then planname = substr(file.i,17,length(file.i)-16) end /* /* Build the BIND statements and save them to the stack. /* say say say say say '****** NOTE: ******' 'If this JAVA client calls a JAVA SP, make sure the SP's' 'collection along with this clients collection' PKG||'.* is in PLAN' planname 'and rebind this PLAN' '*******************' */ */ */
b.0 = 5 b.1 ="BIND PACKAGE("PKG") MEMBER("MEM"1) ACT(REP) (BIND) LIBRARY('"DBRMLIB"') QUALIFIER("QUAL")" b.2 ="BIND PACKAGE("PKG") MEMBER("MEM"2) ACT(REP) (BIND) LIBRARY('"DBRMLIB"') QUALIFIER("QUAL")" b.3 ="BIND PACKAGE("PKG") MEMBER("MEM"3) ACT(REP) (BIND) LIBRARY('"DBRMLIB"') QUALIFIER("QUAL")" b.4 ="BIND PACKAGE("PKG") MEMBER("MEM"4) ACT(REP) (BIND) LIBRARY('"DBRMLIB"') QUALIFIER("QUAL")" b.5 ="END" input = "BIND"||ssid||"INPUT" address syscall "writefile ("||input||") 777 b." if retval=-1 then do "error*** writing bind input file" input return 999 end address syscall "getcwd cwd" if retval=-1 then do "error*** getting current directory to save" return 999 end
*/ */ */
178
if termenv = 'vt100' then /* telnet "tso -t oebind" ssid cwd input mem else "tso oebind" ssid cwd input mem
*/
/* /* Remove input file with BIND statements in /* "rm" input /* /* make sure the directory exist for ser files in /u/"ssid"/ser/ /* address syscall "chdir /u/"ssid"/ser/"pkg if retval=-1 then do "chdir /u/"ssid"/ser/" if retval=-1 then do say "error*** getting directory /u/"ssid"/ser" return 999 end "mkdir" pkg 777 if retval=-1 then do say "error*** making directory /u/"ssid"/ser/"pkg return 999 end end /* reset current directory "chdir" cwd if retval=-1 then do "error*** reseting directory" cwd "to current" return 999 end RETURN
*/ */ */
*/ */ */
*/
179
180
DB2 also copies rows in SYSIBM.SYSPROCEDURES into table SYSIBM.SYSPARMS and propagates information from the PARMLIST column of SYSIBM.SYSROCEDURES into SYSIBM.SYSROUTINES and SYSIBM.SYSPARMS.
181
Stored procedures migrated from Version 5 do not have an owner, because they were not created with the CREATE PROCEDURE statement. This means that the authorization rules don't change from V5. If you subsequently DROP and CREATE the stored procedure, now it has an OWNER, so the caller must have EXECUTE ON PROCEDURE authority to invoke it. DB2 authorization treats these migrated procedures differently than procedures created with CREATE PROCEDURE. The authorization for migrated procedures is unchanged. Migrated stored procedures have SCHEMA set to SYSPROC. This means that to invoke them, SYSPROC has to be in the concatenation of schemes that DB2 uses in resolution. The catalog table SYSIBM.SYSPROCEDURES is not used in Version 6 to define stored procedures to DB2. The SYSCAT.PROCEDURES view of catalog table SYSIBM.SYSPROCEDURES is not used to list the stored procedures registered in DB2. Although these tables are no longer used in Version 6, DB2 does not drop them during migration because they are needed for fallback and data sharing coexistence. For more information, refer to DB2 Application Programming and SQL Guide, SC26-9004.
182
Note
Remember to check that you have removed all data set passwords, any views on SYSIBM.SYSCOLDIST and SYSIBM.SYSCOLDISTSTATS, and convert all indexes to type 2. The sample database DSN8 is created with some type 1 indexes and has passwords on its data sets. Remember to change the passwords by following these steps: 1. Stop the database, using the -STOP DATABASE command. 2. Remove the password on all associated data sets by using VSAM access method services ALTER data.set NULLIFY(MASTERPW) command. 3. Change the password, using the DSETPASS clause of the ALTER TABLESPACE statement or the ALTER INDEX statement to a space. You must use the same password for all data sets for the same table space or index space. 4. Start the database again, using the -START DATABASE command.
183
184
185
186
Some of the differences between private protocol and DRDA are listed below. These differences still exist in Version 6.
187
Private protocol always uses dynamic SQL. There is no way for you to specify static SQL when using private protocol. With DRDA, you can use static and dynamic SQL. Private protocol has restrictions in terms of the SQL that can be executed on the remote server. You are basically limited to DML SQL statements. With DRDA, in addition to DML, you can execute DCL and DDL statements at the remote server. Private protocol limits the server type to DB2 on the MVS platform. With DRDA, you can send/receive SQL statements to any platform that supports DRDA. Private protocol can use only SNA connections. With DB2 for OS/390 Version 5 and higher, DRDA can use SNA and TCP/IP connections. With DB2 Version 6, you have support for UDTs and LOBs. This support is only available if the underlying protocol is DRDA. LOBs can be accessed from a client only when using the DRDA protocol. Because a typical use of LOBs is on some type of workstation, DRDA is enhanced to allow a LOB value to be sent across the network. In this way, LOB values and LOB locators can be passed back and forth between a DRDA AR and AS. Both DB2 on the workstation and DB2 for OS/390 provide support for these DRDA enhancements, allowing a DB2 application to access and manipulate LOB values anywhere in the DRDA network. DB2 on the workstation, however, supports the file reference variables whereby a LOB value can be selected or inserted without the requirement for a contiguous piece of application storage to contain it. When a DRDA client sees a reference to a file reference variable in the VALUES clause of an INSERT statement or the SET clause of an UPDATE statement the DRDA client will read the files contents on the wire as a single LOB value. Similarly, when a DRDA client sees a reference to a file reference variable in the INTO clause of a SELECT or FETCH statement, the DRDA client will place the LOB value it receives from the server into the specified file. If you try to pass UDTs or LOBs using private protocol, the statement fails, and a -728 SQLCODE is returned. Stored procedures are supported only when using DRDA. See Table 12.
188
Category
Use of static/dynamic SQL SQL Type Remote server support Protocol support Support for Object Relational extensions (such as UDTs and LOBs) Support for stored procedures
Private Protocol
Dynamic only DML only DB2 for OS/390 only SNA only No
DRDA
Dynamic and static DML, DCL and DDL Any DRDA AS SNA and TCP/IP Yes
No
Yes
189
So, besides the advantage of minimal impact to exiting programs, the new DBPROTOCOL option produces another major advantage; coding is simplified because there is less of it. Also, if you use alias for remote tables, you achieve location transparency; if a table has to be moved from one location to the other, you do not have to change your application. It is enough to change the alias to point to another location and rebind/copy the package to that location.
190
191
DRDA
LOC1
1 - Check CURRENT SERVER 2 - CONNECT / SET CONNECTION TO LOC1 3 - SET CONNECTION back 4 - LOC1 is DORMANT
Following are the details of the steps shown in Figure 23: 1. DB2 first checks the value of the CURRENT SERVER special register. 2. DB2 will implicitly issue a connect or a SET CONNECTION statement to the remote location. If the program was precompiled with SQLRULES(STD) and the connection to the remote location was already established, DB2 issues the SET CONNECTION statement. Otherwise, DB2 issues the CONNECT statement. 3. Once the statement coded in the application program finishes execution, DB2 issues the SET CONNECTION statement to the previously saved value of the CURRENT SERVER special register. 4. The remote site will remain in the connection set (to maximize performance), but will be marked as a DORMANT connection. The connection management is handled automatically by DB2. There is no need for the application programmer to be concerned about SQLRULES (DB2 or STD). DB2 knows when to do a SET CONNECTION or a CONNECT. When this conversion is accomplished, the concern about having a private connection and a DRDA connection to the same location (SQLCODE -842) is eliminated.
192
Similarly, the statements ALLOCATE CURSOR, DESCRIBE CURSOR, FETCH cursor, and CLOSE cursor require that the application be connected to the site where the stored procedures declaring the cursor are executed. Note that the FETCH and CLOSE cursor statements also apply when a stored procedure is not being used.
193
These statements, in their syntax, contain result set locators which uniquely identify a cursor. So, although a three-part name is not contained in these statements, there is no ambiguity as to which cursor is being referenced. Therefore, the restriction about site connection has been removed for the ALLOCATE CURSOR and DESCRIBE CURSOR statements, regardless of the BIND option.
Note
When using DESCRIBE PROCEDURE and other SQL statements for accessing result sets, you should ensure that the procedure name is specified exactly as it is on the CALL statement (including the number of qualifiers used for the procedure name). See the description of the DESCRIBE PROCEDURE statement in the DB2 SQL Reference, SC26-9014 for further details.
11.1.7 Hopping
This section describes the possible hopping (three-part name) usage scenarios, which are summarized in Figure 24.
194
11.1.7.1 DRDA and private protocol The maximum level of hopping is two hops, if one of the protocols involved is private. For example, if you use a three-part name on SITE1, that refers to SITE2, and in SITE 2, this is an alias for an object residing in SITE 3. This object must be a local view or table in SITE 3; it cannot be an alias for a remote table.
In this scenario, the DRDA protocol is used in the connection between SITE 1 and SITE 2, and the private protocol is used in the connection between SITE 2 and SITE 3. The private protocol cannot be used in both.
11.1.7.2 Only DRDA protocol If you use only DRDA, there is no limit on the number of sites that you can hop, as long as there are packages at the target site. As a consequence, a middle site (SITE 2 or SITE 3 in the diagram) cannot tell how many levels have been nested. 11.1.7.3 Loop back Consider the following scenario:
On SITE 1: rtable is synonym of site2.user1.table1 On SITE 2: table1 is synonym of site1.user1.table1
In this scenario, the loop back would be possible. However, there are some scenarios where DB2 detects and avoids loop back connections. For example:
On SITE 1: rtable is synonym of site2.user1.rtable On SITE 2: rtable is synonym of site1.user1.rtable
DB2 does not allow another hop on a connection that matches the LUWID of another existing DRDA thread. So, if SITE 1 has a thread to SITE 2, and a thread from SITE 2, the incoming thread from SITE 2 will be marked so that no further hops are performed. Another example is:
On SITE 1: rtable is synonym of site2.user1.rtable On SITE 2: rtable is synonym of site3.user1.rtable On SITE 3: rtable is synonym of site1.user1.rtable
For the example above, a -904 SQLCODE with reason code 00D31052 is returned.
195
11.1.8 Advantages
Following are some more advantages of using this new enhancement: Better performance at execution time, because binding occurs when the package is bound, not during program execution. Better performance due to the fact that static statement information is not destroyed at COMMIT time. If a cursor is not specified WITH HOLD, a COMMIT will cause DB2 to discard all the statement information. If the statement is dynamic, subsequent re-execution causes another PREPARE (or REBIND) of the statement to take place.
Note
It is important to emphasize that the options available for Version 5 for truly dynamic statements, such as KEEPDYNAMIC and statement caching, also apply to Version 6. Allows access to DRDA servers that are not DB2 for OS/390 systems through the use of a three-part name (or alias).
196
Permits hopping to non-DB2 for OS/390 systems (see 11.1.7, Hopping on page 194). Access to new DB2 functions such as stored procedures, which were added only to DRDA processing. Take advantage of DRDA DDF enhancements, such as the chained PREPARE/DESCRIBE/ pre-OPEN performance enhancements.
11.1.9 Impacts
There are some minor impacts associated with conversion to DRDA three-part table names. These include: No support for continuous block fetch. Although Version 6 provides for similar function, the OPTIMIZE FOR clause is specified. See 11.2, DRDA query block size on page 198 for details. Loop back is not allowed. See 11.1.7.3, Loop back on page 195 for details. The current restriction with CREATE, ALTER, DROP, GRANT, REVOKE, COMMENT ON, LABEL ON, RENAME is not removed. These statements (whether or not three-part name were used in coding) are excluded from private protocol. This restriction remains with the new three-part name DRDA protocol implementation. In general, only the same statements as for private protocol (DML) are allowed when using DRDA with three-part names. In addition, most SET local statements are propagated to the remote sites through the new DRDA codepoint. Only package authorization information is passed to non OS/390 DRDA servers. Authorization to a DB2 for OS/390 server (hop site) should be identical to the authorization as it currently exists. Once a server other than DB2 for OS/390 is encountered, however, only the package information will flow to that site or to downstream sites. For example, between two DB2 for OS/390 systems, the plan authorization is passed. The above is valid for DRDA and private and will continue be like that. Once DB2 hops to a non-DB2 for OS/390 system, such as DB2 UDB on the workstation, only package authorization is passed.
197
198
With DB2 UDB for OS/390 Version 6, OPTIMIZE FOR n ROWS is also used when the result set that must be returned to the client exceeds the negotiated block size. If a DRDA client (or a stored procedure at a server) declares the cursor with the OPTIMIZE FOR n ROWS clause, the client can request extra blocks from the server, who may then send up to 32 K DRDA query blocks in one network transmission. Additionally, network I/O and SQL operations can be performed in parallel when OPTIMIZE FOR n ROWS is specified and the SQL consists of FETCH requests against the OPTIMIZE FOR n ROWS query. For example, the DRDA requester can issue an asynchronous receive operation for the next DRDA query block, while the SQL operation is processing rows from the current DRDA query block (see Figure 26).
CLIENT
OPTIMIZE FOR 10000000 ROWS
PROCESS ROWS
SYNCHRONOUS
ASYNCHRONOUS
BLOCK 1 BLOCK 2
The first block is sent synchronously. The remaining blocks are sent asynchronously. The minimum between EXTRA BLOCK SRV and EXTRA BLOCK REQ is negotiated. DRDA allows the negotiation to be conducted either at connection or at statement execution time. DB2 UDB for OS/390 Version 6 as a requester only does this at connection time, while as a server it supports negotiation either at connection or statement execution time. This allows DRDA applications to gain many of the benefits currently available in the DB2s private protocol block fetch function.
199
Y
SEND
N
MINIMUM EXT REQ EXT SRV
END
N
More rows?
Y
SEND on new client request
200
201
CLIENT
..OPTIMIZE FOR 1000 ROW S; OPEN C1;
SERVER
CURSOR IS OPENED Query block with 100 rows returned Query block with 100 rows returned Query Query Query Query Query Query block block block block block block with with with with with with 100 100 100 100 100 100 rows rows rows rows rows rows returned returned returned returned returned returned
Query block with 100 rows returned Query block with 100 rows returned Server processes INSERT statement
202
O S/2
Using this DB2 command, you can make DDLs or other changes without breaking the connections to your DDF clients. This feature is very important and helpful to improve the overall server availability for e-business and client/server applications. When the DB2 command, -STOP DDF MODE(SUSPEND) is issued, it has the following effects: Holds INACTIVE threads in INACTIVE state, until a -START DDF command is issued. Terminates all DDF pool threads. Prevents the initiation of all inbound DDF work. Waits for ACTIVE threads to reach the INACTIVE state. After completion, no DDF user will hold locks on any DB2 object.
203
MODE(SUSPEND) is intended to be used at a DB2 for OS/390 DRDA server, especially one that has DDF THREADS = INACTIVE when there are locking conflicts between DDL and client access to the data. This function will quiesce DDF activity and terminate the DDF pool of data base access threads used to service the client requests, thus making the database available for maintenance, including DDL. The fact that MODE(SUSPEND) completes successfully does not guarantee that database resources are not still held if there is any activity other than inbound DDF processing being performed. It may be necessary to use -CANCEL THREAD to terminate other processing that is being performed in order to free the database resources. See Table 13 for a description of the actions taken when a START DDF or a STOP (DB2 or DDF) command is issued depending on the current DDF state.
Table 13. START / STOP command versus DDF status
START DDF
Error Error Error OK (start) OK (resume) OK (resume)
204
If CANCEL or WAIT are not specified, then this command waits for all active DDF database access threads to terminate. If this is not the desired affect, then how long the command will wait and what action will be taken after a specified time period can be controlled by the CANCEL and WAIT optional keywords. CANCEL If suspend processing has not completed successfully in n seconds, cancel all active DDF database access threads. CANCEL has a valid range of 0-9999 seconds. WAIT If suspend processing has not completed successfully in n seconds, resume DDF processing again. WAIT has a valid range of 0-9999 seconds. The affect of the WAIT option is the same as if a -START DDF command was issued after n seconds if the suspend process has not completed successfully during that period.
Note:
See Appendix A, New messages and error codes on page 285 for new messages and error codes provided to support this feature.
205
With BI, there are many cases when you need to pull data out of the database, process the data, and then use it for subsequent join operations. With customers moving their application from Sybase, Oracle, or SQL Server to DB2, we found out that those products had a particular style that was different from that expected by our global temporary table support. DB2 UDB for OS/390 Version 6 provides support for declared global temporary tables, which has the same style, to provide easy porting from Oracle, Sybase, and SQL Server, as well as providing functions that simplify its use for BI. The main enhancements for declared global temporary tables are these: Support for indexes This will be helpful when you use temporary tables for join operations. Without indexes, DB2 would have to do a table space scan. When the create index statement is issued, DB2 records that information in memory; there is no catalog activity. Tables do not have to be predefined in the DB2 catalog Basically, in the middle of your program you just have to issue a new statement DECLARE GLOBAL TEMPORARY TABLE, which is a dynamic SQL statement. It does not go out to the catalog and change it. When you issue the statement, DB2 does this in memory, so only your execution can see it. The temporary table description is not shared across application processes. Each application process that uses the declare global temporary table can define the same qualified table name, with a possibly unique description for the temporary table. In addition, when issuing the DECLARE GLOBAL TEMPORARY TABLE statement, the columns definitions can be implicitly defined as a result of a SELECT statement. This means that you can populate your temporary table through the same one SQL statement used to define its columns. Full support for delete and update operations Declared global temporary tables are like regular tables. You can delete the rows, update the rows. This was not supported with Global Temporary Tables; only insert and massive delete were supported. No catalog contention at runtime This is very important for BI solutions. Using global temporary tables for the intermediate tables, you will not have the catalog contention that you would have with regular create of a real table, where operations such as creating indexes, huge volume of applications running in parallel update the catalog simultaneously.
206
We recommend that you do not use the word SESSION as one of your schema names.
207
Workfiles Global temporary tables do not use the regular workfiles (DSNDB07). This means that they will not compete with your regular workload. Segmented table spaces in a special temporary database are used as the space for the table. Authorization You do not need any special authorization privilege to create or declare a temporary table. Every user automatically has the privilege to create these on their own.
11.6 Savepoints
A savepoint represents the state of data and schema at a particular point in time. An application may set named savepoints within a transaction, then as dictated by application logic, roll back subsequent data and schema changes without affecting the overall outcome of the transaction. The scope of a savepoint is the DBMS on which it is set. Savepoints enable the coding of contingency or what-if logic and could be useful in the following scenarios. Programs with sophisticated error recovery. To undo stored procedure updates when an error is detected. With no savepoints taken in the calling application, a rollback in a stored procedure will roll back the entire unit of recovery, including all work done by the caller prior to the stored procedure being invoked. A savepoint taken immediately prior to the stored procedure call could be used to allow the stored procedure to rollback in the event of a problem being encountered, without also undoing any of the changes made by the caller within the same unit of work. You can set savepoints by using the SAVEPOINT syntax documented in the DB2 UDB for OS/390 Version 6 SQL Reference, SC26-9014-01. The savepoint name can be up to 128 characters, and we suggest that you use a meaningful name. You can use the UNIQUE OPTION to assert that the savepoint name will not be reused within the transaction. If you omit the UNIQUE option and reuse the savepoint name, the old savepoint will be destroyed. Note that this is different from using the RELEASE SAVEPOINT statement, which will release all savepoints with that name.
208
When you issue the SAVEPOINT statement, DB2 writes an external savepoint log record. Savepoints that you create are often termed external (as opposed to internal) because DB2 already uses internal savepoints as its mechanism for backing out specific units of recovery. Internal savepoints are used by DB2 only, cannot be accessed through an application, and may be liable to change in future releases or as a result of applying maintenance. In contrast, you have full control over external savepoints. To roll back to an external savepoint you have set, use the ROLLBACK TO SAVEPOINT svptname statement. This will back out all data and schema changes that were made after the savepoint. The following will not be backed out: Any updates outside of the local DBMS (such as remote DB2s, VSAM, CICS, IMS) Changes to created temporary tables (however, changes to declared temporary tables are backed out) The opening and closing of cursors Changes in cursor positioning The acquisition and release of locks The caching of the rolled back statements
209
DB2 does not restrict the use of aliases and three-part names to connect to a remote site when there are outstanding savepoints at the remote site. However, we do not recommend this; because you will not necessarily know, when you access a three-part name, whether it is local or remote. Also, the location of the data may change without knowledge of the application. It follows, therefore, that the outcome of a rollback to savepoint will be uncertain for the application. We recommend that you code the RELEASE SAVEPOINT savepoint name statement to release savepoints that are no longer required for clarity and to reenable the operation of SQL that resolves to remote locations.
This solution has the potential to cause serious performance bottlenecks, due to lock waits on the 1-row table. These are exacerbated in a data sharing environment.
If you intend to unload tables containing ID columns we recommend that you also look at PQ38493. See 11.7.4, Utility issues on page 218 for details.
210
The remainder of this chapter describes DB2s implementation of this important new feature, which can greatly reduce the amount of work required to port some applications from other vendors database products to DB2 UDB. Unless otherwise specified, all references are to the DB2 for OS/390 product. A section at the end of this chapter deals with the major implementation differences between the OS/390 and UNIX, Windows NT, and OS/2 products.
11.7.1 Overview
DB2s implementation of this feature fulfills the following design objectives: Guarantee uniqueness, both within an individual subsystem and across a data sharing group (if applicable). Provide the ability for an application to either specify an explicit value for an identity column during INSERT, or have DB2 generate the value if required4 . Minimize the resource usage and elapsed time overheads required to generate the value in a highly concurrent environment. Provide recoverability in the event of a DB2 system failure by reconstructing the last value before the outage, thereby ensuring that uniqueness is maintained. At the time a table is created, you may specify a single numeric column within the table as being an identity column. Included in this specification is the columns start value and increment/decrement value, and whether DB2 is to allow explicit values to be supplied.
211
+----------------------------------------------------------+ | COLUMN-DEFINITION: | | |--column-name--data-type--.----------------.----------| | | '-column-options-' | | COLUMN-OPTIONS: | | <-----------------------------------------------< | | |---.---------------------------------------------.----| | | |-NOT NULL------------------------------------| | | |-.-UNIQUE------.-----------------------------| | | | '-PRIMARY KEY-' | | | |-FIELDPROC--program-name--.----------------.-| | | | | <-,------< | | | | | '-(--constant--)-' | | | |-references-clause---------------------------| | | |-check-constraint----------------------------| | | '-generated-column-spec-----------------------' | | GENERATED-COLUMN-SPEC: | | |-+--------------------------------------------------+-| | | | +-WITH-+ | | | |-'------'--DEFAULT--.----------------.------------| | | | '-default-clause-' | | | | | | | +-GENERATED--.-ALWAYS-----.--.------------------.--+ | | '-BY DEFAULT-' '-as-identity-spec-' | | AS-IDENTITY-SPEC: | | |-AS IDENTITY-+---------------------------------------+-|| | | <-,-----------------------------< | | | | +---1----+ | | | | | | | | | | | +-(---+-START WITH--+-nconst-+---+--+-)-+ | | | | | | | +---1----+ | | | | | | | | | |-INCREMENT BY--+-nconst-+-+ | | | | | | | +-CACHE 20------+ | | | | | | | | | +-+-NO CACHE------+--------+ | | | | | | +-CACHE-integer-+ | | LIKE-clause (CREATE TABLE) | | |-----LIKE--+--table-name--+------------------------>> | | | | | | +--view-name---+ | | >>--+---------------------------------------------+---| | | | | |
212
GENERATED
Specifies that DB2 generates values for the column. You must specify GENERATED if the column is to be considered an identity column, or if the data type of the column is a ROWID (or a distinct type that is based on a ROWID).
ALWAYS
Specifies that DB2 always generates a value for the column when a row is inserted into the table.
BY DEFAULT
Specifies that DB2 generates a value for the column when a row is inserted into the table unless a value is specified.
BY DEFAULT is the recommended value only when you are using data propagation.
AS IDENTITY
Specifies that the column is an identity column for the table. A table can have only one identity column. AS IDENTITY can be specified only if the data type for the column is an exact numeric type with a scale of zero (SMALLINT, INTEGER, DECIMAL with a scale of zero, or a distinct type based on one of these types). An identity column is implicitly NOT NULL.
START WITH numeric-constant
Specifies the first value for the identity column. The value can be a positive or negative value that could be assigned to the column, as long as there are no non-zero digits to the right of the decimal point. The default is 1.
213
INCREMENT BY numeric-constant
Specifies the interval between consecutive values of the identity column. This value can be any positive or negative value that is not 0, does not exceed the value of a large integer constant, and could be assigned to this column, as long as there are no non-zero digits to the right of the decimal point. The default is 1. If the value is positive, the sequence of values for the identity column ascends. If the value is negative, the sequence of values for the identity column descends.
CACHE or NO CACHE
Specifies whether to keep some preallocated values in memory. Preallocating and storing values in the cache improves performance for inserting rows into a table that has an identity column.
CACHE integer
Specifies the number of values of the identity column sequence that DB2 preallocates and keeps in memory. The minimum value that can be specified is 2, and the maximum is the largest value that can be represented as an integer. The default is 20. During a system failure, all cached identity column values that are yet to be assigned are lost and, thus, will never be used. Therefore, the value specified for CACHE also represents the maximum number of values for the identity column that could be lost during a system failure. In a data sharing environment, each member gets its own range of <integer> consecutive values to assign.
NO CACHE
Specifies that the columns of the table have exactly the same name and description as the columns of the identified table or view. However, for an identity column, the new table inherits only the data type of the identity column; none of the other column attributes are inherited unless the new INCLUDING IDENTITY clause is specified.
214
Specifies that the new table inherits all of the column attributes of the identity column. If the table identified by LIKE does not have an identity column, the INCLUDING IDENTITY clause is ignored. If the identified object of LIKE is a view, INCLUDING IDENTITY COLUMN ATTRIBUTES cannot be specified.
11.7.2.2 Adding an identity column to an existing table The ALTER TABLE ADD COLUMN statement can be used to add an ID column to an existing table. Unless the table is empty, DB2 will place it in reorg pending status (if the table is partitioned, then all partitions are reorg pending).
Running REORG will materialize the ID column values for all rows in the table (again, if the table is partitioned, REORG must be run against the entire table space and not just one partition). The order in which DB2 will allocate the ID column values is system determined.
11.7.2.3 Altering an identity column To alter the attributes of an existing identity column, you must drop and recreate the table (using your normal procedures for conserving the table data, indexes, authorities, and other dependent objects).
When re-creating the table, you should ensure that the START WITH value that is specified is set to the next value that you want DB2 to generate after the table is reloaded with data. See 11.7.2.4, Copying tables between subsystems on page 216 for an SQL statement that can be used to determine this. Also, as you will be using the LOAD utility to reload the table data after it is recreated, you must specify GENERATED BY DEFAULT so that LOAD is allowed to reuse the previously allocated identity column values. Once this is done, there is no way to go back to GENERATED ALWAYS.
Note
See 11.7.4, Utility issues on page 218 for further considerations when unloading and loading tables containing identity columns.
215
Note
Under very specific circumstances, it may be possible to retain the GENERATED ALWAYS attribute by doing the following: 1. Make the table unavailable to prevent further INSERT/LOAD activity. 2. Unload the table in ID column order. 3. Drop and re-create the table as required, specifying GENERATED ALWAYS for the ID column and the original value for the START WITH attribute. 4. LOAD the data back into the table, excluding the unloaded ID column values from load operation, and thereby allowing DB2 to regenerate them during the load operation. However, if you want to ensure that the ID column key values remain the same (essential if the ID column is a primary key, and referenced as a foreign key in another table) you need to be very careful. Be absolutely sure that: No gaps appear in the ID column sequence (for example, if the increment is 1 and the start value is 1, the table must contain rows with values 1, 2, 3, 4, and so on, with no gaps in the series). Note that it is very likely that gaps will exist, for example, due to caching in a data sharing environment, or rollbacks of failed units of work. No one else is able to LOAD or INSERT into the table in between the time you re-create it and the time the LOAD operation is conducted.
11.7.2.4 Copying tables between subsystems Special consideration has to be given to avoiding overlaps when copying tables with ID columns between subsystems.
Consider the following procedure: 1. Stop the table space containing the table on the source subsystem, to stop any new rows from being inserted. 2. Run the following catalog query to determine the start value and increment for the CREATE TABLE statement on the target system:
SELECT B.DCREATOR, B.DNAME, B.DCOLNAME, A.INCREMENT+A.MAXASSIGNEDVAL AS NEW_START_VALUE, A.INCREMENT
216
FROM
WHERE AND
SYSIBM.SYSSEQUENCES A INNER JOIN SYSIBM.SYSSEQUENCESDEP B ON A.SEQUENCEID = B.BSEQUENCEID B.DCREATOR = 'ACMEE' B.DNAME = 'CUSTOMER';
In these statements, the values for B.DCREATOR and B.DNAME predicates are replaced with your own table creator and table name. 3. Create the table on the target subsystem, using the start and increment values determined from the previous step. 4. Stop the table space on the target system, to prevent rows from being inserted until it is populated. 5. Copy the data from the source to the target (using DSN1COPY or similar) 6. Start the table on the target subsystem (and also the source if required).
For example, if table CUSTOMER has three columns: CUST_NO, CUST_FIRSTNAME and CUST_LASTNAME, where CUST_NO is a GENERATED ALWAYS ID column, an insert could be performed with either of the two methods shown below:
INSERT INTO CUSTOMER (CUST_FIRSTNAME, CUST_LASTNAME) VALUES (John, Doe); INSERT INTO CUSTOMER (CUST_NO, CUST_FIRSTNAME, CUST_LASTNAME) VALUES (DEFAULT, John, Doe);
For GENERATED BY DEFAULT ID columns, you may either use the above syntax to allow DB2 to generate the value, or explicitly specify a value in the normal way. As previously noted, DB2 does not do any checking for explicitly
217
supplied ID column values, so you should consider defining a unique index on the column if you wish to enforce uniqueness.
11.7.3.2 Update UPDATE statements are not allowed against GENERATED ALWAYS ID columns (SQLSTATE 42808, SQLCODE -151).
If an ID column is defined as GENERATED BY DEFAULT, updates are allowed. However, as for INSERT operations, DB2 will not do any validation of the updated column value.
APAR PQ38493 introduces additional features to support the unload and load of identity columns. With the APAR applied, DB2 will include a dummy field called DSN_IDENTITY to represent the identity column within the LOAD statement produced by REORG UNLOAD EXTERNAL and REORG DISCARD. A new option called IGNOREFIELDS will also be present in the LOAD deck. When loading into a table with a GENERATED ALWAYS identity column, the IGNOREFIELDS option will cause LOAD to ignore the DSN_IDENTITY field, allowing LOAD to generate its own values. To load the data into a table with a GENERATED BY DEFAULT identity column (or no identity column) the IGNOREFIELDS option should be removed from the LOAD deck and the DSN_IDENTITY field renamed to point to the corresponding column in the target table. The unloaded data values will then be used. If the APAR has not been applied, the utility will omit field specifications for GENERATED ALWAYS ID columns.
218
Some complications arise when a table has been altered to add an ID column and the table is part of a referential set. If that table is recovered to a point in time after the ALTER but before the REORG, it is possible for the table space to be in both check pending and reorg pending state. To resolve this situation, you can now run REORG with both CHECKP and REORP states set. After completion, CHECKP will still be set, but this can be removed by running CHECK DATA as usual.
11.7.4.2 LOAD Running the LOAD utility against a table containing ID columns will result in the same rules being applied as for INSERT processing when generating data values.
Where the ID column has been defined as GENERATED ALWAYS, DB2 will generate a value for that column as the row is loaded. You may not explicitly include ID columns in the field specification. When loading data produced from a REORG UNLOAD external operation with PQ38493 applied you can use the new IGNOREFIELDS keyword to instruct DB2 to ignore any identity column fields in the unloaded data (see description in previous section). For GENERATED BY DEFAULT, you may include the ID column in the field specification. If you do so, the supplied value in the input data file will be used. Otherwise, the value is generated by DB2. The DEFAULTIF clause can be used to get DB2 to generate a value if required. When loading data produced from a REORG UNLOAD external operation with PQ38493 applied you should remove the IGNOREFIELDS keyword to instruct DB2 to use the unloaded values (see description in previous section). For partitioned tables, you may not run the load against a single partition via LOAD INTO TABLE PART if the ID column in part of the partitioning key. If a table space has been placed in reorg pending state by using ALTER TABLE ADD COLUMN to add an ID column to a populated table, you may use LOAD REPLACE to reset the status if you wish to reload the table rather than reorganize it.
219
11.7.4.3 RECOVER As mentioned in the note above, some complications can arise when using RECOVER to restore a table space to an earlier point in time when an ID column has been added.
If the table space is recovered to a point in time between the ALTER TABLE and the subsequent REORG, the REORP status will be set upon completion of the RECOVER. Some issues can also arise regarding the highest generated value following a recovery. If a table is recovered to a prior point in time, DB2 will not reset the highest generated value for the table. This can lead to large gaps in the series of generated values, which may cause problems for some types of applications. For example, a table has an ID column defined as START WITH 1 INCREMENT BY 1, and has 1000 rows in it. The table is then recovered to an earlier point in time, where only 500 rows existed. The next INSERT operation generates a value of 1001, as DB2 will continue to use the previously generated high value, and there will be a gap in the generated values between 501 and 999.
5 And in a data sharing environment, explicitly locking the table also introduces the possibility of an exclusive retained
220
There may be gaps in the generated column values. This can happen if a transaction is rolled back after allocating a new value, or (in a data sharing environment) if a subsystem fails and had not used all of the numbers reserved in its cache. In a data sharing environment with caching enabled, identity column values may not be inserted into the table in numeric order, as each member will allocate the next unused value in its own cache. For example, if member DB2A caches numbers 1-20 and member DB2B caches 21-40, it is possible that an INSERT from DB2B will use a value of 26, to be followed by an INSERT from DB2A with a value of 14. Global temporary tables may not contain identity columns.
SYSIBM.SYSSEQUENCES contains one row for each ID column, and records attributes such as the internal DB2 name for the column (SEQUENCEID), its defined start (START) and increment (INCREMENT) values, and the currently used high value (MAXASSIGNEDVAL). SYSIBM.SYSSEQUENCESDEP contains one row for each identity column, and links an ID column definition on SYSSEQUENCES (via BSEQUENCEID) to its corresponding definition in SYSCOLUMNS (via DNAME and DCOLNAME). Both of these tables reside in their own table spaces, called SYSEQ and SYSSEQ2 respectively. On other platforms, only the SYSIBM.SYSSEQUENCES table exists, but this contains mostly the same information as the S/390 implementation.
11.7.6.2 Changed catalog tables The usage of the DEFAULT column in SYSIBM.SYSCOLUMNS has been altered for ID columns as follows:
Set to I if column is an ID column and is GENERATED ALWAYS Set to J if column is an ID column and is GENERATED BY DEFAULT Note that the UPDATES column is always set to Y for ID columns, but as previously noted, GENERATED ALWAYS columns cannot be updated.
221
11.7.6.3 Catalog recovery issues As part of the DB2 catalog, the new tables must be included in your routine catalog backup and recovery jobs.
When recovering the catalog to a prior point in time, you should be aware of the implications this will have for tables containing ID columns. Recovery of SYSIBM.SYSSEQUENCES to a previous point in time may result in duplicate values being generated. To avoid this, consider one of the following options: Recover all table spaces containing tables with ID columns to the same point in time as the catalog is recovered to. Following the catalog recovery, determine the highest used ID column value within all ID column tables, then drop and recreate the table with a new START WITH value as described in 11.7.2.3, Altering an identity column on page 215.
However, given that identity columns will commonly be used as primary keys within a table, you should create a unique index on the column, even where GENERATED ALWAYS is used.
11.7.7.2 Retrieving generated values One of the issues you will need to be aware of when using identity columns is retrieving the unique value generated by DB2 following an insert.
For example, where a referential relationship exists between two tables, it is common to use the primary key of the parent table as a foreign key in the dependent table, as shown in Figure 30.
222
Lets assume that the CUST_NO column of the parent table and the ORDER_NO column of the dependent table are both defined as identity columns, and that we wish to insert new rows into both tables. We may insert a row into the CUSTOMER table using the following SQL statement:
INSERT INTO CUSTOMER (FIRSTNAME, LASTNAME) VALUES (John, Doe);
The INSERT into the parent table is successful, with DB2 automatically generating a value for CUST_NO based upon the parameters we specified when the table was created. However, when we want to insert an associated row into the dependent table, we dont know what value to use for the CUST_NO column. This issue is being addressed via an APAR enhancement to DB2 that implements a new built-in function to return the most recently generated ID column value within the current unit of work. However, there are some requirements that this enhancement cannot address, so you may also need to consider alternative solutions.
Note
Both of the solutions presented below assume you will be using singleton inserts. The techniques will not work with mass insert operations (for example, an INSERT with embedded SELECT).
223
Use of IDENTITY_VAL_LOCAL function APAR PQ36328 introduces a new built-in function called IDENTITY_VAL_LOCAL. This function returns the most recently generated ID column value for a single-row insert within the current unit of work at the current processing level6 . The function returns a DECIMAL(31,0) value, regardless of the data type of the underlying ID column.
To use the previous example, our program successfully inserts a row into the CUSTOMER table using the following SQL:
INSERT INTO CUSTOMER (FIRSTNAME, LASTNAME) VALUES (John, Doe);
We will then be able to handle the subsequent insert into the ORDER table using the following SQL:
INSERT INTO ORDER (CUST_NO, ORDER_DATE) VALUES (IDENTITY_VAL_LOCAL(), CURRENT DATE);
Expressions in a VALUES clause are evaluated before the actual insert takes place. Therefore, the most recent generated ID column value within the processing level is for the previous insert into the CUSTOMER table, and the IDENTITY_VAL_LOCAL function within the subsequent insert into ORDER will work. There are a number of important caveats and restrictions to the use of this function, which you should be aware of: If possible, use the function immediately after the INSERT statement that generates the required ID column value. Any subsequent inserts will make it impossible to retrieve the value using this function. Where a suitable INSERT has not been performed at the current processing level, or a COMMIT or ROLLBACK has occurred since the most recent INSERT, a null value is returned. You need to take special care when using triggers in conjunction with this function. For instance, before-insert triggers will not be able to retrieve the generated value, and after-insert triggers can only retrieve values for inserts performed within the trigger body itself. Ensure that the original INSERT operation was successful before invoking the IDENTITY_VAL_LOCAL function, as the value returned following a failed INSERT is unpredictable.
6 In this context, a
processing level is all of the code within a single program, or trigger, or stored procedure. Therefore, a program calling a stored procedure which executes some SQL that invokes a trigger consists of three processing levels.
224
Use of an after-insert trigger If you are unable to use the IDENTITY_VAL_LOCAL function, you may want to consider the use of a simple after-insert trigger to capture the generated value.
To use this technique, you should: 1. Create a global temporary table like the one shown in Figure 31 to hold the generated value.
2. Create an after-insert trigger on the table with the ID column, to retrieve the generated ID column value and insert it into the global temporary table. An example of this is shown in Figure 32 below.
CREATE TRIGGER CUST_IA AFTER INSERT ON CUSTOMER REFERENCING NEW AS NEWROW FOR EACH ROW MODE DB2SQL BEGIN ATOMIC INSERT INTO GTT_CUST_NO (CUST_NO) VALUES (NEWROW.CUST_NO); END;
Figure 32. Example DDL for an after-insert trigger
225
Note
If you use SPUFI to create your triggers, you will probably encounter an error, due to the fact that SPUFI mistakes any semicolons in the BEGIN ATOMIC section as the end of the CREATE TRIGGER statement. To avoid this problem, you can terminate all statements within the SPUFI file (except the ones in the BEGIN ATOMIC section of your triggers!) with another character (a colon, for example) and update your SPUFI defaults to use this as the statement terminator. 3. From within your application program, INSERT the row into the table (thereby invoking the trigger). 4. SELECT the generated value from the global temporary table after the INSERT. 5. If further inserts will be done within the same unit of work, the row should then be deleted from the global temporary table ready for the process to be repeated. This technique is illustrated in Figure 33.
226
Your program
... INSERT INTO CUSTOMER (FIRSTNAME, LASTNAME) VALUES ('JOHN', 'DOE') ... SELECT CUST_NO FROM GTT_CUST_NO ....
CUSTOMER
CUST_NO (ID column) 1 0010 FIRSTNAME JOHN LASTNAME DOE
CUST_NO 0010
GTT_CUST_NO
1. Program inserts row into table and DB2 generates CUST_NO value. 2. Trigger is fired, and inserts generated CUST_NO value into global temporary table. 3. Program retrieves CUST_NO value from global temporary table.
227
Attribute
Identity columns
ROWID columns
Supports DB2 generated or user-supplied valuesa DB2 guarantees uniqueness of generated values Regularly ascending or descending according to user-defined rules Supported data types
Yes Yes No
VARCHAR(40)
Easily understood external representation of generated values? Comparable with other data types? Can be used to reference LOB columns? Can be used for direct row accessc?
Yes Yes No No
No No Yes Yes
a. User specified values only allowed where columns has been defined with GENERATED BY DEFAULT clause b. For GENERATED ALWAYS columns, or GENERATED BY DEFAULT columns with unique index defined. c. Direct row access is a new feature in DB2 for OS/390 that allows an application to directly access a given row in the table if it can supply a value for the rows ROWID in the query.
In general, you should consider using ID columns for the generation of key values that may need to be presented to the user, or be meaningful in their own right. In contrast, ROWID columns are most useful when direct retrieval and manipulation of the generated value is not required, such as dealing with LOB columns and using direct row access.
228
Site A
CREATE TABLE .... (COLA INTEGER GENERATED BY DEFAULT START WITH 2 INCREMENT BY 2 COLB ...
Site B
CREATE TABLE .... (COLA INTEGER GENERATED BY DEFAULT START WITH 1 INCREMENT BY 2 COLB ...
COLA COLB COLC (ID) 1 ... ... 2 ... ... 3 ... ...
1
COLA COLB COLC (ID) 1 ... ... 2 ... ... 3 ... ...
3
INSERT
INSERT
229
The following is a description of the process illustrated above: 1. Process at Site A inserts a row into table (without specifying a value for COLA), and DB2 generates a value of 2. 2. Replication takes place, and row 2 is replicated to Site B (with the value for COLA being specified). As Site B only generates odd-numbered values for COLA, there is no conflict. 3. Process at Site B inserts a row into the table (without specifying a value for COLA), and DB2 generates a value of 3. 4. Replication takes place, and row 3 is replicated to Site A (with the value for COLA being specified). As Site A only generates even-numbered values for COLA, there is no conflict.
DB2 UDB for OS/390 does not support this syntax. However, as the clause is essentially redundant, it can simply be omitted if SQL portability is an issue.
230
11.7.11.3 Support for ALTER ADD ID column DB2 UDB for UNIX, Windows NT, or OS/2 does not support the ALTER TABLE ADD COLUMN of an identity column to an existing table. Identity columns may only be defined as part of a CREATE TABLE statement. 11.7.11.4 Parallel processing support DB2 UDB for UNIX, Windows NT, or OS/2 does not yet support the use of identity columns in the Enterprise Extended Edition (EEE) of the product, which is designed to run on highly parallel hardware. In contrast, the DB2 UDB for OS/390 implementation offers support for data sharing environments.
231
232
JOHN
SP1 SP2 UDF1 TRIG2 UDT3 SP3 UDF1 UDF1 UDT2 SP3
SMITH
SP1 SP4 UDF1 TRIG2 UDT3 SP3 UDF2 UDF3 UDT1 SP5
PROD1
SPCALC UDF_SALCI US_DOLLARS TRIGGER1 UDT2 SP3
TEST
SPCALC UDF_SALCI US_DOLLARS TRIGGER1 UDT2 SP3
233
A schema can also be used for versioning. As shown in Figure 35, a version of UDF1 exists in schema JOHN and another UDF1 exists in schema SMITH (see 8.3.2, Version control on page 164 for a practical example of how this facility could be used for versioning stored procedures).
When an authorization ID matches a schema name, the authorization ID is said to be the schema owner. The schema owner can issue the above commands to grant/revoke the privileges on the schema for other users. There is a new SET CURRENT PATH statement to specify the value of the CURRENT PATH special register. This register is used to specify one or more schema names that are used to resolve unqualified data type names and function names in dynamically prepared SQL statements. It is also used to resolve unqualified procedure names that are specified as host variables in SQL CALL statements (CALL host-variable). There is a new option in the BIND command to specify the value of the PATH to be used during BIND operations.
234
If the schema name specified is not the primary or a secondary authorization ID associated with the process, the primary or one of the secondary authorization IDs associated with the process must have either the CREATEIN, ALTERIN, or DROPIN privilege for the specified schema. To use COMMENT ON the specified object, the authorization ID (primary or secondary) associated with the process must have ALTERIN privilege on the SCHEMA. SYSADM and SYSCTRL implicitly have these privileges.
CREATE
ALTER
DROP
COMMENT ON
object-type JOHN.object_name
JOHN object_name
* Schema name can be any authorization ID of the process * Schema name can be any name if SYSADM, SYSCTRL, or user has appropriate privilege on the schema name
Figure 36. How a schema is used explicit specification
235
they cannot be issued dynamically when DYNAMICRULES(BIND) was specified during BIND.
CREATE
ALTER
DROP
COMMENT ON
object-type object_name
JOHN object_name
* Static: Schema name is the authorization ID BIND QUALIFIER * Dynamic: Schema name is CURRENT SQLID
(Except for DYNAMICRULES(BIND) ==> if allowed)
Figure 37. How a schema is used implicit specification
DB2 uses schema names from the CURRENT PATH special register. Name resolution is object-specific. When DB2 finds a stored procedure definition, DB2 executes that stored procedure if the following conditions are true: The caller is authorized to execute the stored procedure. The stored procedure has the same number of parameters as in the CALL statement.
236
If both conditions are not true, DB2 continues to go through the list of schemas until it finds a stored procedure that meets both conditions or reaches the end of the list. If DB2 cannot find a suitable stored procedure, it returns a -440 SQL error code for the CALL statement. For the following discussion, refer to Figure 38. The CURRENT PATH special register is a VARCHAR string with the maximum length of 254 bytes. It contains an ordered list of schema names. The schema names SYSIBM, SYSFUN and SYSPROC are always included in the list before any other schema name, therefore you don't have to specify them. You can specify them, to override the order of the search. The schema SYSIBM already contains objects in it. Users cannot create objects in SYSIBM or SYSFUN schemas. The CURRENT PATH special register is used to resolve unqualified object names.
237
The SET CURRENT PATH statement has the following characteristics: It can be used in dynamic SQL. No special authorization is required. It can be static or dynamic. Schema existence is not checked. It is classified as a non-local SET statement in DRDA. The CURRENT PATH special register is used to resolve unqualified user-defined distinct types and functions in dynamic SQL statements. The CURRENT PATH special register is used to resolve unqualified stored procedure names when the SQL CALL statement specifies a host variable for the procedure name, and to resolve UDFs and stored procedures that appear in a trigger body. It is not used for the trigger itself. Invocation: This statement can be embedded in an application program or issued interactively. It is an executable statement that can be dynamically prepared. Authorization: No authorization is required to execute this statement. Syntax: For the following discussion, refer to Figure 39.
_=_ <_,____________________ >>__SET__ _ __________________________ __ PATH_ __ | __ | ___ _schema-name_________ | |_CURRENT__ ___________ _ | | |_SYSTEM PATH________ | |_FUNCTION_| | |_USER______________ |_CURRENT_PATH_____________________| |_ _ _________________ | |_CURRENT__ _____ | |_host-variable_________ |_string-constant________
- Description: schema-name
238
Identifies a schema. DB2 for OS/390 does not validate the existence of the schema. If a schema-name is, for example, misspelled, it will not be noted and it could affect the way subsequent SQL operates. SYSTEM PATH This value is the same as specifying the schema name "SYSIBM" followed by "SYSFUN", followed by "SYSPROC". SYSTEM PATH can only be specified once (SQLSTATE 42732, SQLCODE -585). USER The value of the USER special register. USER can only be specified once (SQLSTATE 42732, SQLCODE -585). host-variable A variable of type CHAR or VARCHAR. The value of the host-variable must represent a valid schema-name and cannot be set to null. If the host-variable has an associated indicator variable, the value of that indicator variable must not indicate a null value (SQLSTATE 42815, SQLCODE -713). The schema name must: - Be left justified within the host variable - Be padded on the right with blanks if its length is less than that of the host variable string-constant A character string constant which represents a valid schema-name.
Note: If the schema name specified here as a string-constant will also be specified in other SQL statements and the schema name does not conform to the rules for ordinary identifiers, then in the other SQL statements the schema name must be specified as a delimited identifier. Notes:
- A schema name appears more than once in the path (SQLSTATE 01625, SQLCODE +585). - The number of schemas that can be specified is limited by the total length of the CURRENT PATH special register. - The special register string is built by taking each schema name specified and removing trailing blanks, adding two delimiters around it, and adding one comma after each schema except the last one.
239
- The length of the resulting string cannot exceed 254 bytes (SQLSTATE 42907, SQLCODE -586). - The schemas SYSIBM, SYSFUN and SYSPROC do not need to be specified. If one is not included in the path, it is implicitly assumed as the first schema (in this case, it is not included in the CURRENT PATH special register). If more than one is not included in the path, SYSIBM is put first in the path followed by SYSFUN and then SYSPROC. If SYSIBM, SYSFUN or SYSPROC is not specified, it is not included in the 254 byte length limit. SET CURRENT PATH is executed by the application server and is therefore classified as a non-local SET statement in DRDA.
where: schema-name Identifies a schema. No validation is done to determine whether the schema actually exists at precompile or at bind time. The same schema cannot appear more than once in the path (DSNT205). The number of schemas that can be specified is limited by the length of the resulting path, which cannot exceed 254 bytes. The length is calculated by taking the length of each schema, adding two for delimiters around each schema and adding one for a comma after each schema except for the last one.
240
The SYSIBM, SYSFUN and SYSPROC schemas do not need to be explicitly specified. They are assumed implicitly to be at the beginning of the list. The implicitly added schemas are added in the order listed above. Furthermore, if SYSIBM, SYSFUN, or SYSPROC are not specified, they are not included in the 254 byte length The schema names are not folded by DB2. Therefore, specify schema names which are ordinary (non-delimited) identifiers in uppercase. Failure to do this results in these schema names being essentially ignored in the path (DB2 only matches them with schemas in the database if they are specified in uppercase). The default (that is, if this option is not specified) is as follows: - BIND PLAN:
SYSIBM, SYSFUN, SYSPROC, <I>plan or package /I>>owner
- BIND PACKAGE:
SYSIBM, SYSFUN, SYSPROC, >plan or package /I>>owner
- REBIND PLAN:
use existing value
- REBIND PACKAGE:
use existing value
241
242
243
244
OS/390 System
DB2
SCHEDULE PROGX PERFORM SQL
PERFORM SQL
PROGX ENDS
PROGY
In addition, stored procedures enable you to split the application logic between the client and the server. You can use this technique to prevent the client application from manipulating the contents of sensitive server data. You can also encapsulate business logic into programs at the server. Stored procedures also enable access to features that exist only on the database server. These features include commands that run only on the server, software installed only on the server that can be accessed by the stored procedure, and the computing resources of the server, such as memory and disk space. Because stored procedures are defined in DRDA, they also take advantage of DRDA features, such as data transformation between platforms, database security and accounting, and two-phase commit support.
245
246
acquired by the stored procedure are released when the client application commits or rolls back. 6. The stored procedure address space uses the LE/370 product libraries to load and execute the stored procedure. Through the DB2 catalog, you can pass run-time parameters for LE/370 when the stored procedure is executed. 7. Control is passed to the stored procedure along with the input and output parameters. The stored procedure can issue most SQL statements. It also has access to non-DB2 resources (however, such updates are outside the unit of work if the stored procedure is being executed within a DB2-established address space). 8. Before terminating, the stored procedure assigns values to the output parameters and returns the control to DB2. 9. DB2 copies the output parameters received from the stored procedure to the client application parameter area and returns control to the client application. 10.The calling program receives the output parameters and continues the same unit of work. 11.The client application implicitly issues the COMMIT statement. With DB2 Version 5, the client application can implicitly commit as soon as the stored procedure returns the control to the client application. If the client application and the stored procedure used during this execution update at different sites, the two-phase commit protocol is used. Although stored procedures are primarily used from DRDA remote clients, they are also supported locally. If a local application issues the SQL CALL statement, the distributed data facility (DDF) is not involved and need not be started.
247
Static or dynamic SQL The stored procedure can issue static or dynamic SQL statements. Data definition language (DDL) statements, most data manipulation language (DML) statements, and data control language (DCL) statements can be coded in a stored procedure. The DRDA architecture allows SQL CALL statements to use static or dynamic SQL. For the current version of the DB2 products, the SQL CALL statement must be a static SQL. Nevertheless, parameters in the CALL statement, including the stored procedure name, can be supplied at execution time. Thus, you can use the SQL CALL statement to dynamically invoke any procedure supported by DB2. These characteristics have not changed in Version 6. Ability to use three-part names over private protocol You can reference aliases or three-part names in a stored procedure. Although for Version 4 and Version 5 you cannot issue an SQL CALL statement in your stored procedure, you can call other programs or routines from a stored procedure by using standard programming language facilities. If you must access the same remote location from a client program that uses CONNECT TYPE 2, you can issue an SQL RELEASE statement for the remote location, followed by an SQL COMMIT statement. These statements must be executed before or after the stored procedure, depending on when you want to connect to the remote location. If you use these statements, you terminate your unit of work. If you do not want to terminate your unit of work, but still want to access tables at the remote location, you can use system-directed access in your client program to the same remote location that the stored procedure is accessing. In this case use a three-part name and do not issue the SQL CONNECT statement. For client programs using CONNECT TYPE 1, you must issue an SQL COMMIT before or after the call to the stored procedure. Unlike DB2 on OS/390, if your client program is running in the workstation platform using CONNECT TYPE 2, you can connect in the same unit of work to the same remote location that is accessed by the stored procedure. Note that a new thread is created when you issue the CONNECT statement. When the stored procedure executes the SQL statement with the three-part name specification, another thread is created in DB2 for the same unit of work. In this scenario, be careful when updates are made from the client program and the stored procedure on the same data. You might get into a lock problem situation because the threads are different.
248
If you have precompiled your program with CONNECT TYPE 1, you must issue an SQL COMMIT statement before or after the call to the stored procedure that is using system-directed access. If you do not commit, your client program receives an SQLCODE -30090 when trying to call the stored procedure or in the SQL CONNECT statement. IFI call and DB2 commands You can use IFI calls and issue commands from the stored procedure. Note that DRDA supports only SQL statements, not commands. If, for example, you need to monitor the DB2 environment from a workstation, you can invoke a stored procedure that issues DB2 commands and returns results to the workstation. Access to non-DB2 resources You can access VSAM files and IMS databases or invoke CICS transactions from a stored procedure. To access an IMS database, you have the following options: - Invoke a CICS transaction - Invoke an APPC application - Use MQ Series - Use DRA (new support in IMS, and must use DB2 Version 5 or higher) Restricted SQL operations For DB2 Version 4 and Version 5, the following SQL statements cannot be used in a stored procedure: - CALL - COMMIT - CONNECT - RELEASE - ROLLBACK - SET CONNECTION - SET CURRENT SQLID If you try to use any of the unsupported SQL statements, your stored procedure and the client program receive a -751 SQLCODE. This is an exceptional case where the client program directly receives the failing SQLCODE that the stored procedure receives. When your stored procedure receives a -751 SQLCODE, the DB2 thread associated with it is placed in a must rollback state.
249
When the client program receives control back from the stored procedure, it must issue a successful SQL ROLLBACK statement before it can continue processing. If the client program does not issue the SQL ROLLBACK statement and terminate, DB2 automatically rolls back the unit of work. If, because an error condition, you want to ensure a rollback in the unit of work, you can code the following ROLLBACK statement in your stored procedure:
IF error-condition THEN EXEC SQL ROLLBACK END-EXEC.
Because ROLLBACK is an invalid SQL statement for stored procedures, your unit of work is placed in a must rollback state.
13.1.3.2 In Version 5 DB2 Version 5 supports WLM-established stored procedures address spaces in addition to the DB2-established address space, which was already supported in DB2 Version 4.
DB2 for OS/390 Version 5 (with OS/390 release 3 or above) enables you to run multiple WLM-managed stored procedures address spaces. With WLM-established address spaces, you can: Access non-DB2 resources with two-phase commit. Execute stored procedures based on individual transaction priorities. Achieve workload balancing across multiple stored procedure address spaces. Utilize the increased flexibility to group or isolate applications. Do a RACF check to non-DB2 resources based on the client authorization. For WLM-established address spaces, you can use the primary authorization ID related to the client application. To do this, you must specify the value Y for the EXTERNAL_SECURITY column of SYSIBM.SYSPROCEDURES. You should only specify this option if you access non-DB2 resources and you want to check the privileges of the client authorization ID instead of the WLM-established address space. The following considerations apply if you specify Y for the EXTERNAL_SECURITY column: If you have inbound translation, the translated authorization ID is used. The RACF ID and group name that you select must have authority to run the Recoverable Resource Manager Services Attachment Facility (RRSAF) application programs.
250
Recoverable Resource Manager Services Attachment Facility An application program can use RRSAF to connect to DB2 to process SQL statements, commands, or instrumentation facility interface (IFI) calls. Programs that run in MVS batch, TSO foreground, and TSO background can use RRSAF.
RRSAF uses OS/390 Transaction Management and Recoverable Resource Manager Services (OS/390 RRS). With RRSAF, you can coordinate DB2 updates with updates made by all other resource managers that also use OS/390 RRS in an MVS system. WLM-established address space must use RRSAF, therefore you may update non-DB2 resources that register with RRS using the two-phase commit protocol. IMS and APPC are examples of RRS enabled resource managers.
Multiple result sets in DB2 for OS/390 DB2 for OS/390 has implemented support to multiple result sets as both client and server.
If your stored procedure is executing on DB2 for OS/390, your stored procedure can return multiple result sets to a local or remote client application. These code points are supported by DB2 CONNECT. If the stored procedure is executing on a remote DRDA application server, the remote DRDA application server must support DRDA code points used to return multiple result sets. To implement multiple result sets for each result set you want returned, your stored procedure must: Declare a cursor with the WITH RETURN option Open the cursor Leave the cursor open When the stored procedure ends, DB2 return the rows in the query result when the client issues a FETCH statement. The RESULT_SETS column of the row associated with your stored procedure in the catalog table SYSIBM.SYSPROCEDURES must contain the maximum number of result sets that the stored procedure will be allowed to return to the caller. For example, if you want to return a result set that contains entries for all employees in department D11, you should code your stored procedure as follows:
251
1. The stored procedure declares a cursor that describes this subset of employee:
EXEC SQL DECLARE CURSOR-EMP CURSOR WITH RETURN FOR SELECT EMPNO, FIRSTNAME, MIDINT, LASTNAME, PHONENO FROM DSN8510.EMP WHERE WORKDEPT=D11; END EXEC
3. It ends without closing the cursor or fetching rows from this cursor. If the stored procedure fetches rows, the fetched rows are not returned to the client. In general, there are no reasons for the stored procedure to fetch the row, but sometimes there might be. Following is an example of a real use for fetching rows from the cursor prior to returning to DB2: The customer has a Web application that can only display 50 rows of data on each page. Web applications are stateless, so they are not able to keep the cursor open to fetch more than 50 rows of data on any given series of Web clicks. To get around this problem, they implemented the query inside a stored procedure. The Web user clicks on a button that indicates whether they want: The first 50 rows The second group of 50 rows The third group of 50 rows And so on If the user wants the second group of 50 rows, the stored procedure issues the SELECT statement specifying WITH RETURN and OPTIMIZE FOR 50 ROWs. The stored procedure then issues 50 FETCH calls, so that the cursor is positioned on row 51. At this point, the stored procedure returns to DB2. DB2 will transmit row 51-100 to the Web server, giving the user what they wanted. In this application, rarely are more than 50 rows returned from a query, so this was a simple way to implement the support. You should use meaningful cursor names for returning result sets, because the name of the cursor that is used to return result sets is available to the client application through extensions to the DESCRIBE statement.
252
You can use any of these objects in the SELECT statement associated with the cursor for a result set: Tables, synonyms, views, temporary tables, and aliases defined at local DB2 system. Tables, synonyms, views, temporary tables, and aliases defined at remote DB2 on OS/390 systems that are accessible through DB2 private protocol access. You can use a temporary table to return result sets from a stored procedure. This capability can be used to return nonrelational data sets such as IMS, VSAM, or QSAM, to a DRDA client. For example, you can access IMS data from a stored procedure in the following way: Access the IMS database. Receive the IMS reply message, which contains data that should be returned to the client. Insert the data from the reply message into a global temporary table. Open a cursor against the temporary table. When the stored procedure ends, the rows from the temporary table are available to the client. Using this approach, you can join information contained in the global temporary table obtained from non-relational data to your DB2 data and return it to the client. You can code your multiple result sets stored procedure in any languages supported to code stored procedures. In addition, the stored procedure can be written using the DB2 for OS/390 ODBC/CLI interface. As with a normal stored procedure, it must use LE/370. Multiple result sets stored procedures are supported in the DB2-established address space and in the WLM-established address spaces. If your application program calls a stored procedure that returns result sets, you must include code in your application to receive each of the result sets. Result sets are only available from read-only client applications. You cannot use the UPDATE OR DELETE for multiple result sets in your client application. Stored procedure result set are always marked read only, so update or delete operations fail if you issue them. This implies that UPDATE or DELETE WHERE CURRENT CURSOR is not allowed in the stored procedure or in the client application.
253
Unlike DB2 UDB for workstations, your DB2 for OS/390 client application can be written in any supported language and can use the DB2 for OS/390 ODBC/CLI interface. If the client application is not using ODBC/CLI, there are the following extensions in the SQL language: A result set locator SQL data type An ASSOCIATE LOCATORS SQL statement An ALLOCATE CURSOR SQL statement A DESCRIBE PROCEDURE SQL statement A DESCRIBE CURSOR SQL statement
COMMIT_ON_RETURN DB2 for OS/390 Version 5 has introduced a new column, COMMIT_ON_RETURN. If you specify N for this column. all updates performed by the unit of work are committed when the client application commits. This is the default.
If you specify Y for this column, all updates performed by the unit of work are committed when control returns to the client application if the SQLCODE for the CALL statement is zero or has a positive value. This implies that updates performed before the stored procedure is invoked, are also committed. Those updates can be updates done by the stored procedure locally or remotely (through a three-part name or using RRSAF), or done locally or remotely by the client application before invoking the stored procedure. Any updates performed by the client application after execution of the stored procedure are part of another unit of work. The client application does not need to code the commit statement. This is valid for DB2-established or WLM-established address spaces, regardless of whether the client application is using COMMIT 1 or COMMIT 2. If the application updated other DRDA servers before invoking the stored procedure, those updates are also committed upon successful execution of the stored procedure. The advantage of committing automatically is that all locks acquired previously are released, except for locks acquired for opened cursors declared with both the WITH HOLD and WITH RETURN options. If the stored procedure is coded to return result sets, you must declare the cursors for the result sets with the WITH RETURN and WITH HOLD options; otherwise the cursors are closed when control returns to the client application. For one result set, you only need to specify WITH HOLD if COMMIT_ON_RETURN is 'Y'.
254
If the stored procedure is connected to a location, for which updates are not allowed, the client application gets a -426 SQLCODE.
DLI support Because IMS does not support multiple TCBs for batch processing and requires that the IMS region controller be the module in control, you cannot access IMS databases directly from the stored procedures address spaces using the batch region facility.
There are several ways that you can access IMS databases: Using the database resource adapter (DRA) callable interface. Including APPC code in the stored procedure. An IMS or CICS transaction can be invoked by APPC. Using the MQI interface to access CICS transaction. Using the EXCI interface. Using the MQI interface to place a transaction on the IMS message queue. Depending on the method and the level of product you use, you can have different combinations of: Commitment control Complexity of the code Performance Once you have accessed IMS databases, you can pass IMS information through output parameters, or you can insert information obtained from IMS databases in a global temporary table, and pass this information to the client application using multiple result sets. Here we describe a method using the DRA callable interface (see Figure 41). The IMS-supplied DRA-callable interface is a facility available in IMS Version 6 as an APAR. The DRA-callable interface allows an OS/390 application execution environment (AEE), such as a stored procedures address spaces, access to IMS database through the IMS database control system (DBCTL).
255
A stored procedure has access to the IMS database using DRA connection to DBCTL in a CICS environment and connection to the IMS control region in an IMS TM environment, because in an IMS TM environment, DBCTL services are provided in the IMS control region. The architecture of DRA, the callable interface, resides in the DB2 stored procedure address space, and is recognized by IMS as an application execution region (AER). Using the DRA-callable interface the stored procedure can access full function DL/I databases and fast path data entry databases (DEDB). The DRA-callable interface allows DBCTL and OS/390 application programs, such as stored procedures, to be developed, installed, and maintained independently of each other.
M V S S y s te m DRDA C lien t EXEC SQL CALL PRO GX D B 2 S to re d P roc e du re s R e gio n DB2 S c h ed P R O G X P R O G X: C ALL C OB T D LI "A P SB " C ALL C OB T D LI "G U " R etu rn v a lu es to D R D A u s e r EXEC SQL C O M M IT MVS RRS
DBCTL
D L IS A S
The IMS DRA-callable interface provides new modules packaged with existing IMS Version 6 DRA modules to support the new callable interface to DBCTL.
256
Because the interface requires OS/390 RRS, you can use the interface only in the WLM-established address space. Note that OS/390 R3 or later is required, due to RRS. As a consequence, the minimum level of DB2 that allows you to use the DRA-callable interface is DB2 for OS/390 Version 5. Because Version 4 supports only DB2-established address spaces, you cannot access an IMS database using the DRA-callable interface with DB2 Version 4. You cannot execute a stored procedure as an IMS batch application, because the batch does not connect to DBCTL. You access IMS databases using the language CALL statement. The CALLs that are available are the CALLs to the AERTDLI interface or the AIBTDLI interface. The following function calls are supported by DRA-callable interface: APSB, CIMS, DEQ, DLET, DPSB, FLD, GU, GHU, GN, GHN, GMSG, ICMD, INIT, INQY, ISRT, LOG, POS, RCMD, REPL, ROLS, SETS, SETU, SNAP, STAT, OPEN, and CLSE.
13.1.3.3 In Version 6 This section describes the stored procedures enhancements introduced in DB2 UDB for OS/390 Version 6.
CREATE PROCEDURE In Version 6, the SYSIBM.SYSPROCEDURES catalog table is no longer used. Stored procedures are defined using the CREATE PROCEDURE DDL statement. The CREATE PROCEDURE statement updates other catalog tables, such as SYSIBM.SYSROUTINES and SYSIBM.SYSPARMS.
As consequence of the CREATE PROCEDURE statement, there are also the ALTER PROCEDURE and DROP PROCEDURE DDL statements. The SQL GRANT and REVOKE statements are enhanced to allow users to manage the privileges to execute stored procedures. The CURRENT PATH special register and the PATH bind option are used to determine the schema name of unqualified stored procedures (see Chapter 12, DB2 UDB for OS/390 schema support on page 233 for more details about schemas). Stored procedures share with User Defined Functions (UDFs) the same catalog tables for CREATE/ALTER/GRANT and REVOKE.
257
Three-part name usage In prior release of DB2, the stored procedure name was composed of three parts. If the first part was specified, it had to match the location of the current server. If the second part was specified, it had to match exactly SYSPROC. The third part had to match the PROCEDURE column of SYSIBM.SYSPROCEDURE table.
In Version 6, the first part can match any LOCATION name specified in the SYSIBM.LOCATIONS catalog table. An implicit CONNECT statement is issued to that location, using DRDA. This provides an enhanced degree of flexibility. You can invoke a remote procedure as long as you have DRDA connectivity to the location where the stored procedure resides.
Usage of schemas In Version 6, the second part of the name does not need to be SYSPROC. it can be any schema name. Again, this provides a greater degree in management of stored procedures. You may want to group all related stored procedures under the same schema. See Chapter 12, DB2 UDB for OS/390 schema support on page 233 for more details about schemas. Some DML restrictions lifted SQL statements such as CALL, CONNECT, SET CONNECTION and RELEASE are now allowed within a stored procedure. This allows for nesting of stored procedures and flexibility to manage the connections. Authorization enhancements Because the stored procedure is now created using SQL CREATE statement, the authorization ID that creates the stored procedure is the OWNER of the stored procedure and owns it. In previous versions, if the stored procedure had no SQL, then a package was not required, and you could not directly prevent the execution of the stored procedure.
Now the owner of the stored procedure can prevent execution of the stored procedure even if the stored procedure does not require a package. Also, when you create the stored procedure, you can specify several levels of DML SQL statements that can be issued by the stored procedure.
UDFs You can invoke a UDF from a stored procedure and you can invoke a stored procedure from within a UDF. With the support for the SQL CALL statement in a stored procedure, you can nest stored procedures and UDFs. UDFs execute the same way that stored procedures do, in the WLM-established
258
address space. Stored procedures can also be invoked from triggers. Transition tables can be passed to the stored procedure from triggers.
Note:
LOBs You can use LOCATORs, BLOB, CLOB, DBCLOB as input or output parameters to the stored procedures.
Note:
In version 6, LOBs, LOCATORs and ROWID cannot be defined as parameters to stored procedures written in Java.
UDTs The built-in as well as the UDT are supported for the data type of stored procedure input/output parameters.
259
1,'WLMJAVADBS1','S','N','N' );
Note that there are new options, modified options, and options that are unmodified from previous versions. Following are the new options available in Version 6: NOT DETERMINISTIC | DETERMINISTIC This optional clause specifies whether the stored procedure will always return the same result from successive calls with identical input arguments. CONTAINS SQL | READS SQL DATA | MODIFIES SQL DATA | NO SQL This optional clause specifies whether the stored procedure issues any SQL statement, and if so, what type of SQL statements. DBINFO | NO DBINFO Specifies whether specific information known by DB2 is to be passed to the stored procedure as an additional invocation time argument. Following are the options that were enhanced in Version 6: PARAMETER STYLE Identifies the linkage convention used to pass parameters to the stored procedure. All of the linkage conventions provide arguments to the stored procedure containing the parameters specified on the SQL CALL
260
statement. Some of the linkage conventions pass additional arguments to the stored procedure that provide more information to the stored procedure. NO WLM ENVIRONMENT | WLM ENVIRONMENT (name,*) Specifies if this stored procedure is to execute in the DB2-established stored procedure address space or in the WLM-established stored procedure address space. EXTERNAL SECURITY Specifies how this stored procedure interacts with an external security product (such as RACF) to control access to non-DB2 resources. The following options were already specifiable through the SYSIBM.SYSPROCEDURE catalog table and have not changed for this version of DB2. Following is a brief explanation of the various options: LANGUAGE Specifies the language in which this stored procedure is coded. EXTERNAL NAME Specifies the name of the load module for this stored procedure COLLID Identifies the package collection to use when the stored procedure is executed. ASUTIME Specifies the total amount of CPU that a single invocation of a stored procedure can run, in CPU service units. RUN OPTIONS Specifies the LE/370 run-time options to be passed to the stored procedure. STAY RESIDENT Specifies whether the stored procedure load module remains resident in memory when the stored procedure ends. PROGRAM TYPE Specifies whether the stored procedure runs as a main routine or as a subroutine. If the CREATE statement is embedded in a program, the default for this option depends on the value of the SQLRULES option: - If SQLRULES(DB2) is specified, the default for PROGRAM TYPE is MAIN.
261
- If SQLRULES(STD) is specified, the default for PROGRAM TYPE is SUB. If the CREATE statement is issued dynamically, the default for this option depends on the value of the CURRENT RULES special register: If the CURRENT RULES special register is DB2, the default for PROGRAM TYPE is MAIN. If the CURRENT RULES special register is STD, the default for PROGRAM TYPE is SUB. RESULT SET n Specifies the maximum number of result sets that can be returned by the stored procedure. COMMIT ON RETURN Indicates whether the transaction should be committed immediately upon return from a successful execution of the stored procedure. Note that in Version 6, there is no specification equivalent to AUTHID and LUNAME. These were most likely used for versioning. You can still control the versioning by placing the same stored procedure definition under different schemas. In this case, you should also specify that the stored procedure executes in different WLM-established stored procedure address spaces (different WLM application environments), if the load module name is equal for both versions, each one in a different load module library.
Note:
The stored procedures with the same name but different schemas can have different EXTERNAL NAME and be in the same WLM environment, they only have to be in different ones if they have the same EXTERNAL NAME (load module).
262
[schema.]udt | built_in
AS LOCATOR
Only a LOB data type, or a distinct type based on a LOB data type, can specify AS LOCATOR. Note that for Version 6, in the SQL CALL statement, you can pass a special register, an operator (+, -, *, /, CONCAT, !!), a CASE expression, a CAST specification, or a function besides a constant, a host variable, and the NULL value. A table can also be passed, if the SQL CALL statement is issued from a trigger. Each column of the table comes in as a separate parameter, described by an SQLDA.
Note:
In version 6, LOBs, LOCATORs and ROWID cannot be defined as parameters to stored procedures written in Java.
263
DETERMINISTIC The stored procedure always returns the same result from successive calls with identical input arguments. For example, if you issue the following CALL:
CALL TOTAL_SALES_96(itemnumber)
This is deterministic, because no matter how many times you invoke the stored procedure the total sales for a passed year will always be the same for a particular item. On the other hand, if you issue the following CALL:
CALL CURRENT_SALES(itemnumber)
This is not deterministic, because depending upon when you invoked the stored procedure, the sales for a particular item might have changed. Note that DB2 does not check if the stored procedure is consistent with the specification of DETERMINISTIC or NOT DETERMINISTIC. The specification is intended for documentation purposes. In the future, this might be used for optimization (not to actually call the stored procedure, if we already know what the answer will be). NO SQL No SQL statements are allowed in the stored procedure. If the stored procedure attempts to execute any SQL statements, then an error (SQLCODE-487) is raised at run time. Nevertheless, the stored procedure can perform complex calculations, access non-DB2 resources, or trigger events outside of DB2, such as to broadcast an e-mail. CONTAINS SQL If the stored procedure attempts to execute COMMIT, DELETE, DESCRIBE PREPARE, ROLLBACK, SELECT and INSERT SQL statements, then an error (SQLCODE-579) is raised at run time. This is the default when you create a procedure. The restriction applies to all SQL (cursors or singleton SQL). READS SQL DATA If the stored procedure attempts to execute COMMIT, DELETE, INSERT, ROLLBACK, and UPDATE SQL statements, then an error (SQLCODE-577) is raised at run time. MODIFIES SQL DATA If the stored procedure attempts to execute COMMIT, AND ROLLBACK SQL statements, then an error (SQLCODE-751) is raised at run time. If this was for a ROLLBACK statement, the whole unit of work is placed in a
264
"must rollback state". The SYSIBM.SYSPROCEDURES (Version 5) catalog entries will be migrated to be 'MODIFIES SQL DATA', not the default CONTAINS SQL.
Note:
NO SQL, CONTAINS SQL, READS SQL DATA, and MODIFIES SQL DATA are (by ANSI rules) supposed to 'cascade' such that nested procedures obey the strictest rule specified by any parent (calling) procedure. DB2INFO When DB2INFO is specified (NO DB2INFO is the default), an additional argument is passed on invocation of the stored procedure. This specification is compatible with UDFs, therefore some of the information will be blank for stored procedures. The argument is a structure which contains the following information: - Location name length - Location name of where the stored procedure was invoked - Application run-time authorization ID, regardless of the nested routines in between this routine and the application - CCSID of the DB2 subsystem - Schema-name blank for stored procedures - Table name length, blank for stored procedures - Table name, blank for stored procedures. - Column name blank for stored procedures - Column name, blank for stored procedures - Database release level of where the stored procedure was invoked - Database version number of where the stored procedure was invoked - Operating system platform of where the stored procedure was invoked
265
versions SIMPLE WITH NULLS for the LINKAGE column of SYSPROCEDURES), the DB2SQL option can be specified. When DB2SQL is specified, additional arguments are passed to/from the stored procedure: - A null indicator for each parameter on the CALL statement - The SQLSTATE to be returned to DB2 upon completion of the stored procedure - The qualified name of the stored procedure (location.schema.procname) - The specific name of the stored procedure - Currently DB2 does not support multiple procedures with the same name in the same schema, so the specific name is the same as the procedure name - The SQL diagnostic string to be returned to DB2 Migrated stored procedures will have GENERAL or GENERAL WITH NULLS depending on the value of LINKAGE. EXTERNAL SECURITY DEFINER In addition to DB2 (in previous versions NO for the EXTERNAL_SECURITY column of SYSPROCEDURES) and USER (in previous versions YES for the EXTERNAL SECURITY column of SYSPROCEDURES), the DEFINER option can be specified. When DEFINER is specified, an external security environment should be established for the stored procedure. If the stored procedure accesses resources protected by an external security product, that access will be performed using the authorization ID of the person that created the stored procedure. This specification is valid only for WLM-established stored procedure address spaces. WLM ENVIRONMENT (name,*) When the stored procedure is called directly by an SQL application program, name specifies the WLM application environment used to run the stored procedure. If the stored procedure is called by another stored procedure or UDF (nested CALL to a stored procedure), this stored procedure will run in the environment used by the calling stored procedure or user-defined function.
266
WLM will try to schedule the stored procedure to run in the same address space as the calling stored procedure or UDF. But if for any reason it cannot (for example, maximum number of TCBs exceeded, requirement to schedule another address space), the stored procedure will still run using the application environment of the caller, but will run in another address space. WLM uses the current workload and the priority of the thread to decide whether to schedule another address space. The stored procedure will run in the same application environment as the caller if the ,* is specified after name. Note also that to prevent users from moving a stored procedure or a UDF to a sensitive WLM application environment, DB2 invokes the external security manager (for example, RACF), to determine if the user is allowed to issue ALTER statements that reference the specified WLM environment. The RACF command below authorizes a DB2 user (DB2USER1) to CREATE or ALTER stored procedures on DB2 subsystem DB2A that specify the WLM environment PAYROLL:
PERMIT DB2A.WLMENV.PAYROLL CLASS(DSNR) ID(DB2USER1) ACCESS(READ)
267
- Privileges To CREATE a stored procedure, one of the following privileges is required: CREATE IN schema SYSADM or SYSCTRL authority. Usage of schemas The following sections describe some considerations related to the usage of schemas and stored procedures. Note that the CREATE IN schema is implicit in your own USERID. ALTER You can ALTER any of the options of a stored procedure. The altered definition and the original definition are both cached in memory. Only the application that performed the ALTER sees the altered definition. Once the application that performed the ALTER commits, the old definition is deleted and the new definition is available. - Privilege To ALTER a stored procedure, one of the following privileges is required: Ownership of the stored procedure ALTER IN schema SYSADM or SYSCTRL authority - CALL packages are invalidated Any program (client, UDFs, or another stored procedure that has a CALL for the altered procedure) have their packages invalidated. On the next invocation of the altered stored procedure, the packages are automatically rebound. DROP The keyword RESTRICT must be specified. All packages containing a CALL to the stored procedure are invalidated, but RESTRICT only applies to trigger packages. The stored procedure is not dropped if a trigger definition contains a CALL to this stored procedure.
268
- Privilege To DROP a stored procedure, one of the following privileges is required: Ownership of the stored procedure DROP IN schema SYSADM or SYSCTRL authority COMMENT ON PROCEDURE You can use the COMMENT ON PROCEDURE procname to add comments to an existing stored procedure. These comments are registered in the REMARKS columns of the corresponding row of SYSROUTINES.
In this case, the schema can be the same as any authorization IDs of the process. However, if the specified name includes a qualifier that is not the same as one of these authorization IDs, then one of the following must be met: The privilege set includes SYSADM or SYSCTRL The authorization ID of the process has the CREATE IN privilege on the specified schema. If the procedure name is unqualified, as, for example:
CREATE procname....
and the statement is embedded in a program, the schema name of the procedure is the authorization ID in the QUALIFIER bind option when the plan or package was created or last rebound. If QUALIFIER was not used, the schema name of the procedure is the owner of the plan or package. If the procedure name is unqualified and the statement is dynamically prepared, the SQL authorization ID contained in the CURRENT SQLID special register is the schema name of the stored procedure.
269
270
You should use VALIDATE(RUN) with a remote call or the local BIND will fail, since the stored procedure will most likely not exist at the calling site. Note that there was not any such validation in Version 4 or 5. If you specify a literal for the stored procedure name without a schema name, then name resolution occurs at bind time based on the PATH bind option specification. If you specify a host variable for the stored procedure name, then name resolution occurs at the execution time based on the value of the CURRENT PATH special register. Note that all CALLs issued by ODBC, JDBC, or CLI are resolved at execution time. This is because each of these drivers map the CALL onto a CALL :hv in the driver package. DB2 searches the schema name using the CURRENT PATH special register or the PATH bind option from left to right. It qualifies the specified procedure name starting with the first schema name of CURRENT PATH or PATH bind option until a match is found. If a matching schema.procname is found, but the caller is not authorized to it, or if the number of parameters in the procedure definition does not match the number of parameters specified in the CALL statement, the next schema.procname combination is tried until one is found that the caller is authorized to execute and has a matching number of parameters, or until the list of schemas is exhausted. If the
271
procedure name cannot be resolved a -440 SQLCODE is returned. Figure 44 summarizes this flow.
C A L L p ro c 1 C A L L :h o s tv a r
P A T H b in d o p tio n C U R R E N T P A T H s p e c re g
N e x t s c h e m a ? = = = = > N O = = = = = > -4 4 0 p ro c 1 fo u n d ?
NO
U s e r is a u t h o ri z e d ?
M a tc h i n g n u m b e r o f p a rm s ?
T h a t's th e o n e !!!
272
Note that if the stored procedure is used for complex logic and complex calculation but no data access, you can have code reuse. For example, assume you have a workstation that invokes a stored procedure on one DB2, whose hardware capability is not fitted for heavy calculations. This stored procedure can invoke a remote stored procedure just for this purpose. Figure 45 shows an example of nested SQL CALLs. See 13.4, Nested stored procedures: characteristics on page 274 for more details about nested stored procedures.
CALL PROC1
DRDA
PR3 CALL PR4 PR4
In addition, as mentioned before, if you use the three-part name, then the location name does not need to match the location of the current server. It can be any location specified in the SYSIBM.SYSLOCATIONs catalog table. Note that if you specify a location that refers to a DB2 on OS/390 prior to Version 6, you should code for the second part SYSPROC. DB2 UDB supports schema names for stored procedures. No particular DRDA level required. The schema.procname is buried within the execute SQL statement DDM message.
273
No COMMIT ON RETURN A stored procedure with the COMMIT ON RETURN attribute cannot be nested. In other words, a stored procedure, user-defined function, or trigger cannot issue a CALL to a stored procedure defined with the COMMIT ON RETURN attribute (SQLCODE -729). However, a client can invoke a stored procedure that has COMMIT ON RETURN specified, and this stored procedure CALLs other stored procedures for which COMMIT ON RETURN was NOT specified. A stored procedure that executes in a WLM-established address space cannot be nested with a stored procedure that executes in a DB2-established address space. You can nest DB2-established with DB2-established and WLM-established with WLM-established, but you cannot nest the two with each other. Result sets Result sets are returned only to the previous levels.
274
Up to 16 levels of nesting You can nest stored procedures, UDFs and triggers up to 16 levels. Note that if you use a three-part name to invoke a procedure at a remote location, the nesting level starts over at that new server. Also, if there is a loop back to the first server, it is again reset, but the remote chain will stop there because that server cannot nest to another location. The nesting level is any combination of stored procedures, UDFs, and triggers. Can use alias for three-part name tables This capability is no different than in previous versions of DB2. However, DRDA can now be used as the protocol; therefore, you can also access tables at non-DB2 for OS/390 remote sites from a stored procedure.
13.5 Authorization
Figure 46 shows the authorization required to issue the CALL statement for a stored procedure, depending on the caller, as follows: The client application that has a CALL coded must have a package created (if the client is remote, the package is enough), or must have a plan that includes a package, or the DBRM was bound directly in plan. The stored procedure, in turn, must have a package if it has SQL statements coded. The stored procedure can invoke another program (or stored procedure), which, in turn, must have a package if the routine has SQL statements. To execute the plan (or package for remote clients), one of the following privileges is required: EXECUTE on plan or package of the client application Ownership of the plan or package of the client application PACKADM on the collection where the package for client application was bound SYSADM authority
275
C LIEN T
SP1 C ALL P G M 1
CA LL S P 1
PG M 1
P LA N
C LIE N T
S P1
P A CK A G E
PGM1 P A CK A G E
P AC K A G E
To execute the package/plan m ust: EX E CU TE on plan/package Ownership of plan/package PA C K AD M on collection SY S A DM Owner of client package/authid of client m us t: E X E CU TE on S P O wnership of S P S Y S A DM
For static SQL calls that specify a literal for a procedure name, the owner of the package for the client application (OWNER bind specification) must have one of the following privileges: EXECUTE on the stored procedure Ownership of the stored procedure SYSADM authority The owner of the stored procedure (owner is the definer, who issued the CREATE PROCEDURE statement, in turn, must have one of the following privileges: EXECUTE on the stored procedure package and packages for invoked routines from the stored procedure (packages SP1 and PGM1 as shown in Figure 46) Ownership of the stored procedure package and packages for invoked routines from the stored procedure (packages SP1 and PGM1 as shown in Figure 46) PACKADM on the collection of the stored procedure and on the collection where the packages for invoked routines from the stored procedure (packages SP1 and PGM1 as shown in Figure 46) SYSADM authority
276
277
CLIENT
CALL SP1
PGM1
PLAN
CLIENT
SP1
PACKAGE
PGM1 PACKAGE
PACKAGE
* Literal:owner of the package/plan of the client * Host variable: depends on DYNAMICRULES: RUN =>primary/sec AUTHID associated with the client BIND=>owner of package/plan containing CALL DEFINE=> equal BIND, or owner of SP/UDF INVOKE=> equal RUN, or invoker of SP/UDF
Figure 47. Authorization who is checked?
Let us now guide you though an example: Assume that a stored procedure (SP1) invokes another routine (PGM1). There is a client application with a CALL statement for this stored procedure. Three packages are invoked: PKG1 for the routine PKG2 for the stored procedure PKG3 for the client application Also assume the following: The owner of PKG1 is USER1. The owner of PKG2 is USER2. The owner of the stored procedure is USER3. The owner of the package of the client application is USER4. USER5 wants to execute the client application. Under these conditions: USER3, the owner of the stored procedure, must have EXECUTE privilege on PKG1.
278
USER5 must have EXECUTE privilege on the package of the client application:
USER4: GRANT EXECUTE ON PKG3 TO USER5
- For static SQL programs that specify a literal, the owner of the client application (USER4) must have EXECUTE privilege on the stored procedure:
USER3: GRANT EXECUTE ON PROCEDURE SP1 TO USER4
- For static SQL that specifies a host variable or parameter marker the authorization ID that will be checked for the execution of the stored procedure will be USER5 or USER4 depending on the DYNAMICRULES bind option. If DYNAMICRULES bind option is RUN, the privilege is checked against USER5:
USER3: GRANT EXECUTE ON PROCEDURE SP1 TO USER5
SP1 USER3
USER5
PGM1
PKG3
USER4
PKG2
USER2
PKG1
USER1
USER1: GRANT EXECUTE ON PACKAGE PKG1 TO USER3 USER2: GRANT EXECUTE ON PACKAGE PKG2 TO USER3
IN ADDITION
CALL SP1 ===> USER3: GRANT EXECUTE ON PROCEDURE SP1 TO USER4 CALL :HV ===> USER3: GRANT EXECUTE ON PROCEDURE SP1 TO USER5 (DYNAMICRULES RUN) CALL :HV ===> USER3: GRANT EXECUTE ON PROCEDURE SP1 TO USER4 (DYNAMICRULES BIND)
279
DSNX940I csect - DISPLAY PROCEDURE REPORT FOLLOWS------ SCHEMA=PAYROLL PROCEDURE STATUS PAYRPRC1 STARTED PAYRPRC2 STOPQUE PAYRPRC3 STARTED USERPRC4 STOPREJ
ACTIVE 0 0 2 0
QUEUED 0 5 0 0
MAXQUE 1 5 6 1
------ SCHEMA=HRPROD PROCEDURE STATUS ACTIVE HRPRC1 STARTED 0 HRPRC2 STOPREJ 0 DISPLAY PROCEDURE REPORT COMPLETE
QUEUED 0 0
MAXQUE 1 1
TIMEOUT 0 0
The DISPLAY PROCEDURE does not use the current path to determine schema. It works the same way from an application program as from the console. The argument to display with schema can be: Procedure name displays the named stored procedure in schema SYSPROC (*.*) displays information for all stored procedures in all schemas that have been accessed by DB2 applications, since DB2 was started. This is the default. You must have DISPLAY privilege, SYSOPR, SYSCTRL, or SYSADM authority for all schemas to issue DISPLAY PROCEDURE with this option. Note that the owner of a stored procedure can DISPLAY their stored procedures status.
280
281
282
Part 4. Appendices
283
284
DSNL066I DSNL066I csect STOP DDF MODE(SUSPEND) COMPLETE Explanation: DDF suspend processing has completed successfully. DDF has suspended all inbound activity. System Action: Processing continues normally.
_____________________________________________________________
DSNL067I DSNL067I csect CURRENT DDF STATE DOES NOT PERMIT START DDF Explanation: The current DDF state does not allow START DDF processing to be initiated. System Action: The command is not executed.
_____________________________________________________________
DSNL068I DSNL068I csect START DDF (RESUME PROCESSING) COMPLETE Explanation: DDF has resumed normal processing. System Action: Processing continues normally.
_____________________________________________________________
285
Explanation: DDF has initiated suspend processing. System Action: Processing continues normally.
_____________________________________________________________
DSNL070I DSNL070I csect DDF IS RESUMING Explanation: DDF has initiated resume processing. System Action: Processing continues normally.
_____________________________________________________________
DSNL071I DSNL071I csect WAIT OR CANCEL REQUIRES KEYWORD SUSPEND Explanation: The WAIT(n) or CANCEL(n) key words require that MODE(SUSPEND) be specified. System Action: The command is not executed.
_____________________________________________________________
DSNL072I DSNL072I csect WAIT TIME EXPIRED, DDF RESUME PROCESSING INITIATED Explanation: The DDF suspend process has not completed successfully in the period of time specified for the WAIT key word and so DDF resume processing has been initiated. System Action: DDF resume processing has been initiated.
_____________________________________________________________
DSNL073I DSNL073I csect CANCEL TIME EXPIRED, CANCEL ACTIVE DBAT PROCESSING HAS BEEN INITIATED. Explanation: The DDF suspend process has not completed successfully in the period of time specified for the CANCEL key word and so DDF is cancelling all active data base access threads (DBATS). System Action: DDF is attempting to terminate all active data base access threads.
286
287
CREATE TABLE ACMES.CUSTOMER ( CUST_NO INTEGER NOT NULL PRIMARY KEY, CUST_FIRSTNAME CHAR(20) NOT NULL, CUST_LASTNAME CHAR(20) NOT NULL, CUST_ADDRESS CHAR(30) ) IN DACMES.SCUST; CREATE UNIQUE INDEX ACMES.P_CUSTOMER ON ACMES.CUSTOMER (CUST_NO); --- PRODUCT -CREATE TABLESPACE SPRODUCT IN DACMES USING STOGROUP SYSDEFLT; CREATE TABLE ACMES.PRODUCT ( PROD_NO INTEGER PROD_DESC PROD_PRICE PROD_IN_STOCK ) IN DACMES.SPRODUCT;
NOT NULL PRIMARY KEY, CHAR(30) NOT NULL, DECIMAL(10,2) NOT NULL, INTEGER NOT NULL
288
-- ORDER -CREATE TABLESPACE SORDER IN DACMES USING STOGROUP SYSDEFLT; CREATE TABLE ACMES.ORDER ( ORD_NO INTEGER
NOT NULL PRIMARY KEY , ORD_DATE DATE NOT NULL, ORD_CUST_NO INTEGER NOT NULL, FOREIGN KEY (ORD_CUST_NO) REFERENCES ACMES.CUSTOMER(CUST_NO) ON DELETE CASCADE ) IN DACMES.SORDER; CREATE UNIQUE INDEX ACMES.P_ORDER ON ACMES.ORDER (ORD_NO); CREATE INDEX ACMES.F_ORDER_1 ON ACMES.ORDER (ORD_CUST_NO); --- ORDER ITEM -CREATE TABLESPACE SORDITEM IN DACMES USING STOGROUP SYSDEFLT; CREATE TABLE ACMES.ORDER_ITEM ( ORD_ITEM_NO INTEGER NOT NULL PRIMARY KEY, ORD_ITEM_ORD_NO INTEGER NOT NULL, ORD_ITEM_PROD_NO INTEGER NOT NULL, ORD_ITEM_QTY INTEGER NOT NULL, FOREIGN KEY (ORD_ITEM_ORD_NO) REFERENCES ACMES.ORDER(ORD_NO) ON DELETE CASCADE, FOREIGN KEY (ORD_ITEM_PROD_NO) REFERENCES ACMES.PRODUCT(PROD_NO) ON DELETE CASCADE ) IN DACMES.SORDITEM;
289
CREATE UNIQUE INDEX ACMES.P_ORDER_ITEM ON ACMES.ORDER_ITEM (ORD_ITEM_NO); CREATE INDEX ACMES.F_ORDER_ITEM_1 ON ACMES.ORDER_ITEM (ORD_ITEM_ORD_NO); CREATE INDEX ACMES.F_ORDER_ITEM_2 ON ACMES.ORDER_ITEM (ORD_ITEM_PROD_NO); --- HI_CUST_NO -CREATE TABLESPACE SHICUST IN DACMES USING STOGROUP SYSDEFLT; CREATE TABLE ACMES.HI_CUST_NO ( HI_CUST_NO INTEGER NOT NULL ) IN DACMES.SHICUST; INSERT INTO ACMES.HI_CUST_NO VALUES(1); --- HI_ORD_NO -CREATE TABLESPACE SHIORD IN DACMES USING STOGROUP SYSDEFLT; CREATE TABLE ACMES.HI_ORD_NO ( HI_ORD_NO INTEGER NOT NULL ) IN DACMES.SHIORD; INSERT INTO ACMES.HI_ORD_NO VALUES(1);
290
If you intend to submit the following DDL using SPUFI, ensure that the termination character is set to : in the SPUFI defaults panel (see explanatory text in DDL for details).
----------------------------------------------------------DDL FOR ACME SOFTWARE CO EXAMPLE ------- SQL LEVEL: ENHANCED (USES ENHANCED V6 FEATURES) ----- NOTE: THE COLON (':') CHARACTER IS USED INSTEAD --OF THE SEMICOLON (';') CHARACTER FOR --TERMINATING COMMNANDS, DUE TO THE PRESENCE --OF CREATE TRIGGER STATEMENTS. ----IF THIS FILE IS SUBMITTED USING SPUFI, --ENSURE THAT THE TERMINATION CHARACTER IS --SET TO ':' IN THE SPUFI DEFAULTS PANEL. -----------------------------------------------------------
--------------------------------------------------------CREATE DATABASE ----------------------------------------------------------DROP DATABASE DACMEE : COMMIT : CREATE DATABASE DACMEE : --------------------------------------------------------CREATE TABLESPACES/TABLES/INDEXES ----------------------------------------------------------- CUSTOMER --
291
CREATE TABLE ACMEE.CUSTOMER ( CUST_NO INTEGER NOT NULL PRIMARY KEY GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1, CACHE 10), CUST_FIRSTNAME CHAR(20) NOT NULL, CUST_LASTNAME CHAR(20) NOT NULL, CUST_ADDRESS CHAR(30) NOT NULL ) IN DACMEE.SCUST: CREATE UNIQUE INDEX ACMEE.P_CUSTOMER ON ACMEE.CUSTOMER (CUST_NO): --- PRODUCT -CREATE TABLESPACE SPRODUCT IN DACMEE USING STOGROUP SYSDEFLT: CREATE TABLE ACMEE.PRODUCT ( PROD_NO INTEGER
PROD_DESC CHAR(30), PROD_PRICE DECIMAL(10,2) NOT NULL, PROD_IN_STOCK INTEGER NOT NULL ) IN DACMEE.SPRODUCT: CREATE UNIQUE INDEX ACMEE.P_PRODUCT ON ACMEE.PRODUCT (PROD_NO): --
292
-- ORDER -CREATE TABLESPACE SORDER IN DACMEE USING STOGROUP SYSDEFLT: CREATE TABLE ACMEE.ORDER ( ORD_NO INTEGER PRIMARY KEY
NOT NULL
GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1, CACHE 10), ORD_DATE DATE NOT NULL, ORD_CUST_NO INTEGER NOT NULL, FOREIGN KEY (ORD_CUST_NO) REFERENCES ACMEE.CUSTOMER(CUST_NO) ON DELETE CASCADE ) IN DACMEE.SORDER: CREATE UNIQUE INDEX ACMEE.P_ORDER ON ACMEE.ORDER (ORD_NO): CREATE INDEX ACMEE.F_ORDER_1 ON ACMEE.ORDER (ORD_CUST_NO): --- ORDER ITEM -CREATE TABLESPACE SORDITEM IN DACMEE USING STOGROUP SYSDEFLT: CREATE TABLE ACMEE.ORDER_ITEM ( ORD_ITEM_NO INTEGER NOT NULL PRIMARY KEY GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1, CACHE 10), ORD_ITEM_ORD_NO INTEGER NOT NULL,
293
ORD_ITEM_PROD_NO INTEGER NOT NULL, ORD_ITEM_QTY INTEGER NOT NULL, FOREIGN KEY (ORD_ITEM_ORD_NO) REFERENCES ACMEE.ORDER(ORD_NO) ON DELETE CASCADE, FOREIGN KEY (ORD_ITEM_PROD_NO) REFERENCES ACMEE.PRODUCT(PROD_NO) ON DELETE CASCADE ) IN DACMEE.SORDITEM: CREATE UNIQUE INDEX ACMEE.P_ORDER_ITEM ON ACMEE.ORDER_ITEM (ORD_ITEM_NO): CREATE INDEX ACMEE.F_ORDER_ITEM_1 ON ACMEE.ORDER_ITEM (ORD_ITEM_ORD_NO): CREATE INDEX ACMEE.F_ORDER_ITEM_2 ON ACMEE.ORDER_ITEM (ORD_ITEM_PROD_NO):
--------------------------------------------------------CREATE GLOBAL TEMP TABLES ----- THESE ARE USED BY THE AFTER-INSERT TRIGGERS THAT --- ARE DEFINED BELOW. THE TRIGGERS INSERT THE PRIMARY --- KEY VALUE OF THE NEW ROW INTO THE GLOBAL TEMP --- TABLE TO ALLOW IT TO BE ACCESSED BY THE CALLING --- APP. ----------------------------------------------------------CREATE GLOBAL TEMPORARY TABLE ACMEE.GTT_CUST_NO ( CUST_NO INTEGER NOT NULL ): CREATE GLOBAL TEMPORARY TABLE ACMEE.GTT_ORDER_NO ( ORDER_NO INTEGER NOT NULL ): --------------------------------------------------------CREATE TRIGGERS ---------------------------------------------------------
294
CREATE TRIGGER ACMEE.CUST_IA AFTER INSERT ON ACMEE.CUSTOMER REFERENCING NEW AS NEWROW FOR EACH ROW MODE DB2SQL BEGIN ATOMIC INSERT INTO ACMEE.GTT_CUST_NO (CUST_NO) VALUES (NEWROW.CUST_NO); END: CREATE TRIGGER ACMEE.ORD_IA AFTER INSERT ON ACMEE.ORDER REFERENCING NEW AS NEWROW FOR EACH ROW MODE DB2SQL BEGIN ATOMIC INSERT INTO ACMEE.GTT_ORDER_NO (ORDER_NO) VALUES (NEWROW.ORD_NO); END: --------------------------------------------------------Create Temporary Table Used For Summary Query--------------------------------------------------------create global temporary table acmee.order_item_summ ( PROD_DESC CHAR(30) , QTY_1_TO_5 CHAR(1) NOT NULL, QTY_6_TO_10 CHAR(1) NOT NULL, QTY_11_PLUS CHAR(1) NOT NULL ): --------------------------------------------------------POPULATE PRODUCT TABLE --------------------------------------------------------INSERT INTO ACMEE.PRODUCT (PROD_NO, PROD_DESC, PROD_PRICE, PROD_IN_STOCK) VALUES (1,'Acme Word Processor',19.99,200): INSERT INTO ACMEE.PRODUCT (PROD_NO, PROD_DESC, PROD_PRICE, PROD_IN_STOCK) VALUES (2,'Acme Speadsheet',29.99,12): INSERT INTO ACMEE.PRODUCT (PROD_NO, PROD_DESC, PROD_PRICE, PROD_IN_STOCK) VALUES (3,'Acme Presentation Graphics',29.99,101): INSERT INTO ACMEE.PRODUCT
295
(PROD_NO, PROD_DESC, PROD_PRICE, PROD_IN_STOCK) VALUES (4,'Acme E-Mail Client',39.99,240): INSERT INTO ACMEE.PRODUCT (PROD_NO, PROD_DESC, PROD_PRICE, PROD_IN_STOCK) VALUES (5,'Acme Office Suite',49.99,12): INSERT INTO ACMEE.PRODUCT (PROD_NO, PROD_PRICE, PROD_IN_STOCK) VALUES (6,69.99,678):
--------------------------------------------------------POPULATE CUSTOMER --------------------------------------------------------INSERT INTO ACMEE.CUSTOMER (cust_firstname, cust_lastname, cust_address) VALUES ('John Q.', 'Public', '111 1st St., San Jose, CA '):
--------------------------------------------------------POPULATE ORDER --------------------------------------------------------INSERT INTO ACMEE.ORDER (ord_date, ord_cust_no) VALUES (CURRENT DATE, 1): INSERT INTO ACMEE.ORDER (ord_date, ord_cust_no) VALUES (CURRENT DATE - 1 DAY, 1): --------------------------------------------------------POPULATE ORDER ITEM --------------------------------------------------------Insert into ACMEE.ORDER_ITEM (ORD_ITEM_ORD_NO, ORD_ITEM_PROD_NO,ORD_ITEM_QTY) VALUES(1,1,1): Insert into ACMEE.ORDER_ITEM (ORD_ITEM_ORD_NO, ORD_ITEM_PROD_NO,ORD_ITEM_QTY) VALUES(1,2,2): Insert into ACMEE.ORDER_ITEM (ORD_ITEM_ORD_NO, ORD_ITEM_PROD_NO,ORD_ITEM_QTY) VALUES(1,3,3): Insert into ACMEE.ORDER_ITEM (ORD_ITEM_ORD_NO, ORD_ITEM_PROD_NO,ORD_ITEM_QTY)
296
Insert into ACMEE.ORDER_ITEM (ORD_ITEM_ORD_NO, ORD_ITEM_PROD_NO,ORD_ITEM_QTY) VALUES(2,1,2): Insert into ACMEE.ORDER_ITEM (ORD_ITEM_ORD_NO, ORD_ITEM_PROD_NO,ORD_ITEM_QTY) VALUES(2,2,4): Insert into ACMEE.ORDER_ITEM (ORD_ITEM_ORD_NO, ORD_ITEM_PROD_NO,ORD_ITEM_QTY) VALUES(2,3,6): Insert into ACMEE.ORDER_ITEM (ORD_ITEM_ORD_NO, ORD_ITEM_PROD_NO,ORD_ITEM_QTY) VALUES(2,4,8): Insert into ACMEE.ORDER_ITEM (ORD_ITEM_ORD_NO, ORD_ITEM_PROD_NO,ORD_ITEM_QTY) VALUES(2,5,10):
297
CREATE TABLE ACMES.CUSTOMER ( CUST_NO INTEGER NOT NULL PRIMARY KEY, CUST_FIRSTNAME CHAR(20) NOT NULL, CUST_LASTNAME CHAR(20) NOT NULL, CUST_ADDRESS CHAR(30) ) ; CREATE UNIQUE INDEX ACMES.P_CUSTOMER ON ACMES.CUSTOMER (CUST_NO); --- PRODUCT -CREATE TABLE ACMES.PRODUCT ( PROD_NO INTEGER PROD_DESC PROD_PRICE PROD_IN_STOCK ) ;
NOT NULL PRIMARY KEY, CHAR(30) NOT NULL, DECIMAL(10,2) NOT NULL, INTEGER NOT NULL
CREATE UNIQUE INDEX ACMES.P_PRODUCT ON ACMES.PRODUCT (PROD_NO); --- ORDER -CREATE TABLE ACMES.ORDER
298
( ORD_NO
NOT NULL PRIMARY KEY , ORD_DATE DATE NOT NULL, ORD_CUST_NO INTEGER NOT NULL, FOREIGN KEY (ORD_CUST_NO) REFERENCES ACMES.CUSTOMER(CUST_NO) ON DELETE CASCADE ) ; CREATE UNIQUE INDEX ACMES.P_ORDER ON ACMES.ORDER (ORD_NO); CREATE INDEX ACMES.F_ORDER_1 ON ACMES.ORDER (ORD_CUST_NO); --- ORDER ITEM -CREATE TABLE ACMES.ORDER_ITEM ( ORD_ITEM_NO INTEGER NOT NULL PRIMARY KEY, ORD_ITEM_ORD_NO INTEGER NOT NULL, ORD_ITEM_PROD_NO INTEGER NOT NULL, ORD_ITEM_QTY INTEGER NOT NULL, FOREIGN KEY (ORD_ITEM_ORD_NO) REFERENCES ACMES.ORDER(ORD_NO) ON DELETE CASCADE, FOREIGN KEY (ORD_ITEM_PROD_NO) REFERENCES ACMES.PRODUCT(PROD_NO) ON DELETE CASCADE ) ; CREATE UNIQUE INDEX ACMES.P_ORDER_ITEM ON ACMES.ORDER_ITEM (ORD_ITEM_NO); CREATE INDEX ACMES.F_ORDER_ITEM_1 ON ACMES.ORDER_ITEM (ORD_ITEM_ORD_NO); CREATE INDEX ACMES.F_ORDER_ITEM_2 ON ACMES.ORDER_ITEM (ORD_ITEM_PROD_NO);
INTEGER
299
--- HI_CUST_NO --
CREATE TABLE ACMES.HI_CUST_NO ( HI_CUST_NO INTEGER NOT NULL ) ; INSERT INTO ACMES.HI_CUST_NO VALUES(1); --- HI_ORD_NO -CREATE TABLE ACMES.HI_ORD_NO ( HI_ORD_NO INTEGER NOT NULL ) ; INSERT INTO ACMES.HI_ORD_NO VALUES(1); --- Create Procedures ------Note that all CREATE PROCEDURE statements are within the prep BAT files for each procedure. This is due to the fact that the JAR file for the procedure must exist before the procedure can be defined to DB2
300
---- SQL LEVEL: ENHANCED (USES ENHANCED FEATURES) ----- NOTE: THE COLON (':') CHARACTER IS USED INSTEAD --OF THE SEMICOLON (';') CHARACTER FOR --TERMINATING COMMNANDS, DUE TO THE PRESENCE --OF CREATE TRIGGER STATEMENTS. ----IF THIS FILE IS SUBMITTED USING CLP, --ENSURE THAT THE TERMINATION CHARACTER IS --SET TO ':' as in the following: ---db2 -td: -vf ddle.txt -------------------------------------------------------CONNECT TO ACMEE: --------------------------------------------------------CREATE TABLES/INDEXES ----------------------------------------------------------- CUSTOMER --
--
CREATE TABLE ACMEE.CUSTOMER ( CUST_NO INTEGER NOT NULL PRIMARY KEY GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1, CACHE 10), CUST_FIRSTNAME CHAR(20) NOT NULL, CUST_LASTNAME CHAR(20) NOT NULL, CUST_ADDRESS CHAR(30) NOT NULL ) : CREATE UNIQUE INDEX ACMEE.P_CUSTOMER ON ACMEE.CUSTOMER (CUST_NO): --
301
-- PRODUCT --
NOT NULL PRIMARY KEY, CHAR(30) , DECIMAL(10,2) NOT NULL, INTEGER NOT NULL
CREATE UNIQUE INDEX ACMEE.P_PRODUCT ON ACMEE.PRODUCT (PROD_NO): --- ORDER -CREATE TABLE ACMEE.ORDER ( ORD_NO INTEGER
NOT NULL PRIMARY KEY GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1, CACHE 10), ORD_DATE DATE NOT NULL, ORD_CUST_NO INTEGER NOT NULL, FOREIGN KEY (ORD_CUST_NO) REFERENCES ACMEE.CUSTOMER(CUST_NO) ON DELETE CASCADE ) : CREATE UNIQUE INDEX ACMEE.P_ORDER ON ACMEE.ORDER (ORD_NO): CREATE INDEX ACMEE.F_ORDER_1 ON ACMEE.ORDER (ORD_CUST_NO): --- ORDER ITEM
302
--
CREATE TABLE ACMEE.ORDER_ITEM ( ORD_ITEM_NO INTEGER NOT NULL PRIMARY KEY GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1, CACHE 10), ORD_ITEM_ORD_NO INTEGER NOT NULL, ORD_ITEM_PROD_NO INTEGER NOT NULL, ORD_ITEM_QTY INTEGER NOT NULL, FOREIGN KEY (ORD_ITEM_ORD_NO) REFERENCES ACMEE.ORDER(ORD_NO) ON DELETE CASCADE, FOREIGN KEY (ORD_ITEM_PROD_NO) REFERENCES ACMEE.PRODUCT(PROD_NO) ON DELETE CASCADE ) : CREATE UNIQUE INDEX ACMEE.P_ORDER_ITEM ON ACMEE.ORDER_ITEM (ORD_ITEM_NO): CREATE INDEX ACMEE.F_ORDER_ITEM_1 ON ACMEE.ORDER_ITEM (ORD_ITEM_ORD_NO): CREATE INDEX ACMEE.F_ORDER_ITEM_2 ON ACMEE.ORDER_ITEM (ORD_ITEM_PROD_NO):
--------------------------------------------------------CREATE GLOBAL TEMP TABLES ----- THESE ARE USED BY THE AFTER-INSERT TRIGGERS THAT --- ARE DEFINED BELOW. THE TRIGGERS INSERT THE PRIMARY --- KEY VALUE OF THE NEW ROW INTO THE GLOBAL TEMP --- TABLE TO ALLOW IT TO BE ACCESSED BY THE CALLING --- APP. ----------------------------------------------------------CREATE TABLE ACMEE.GTT_CUST_NO (
303
CUST_NO ):
INTEGER
NOT NULL
CREATE TABLE ACMEE.GTT_ORDER_NO ( ORDER_NO INTEGER NOT NULL ): --------------------------------------------------------CREATE TRIGGERS --------------------------------------------------------CREATE TRIGGER ACMEE.CUST_IA AFTER INSERT ON ACMEE.CUSTOMER REFERENCING NEW AS NEWROW FOR EACH ROW MODE DB2SQL BEGIN ATOMIC DELETE FROM ACMEE.GTT_CUST_NO; INSERT INTO ACMEE.GTT_CUST_NO (CUST_NO) VALUES (NEWROW.CUST_NO); END: CREATE TRIGGER ACMEE.ORD_IA AFTER INSERT ON ACMEE.ORDER REFERENCING NEW AS NEWROW FOR EACH ROW MODE DB2SQL BEGIN ATOMIC DELETE FROM ACMEE.GTT_ORDER_NO; INSERT INTO ACMEE.GTT_ORDER_NO (ORDER_NO) VALUES (NEWROW.ORD_NO); END: --------------------------------------------------------POPULATE PRODUCT TABLE --------------------------------------------------------INSERT INTO ACMEE.PRODUCT (PROD_NO, PROD_DESC, PROD_PRICE, PROD_IN_STOCK) VALUES (1,'Acme Word Processor',19.99,200): INSERT INTO ACMEE.PRODUCT (PROD_NO, PROD_DESC, PROD_PRICE, PROD_IN_STOCK) VALUES (2,'Acme Speadsheet',29.99,12):
304
INSERT INTO ACMEE.PRODUCT (PROD_NO, PROD_DESC, PROD_PRICE, PROD_IN_STOCK) VALUES (3,'Acme Presentation Graphics',39.99,101): INSERT INTO ACMEE.PRODUCT (PROD_NO, PROD_DESC, PROD_PRICE, PROD_IN_STOCK) VALUES (4,'Acme E-Mail Client',49.99,240): INSERT INTO ACMEE.PRODUCT (PROD_NO, PROD_DESC, PROD_PRICE, PROD_IN_STOCK) VALUES (5,'Acme Office Suite',59.99,12): INSERT INTO ACMEE.PRODUCT (PROD_NO, PROD_PRICE, PROD_IN_STOCK) VALUES (6,69.99,678):
--------------------------------------------------------POPULATE CUSTOMER --------------------------------------------------------INSERT INTO ACMEE.CUSTOMER (cust_firstname, cust_lastname, cust_address) VALUES ('John Q.', 'Public', '111 1st St., San Jose, CA '):
--------------------------------------------------------POPULATE ORDER --------------------------------------------------------INSERT INTO ACMEE.ORDER (ord_date, ord_cust_no) VALUES (CURRENT DATE, 1): INSERT INTO ACMEE.ORDER (ord_date, ord_cust_no) VALUES (CURRENT DATE - 1 DAY, 1): --------------------------------------------------------POPULATE ORDER ITEM --------------------------------------------------------Insert into ACMEE.ORDER_ITEM (ORD_ITEM_ORD_NO, ORD_ITEM_PROD_NO,ORD_ITEM_QTY) VALUES(1,1,1): Insert into ACMEE.ORDER_ITEM (ORD_ITEM_ORD_NO, ORD_ITEM_PROD_NO,ORD_ITEM_QTY) VALUES(1,2,2): Insert into ACMEE.ORDER_ITEM (ORD_ITEM_ORD_NO, ORD_ITEM_PROD_NO,ORD_ITEM_QTY)
305
VALUES(1,3,3): Insert into ACMEE.ORDER_ITEM (ORD_ITEM_ORD_NO, ORD_ITEM_PROD_NO,ORD_ITEM_QTY) VALUES(1,4,4): Insert into ACMEE.ORDER_ITEM (ORD_ITEM_ORD_NO, ORD_ITEM_PROD_NO,ORD_ITEM_QTY) VALUES(1,5,5):
Insert into ACMEE.ORDER_ITEM (ORD_ITEM_ORD_NO, ORD_ITEM_PROD_NO,ORD_ITEM_QTY) VALUES(2,1,2): Insert into ACMEE.ORDER_ITEM (ORD_ITEM_ORD_NO, ORD_ITEM_PROD_NO,ORD_ITEM_QTY) VALUES(2,2,4): Insert into ACMEE.ORDER_ITEM (ORD_ITEM_ORD_NO, ORD_ITEM_PROD_NO,ORD_ITEM_QTY) VALUES(2,3,6): Insert into ACMEE.ORDER_ITEM (ORD_ITEM_ORD_NO, ORD_ITEM_PROD_NO,ORD_ITEM_QTY) VALUES(2,4,8): Insert into ACMEE.ORDER_ITEM (ORD_ITEM_ORD_NO, ORD_ITEM_PROD_NO,ORD_ITEM_QTY) VALUES(2,5,10):
Insert into ACMEE.ORDER_ITEM (ORD_ITEM_ORD_NO, ORD_ITEM_PROD_NO,ORD_ITEM_QTY) VALUES(2,6,22): --------------------------------------------------------Create Temporary Table Used For Summary Query--------------------------------------------------------create table acmee.order_item_summ ( PROD_DESC CHAR(30) , QTY_1_TO_5 CHAR(1) NOT NULL, QTY_6_TO_10 CHAR(1) NOT NULL, QTY_11_PLUS CHAR(1) NOT NULL ):
306
The simple version of the samples was designed to work on DB2 UDB for OS/390 Version 5. The stored procedure defintitions therefore take the form of INSERT statements into the SYSIBM.SYSPROCEDURES catalog table. The enhanced version was intended for DB2 UDB for OS/390 Version 6, and therefore uses the new CREATE PROCEDURE statements.
B.2.1.1 Simple stored procedure defintions The stored procedure definitions for each of the simple samples follow.
ACMECOS
---------------------------------------------------------------SYSPROCEDURES INSERT FOR SG24-5945 ----- Package ACMECOS ----- SQL Type: COBOL/static SQL --- Platform: OS/390 --- SQL Level: Standard ------------------------------------------------------------------ Delete old rows if they exist -DELETE FROM SYSIBM.SYSPROCEDURES WHERE PROCEDURE LIKE 'CS%'; --- Add_customer --
307
INSERT INTO SYSIBM.SYSPROCEDURES (PROCEDURE,AUTHID,LUNAME,LOADMOD,LINKAGE,COLLID, LANGUAGE,ASUTIME,STAYRESIDENT,IBMREQD, RUNOPTS, PARMLIST, RESULT_SETS,WLM_ENV,PGM_TYPE, EXTERNAL_SECURITY,COMMIT_ON_RETURN) VALUES( 'CS_ADD_CUSTOMER', '', '', 'ADDCUST', 'N', 'ACMECOS', 'COBOL', 900, '','N', '', 'CHAR(20) IN, CHAR(20) IN, CHAR(30) IN, INTEGER OUT, CHAR(40) OUT, CHAR(240) OUT', 0,'WLM_JAVA_DB21','S','N','N' );
--- Check all OK -SELECT * FROM SYSIBM.SYSPROCEDURES WHERE PROCEDURE LIKE 'CS%';
ACMEJOS
---------------------------------------------------------------SYSPROCEDURES INSERT FOR SG24-5945 ----- Package ACMEJOS ----- SQL Type: JDBC --- Platform: OS/390 --- SQL Level: Standard ------------------------------------------------------------------ Delete old rows if they exist -DELETE FROM SYSIBM.SYSPROCEDURES WHERE PROCEDURE LIKE 'JS%'; --- Add_customer -INSERT INTO SYSIBM.SYSPROCEDURES (PROCEDURE,AUTHID,LUNAME,LOADMOD,LINKAGE,COLLID,
308
LANGUAGE,ASUTIME,STAYRESIDENT,IBMREQD, RUNOPTS, PARMLIST, RESULT_SETS,WLM_ENV,PGM_TYPE, EXTERNAL_SECURITY,COMMIT_ON_RETURN) VALUES( 'JS_ADD_CUSTOMER', '', '', '', 'N', 'DSNJDBC', 'COMPJAVA', 900, '','N', 'ACMEJOS/Add_customer.add_customer', 'CHAR(20) IN, CHAR(20) IN, CHAR(30) IN, INTEGER OUT, CHAR(40) OUT, CHAR(240) OUT', 0,'WLM_JAVA_DB21','S','N','N' ); --- Check all OK -SELECT * FROM SYSIBM.SYSPROCEDURES WHERE PROCEDURE LIKE 'JS%';
ACMESOS
---------------------------------------------------------------SYSPROCEDURES INSERT FOR SG24-5945 ----- Package ACMESOS ----- SQL Type: SQLJ --- Platform: OS/390 --- SQL Level: Standard ------------------------------------------------------------------ Delete old rows if they exist -DELETE FROM SYSIBM.SYSPROCEDURES WHERE PROCEDURE LIKE 'SS%'; --- Add_customer -INSERT INTO SYSIBM.SYSPROCEDURES (PROCEDURE,AUTHID,LUNAME,LOADMOD,LINKAGE,COLLID, LANGUAGE,ASUTIME,STAYRESIDENT,IBMREQD, RUNOPTS, PARMLIST,
309
RESULT_SETS,WLM_ENV,PGM_TYPE, EXTERNAL_SECURITY,COMMIT_ON_RETURN) VALUES( 'SS_ADD_CUSTOMER', '', '', '', 'N', 'ACMESOS', 'COMPJAVA', 900, '','N', 'ACMESOS/Add_customer.add_customer', 'CHAR(20) IN, CHAR(20) IN, CHAR(30) IN, INTEGER OUT, CHAR(40) OUT, CHAR(240) OUT', 0,'WLM_JAVA_DB21','S','N','N' );
--- Check all OK -SELECT * FROM SYSIBM.SYSPROCEDURES WHERE PROCEDURE LIKE 'SS%';
ACMEBOS
---------------------------------------------------------------SYSPROCEDURES INSERT FOR SG24-5945 ----- Package ACMEBOS ----- SQL Type: SQLJ & JDBC Combined --- Platform: OS/390 --- SQL Level: Standard ------------------------------------------------------------------ Delete old rows if they exist -DELETE FROM SYSIBM.SYSPROCEDURES WHERE PROCEDURE LIKE 'BS%'; --- Add_customer -INSERT INTO SYSIBM.SYSPROCEDURES (PROCEDURE,AUTHID,LUNAME,LOADMOD,LINKAGE,COLLID, LANGUAGE,ASUTIME,STAYRESIDENT,IBMREQD, RUNOPTS, PARMLIST, RESULT_SETS,WLM_ENV,PGM_TYPE, EXTERNAL_SECURITY,COMMIT_ON_RETURN) VALUES(
310
'BS_ADD_CUSTOMER', '', '', '', 'N', 'ACMEBOS', 'COMPJAVA', 900, '','N', 'ACMEBOS/Add_customer.add_customer', 'CHAR(20) IN, CHAR(20) IN, CHAR(30) IN, INTEGER OUT, CHAR(40) OUT, CHAR(240) OUT', 0,'WLM_JAVA_DB21','S','N','N' ); --- Check all OK -SELECT * FROM SYSIBM.SYSPROCEDURES WHERE PROCEDURE LIKE 'BS%';
B.2.1.2 Enhanced stored procedure definitons The stored procedure definitions for each of the enhanced samples follow.
ACMECOE
---------------------------------------------------------------CREATE PROCEDURES FOR SG24-5945 ----- Package ACMECOE ----- SQL Type: COBOL --- Platform: OS/390 --- SQL Level: Enhanced ------------------------------------------------------------------ Drop procedures if they exist -drop PROCEDURE ACMECOE.ADD_CUSTOMER RESTRICT; drop PROCEDURE ACMECOE.ADD_ORDER RESTRICT; drop PROCEDURE ACMECOE.ADD_CUST_ORDER RESTRICT; --- Add_customer -CREATE PROCEDURE ACMECOE.ADD_CUSTOMER ( IN FIRSTNAME CHAR(20),
311
IN LASTNAME CHAR(20), IN ADDRESS CHAR(30), OUT CUSTNO INTEGER, OUT MARK CHAR(40), OUT MARK_ERROR_TEXT CHAR(200) ) FENCED MODIFIES SQL DATA LANGUAGE COBOL EXTERNAL NAME ADDCUST PARAMETER STYLE DB2SQL COLLID ACMECOE WLM ENVIRONMENT WLMJAVADBZ2 RESULT SETS 0 PROGRAM TYPE SUB; --- Add_order -CREATE PROCEDURE ACMECOE.ADD_ORDER ( IN CUSTNO INTEGER, IN NUM_ITEMS INTEGER, IN ORDERDETS CHAR(80), OUT ORDERNO INTEGER, OUT MARK CHAR(40), OUT MARK_ERROR_TEXT CHAR(200) ) FENCED MODIFIES SQL DATA LANGUAGE COBOL EXTERNAL NAME ADDORD PARAMETER STYLE DB2SQL COLLID ACMECOE WLM ENVIRONMENT WLMJAVADBZ2 RESULT SETS 0 PROGRAM TYPE SUB; --- Add_cust_order -CREATE PROCEDURE ACMECOE.ADD_CUST_ORDER ( IN FIRSTNAME CHAR(20), IN LASTNAME CHAR(20), IN ADDRESS CHAR(30), IN NUM_ITEMS INTEGER,
312
IN ORDERDETS CHAR(100), OUT CUSTNO INTEGER, OUT ORDERNO INTEGER, OUT MARK CHAR(40), OUT MARK_ERROR_TEXT CHAR(200) ) FENCED MODIFIES SQL DATA LANGUAGE COBOL EXTERNAL NAME ADDCORD PARAMETER STYLE DB2SQL COLLID ACMECOE WLM ENVIRONMENT WLMJAVADBZ2 RESULT SETS 0 PROGRAM TYPE SUB;
ACMEJOE
---------------------------------------------------------------CREATE PROCEDURES FOR SG24-5945 ----- Package ACMEJOE ----- SQL Type: JDBC --- Platform: OS/390 --- SQL Level: Enhanced ----- NOTE: Java package * class name duplicated in RUNOPTS --due to current drivers ignoring EXTERNAL NAME. --This should not be required in general release of --the code, so RUNOPTS can be removed at that time. ------------------------------------------------------------------ --drop procedures if they exist --
313
drop PROCEDURE ACMEJOE.ADD_CUSTOMER RESTRICT; drop PROCEDURE ACMEJOE.ADD_ORDER RESTRICT; drop PROCEDURE ACMEJOE.QUERY_OI_SUMM RESTRICT; --- Add_customer -CREATE PROCEDURE ACMEJOE.ADD_CUSTOMER ( IN FIRSTNAME CHAR(20), IN LASTNAME CHAR(20), IN ADDRESS CHAR(30), OUT CUSTNO INTEGER, OUT MARK CHAR(40), OUT MARK_ERROR_TEXT CHAR(200) ) FENCED MODIFIES SQL DATA LANGUAGE COMPJAVA EXTERNAL NAME 'acmejoe/Add_customer.add_customer' PARAMETER STYLE JAVA COLLID DSNJDBC WLM ENVIRONMENT WLMJAVADBZ2 RUN OPTIONS 'acmejoe/Add_customer.add_customer' DYNAMIC RESULT SETS 0 PROGRAM TYPE SUB; --- Add_order -CREATE PROCEDURE ACMEJOE.ADD_ORDER ( IN CUSTNO INTEGER, IN ORDERDETS CHAR(100), OUT ORDERNO INTEGER, OUT MARK CHAR(40), OUT MARK_ERROR_TEXT CHAR(200) ) FENCED MODIFIES SQL DATA LANGUAGE COMPJAVA EXTERNAL NAME 'ACMEJOE/Add_order.add_order' PARAMETER STYLE JAVA COLLID DSNJDBC WLM ENVIRONMENT WLMJAVADBZ2 RUN OPTIONS 'ACMEJOE/Add_order.add_order'
314
DYNAMIC RESULT SETS 0 PROGRAM TYPE SUB; --- Query Order item summary -CREATE PROCEDURE ACMEJOE.QUERY_OI_SUMM ( IN IN_CUST_NO CHAR(10), IN IN_ORDER_NO CHAR(10), OUT MARK CHAR(40), OUT MARK_ERROR_TEXT CHAR(200) ) EXTERNAL NAME 'ACMEJOE/Query_oi_summ.query_oi_summ' RESULT SETS 1 LANGUAGE COMPJAVA PARAMETER STYLE JAVA COLLID DSNJDBC WLM ENVIRONMENT WLMJAVADBZ2 RUN OPTIONS 'ACMEJOE/Query_oi_summ.query_oi_summ' FENCED NO DBINFO NULL CALL MODIFIES SQL DATA PROGRAM TYPE SUB; --- Check all OK -SELECT * FROM SYSIBM.SYSroutines WHERE schema = 'ACMEJOE';
ACMESOE
---------------------------------------------------------------CREATE PROCEDURES FOR SG24-5945 ----- Package ACMESOE ----- SQL Type: SQLJ --- Platform: OS/390 --- SQL Level: Enhanced ----- NOTE: Java package & class name duplicated in RUNOPTS --due to current drivers ignoring EXTERNAL NAME. --This should not be required in general release of --the code, so RUNOPTS can be removed at that time. --
315
----------------------------------------------------------------- Drop procedures if they exist -drop PROCEDURE ACMESOE.ADD_CUSTOMER RESTRICT; drop PROCEDURE ACMESOE.ADD_ORDER RESTRICT; drop PROCEDURE ACMESOE.QUERY_OI_SUMM RESTRICT; --- Add_customer -CREATE PROCEDURE ACMESOE.ADD_CUSTOMER ( IN FIRSTNAME CHAR(20), IN LASTNAME CHAR(20), IN ADDRESS CHAR(30), OUT CUSTNO INTEGER, OUT MARK CHAR(40), OUT MARK_ERROR_TEXT CHAR(200) ) FENCED MODIFIES SQL DATA LANGUAGE COMPJAVA EXTERNAL NAME 'ACMESOE.Add_customer.add_customer' PARAMETER STYLE JAVA COLLID ACMESOE WLM ENVIRONMENT WLMJAVADBZ2 RUN OPTIONS 'ACMESOE.Add_customer.add_customer' DYNAMIC RESULT SETS 0 PROGRAM TYPE SUB; --- Add_order -CREATE PROCEDURE ACMESOE.ADD_ORDER ( IN CUSTNO INTEGER, IN ORDERDETS CHAR(100), OUT ORDERNO INTEGER, OUT MARK CHAR(40), OUT MARK_ERROR_TEXT CHAR(200) ) FENCED MODIFIES SQL DATA
316
LANGUAGE COMPJAVA EXTERNAL NAME 'ACMESOE.Add_order.add_order' PARAMETER STYLE JAVA COLLID ACMESOE WLM ENVIRONMENT WLMJAVADBZ2 RUN OPTIONS 'ACMESOE.Add_order.add_order' DYNAMIC RESULT SETS 0 PROGRAM TYPE SUB; --- Query Order item summary -CREATE PROCEDURE ACMESOE.QUERY_OI_SUMM ( IN IN_CUST_NO CHAR(10), IN IN_ORDER_NO CHAR(10), OUT MARK CHAR(40), OUT MARK_ERROR_TEXT CHAR(200) ) EXTERNAL NAME 'ACMESOE.Query_oi_summ.query_oi_summ' RESULT SETS 1 LANGUAGE COMPJAVA PARAMETER STYLE JAVA COLLID ACMESOE WLM ENVIRONMENT WLMJAVADBZ2 RUN OPTIONS 'ACMESOE.Query_oi_summ.query_oi_summ' FENCED NO DBINFO NULL CALL MODIFIES SQL DATA PROGRAM TYPE SUB; --- Check all OK -SELECT * FROM SYSIBM.SYSROUTINES WHERE schema = 'ACMESOE';
B.2.2 DB2 UDB for AIX and Windows stored procedure definitions
Due to the nature of the process, the stored procedure definitions on the AIX and Windows platforms have to be dropped and redefined as part of program preparation (see 7.3.1, NT / AIX JDBC program preparation process on
317
page 144 and 7.3.2, NT / AIX SQLJ program preparation process on page 149 for an explanation of why). For this reason, the stored procedure definitions for these platfoms can be found in B.5.2, AIX program preparation scripts on page 318 and B.5.3, NT program preparation scripts on page 321.
318
B.5.2.1 Basic shell preparation of a JDBC stored procedure The following demonstrates using a script to compile, JAR, and install the JAR. If you choose not to use a JAR then you need to copy the resultant Java classes to the function directory as performed in the shipped samples.
prep.sh
echo off cls if [ $1 ] then PKG=$1 else PKG=ACMEJUS fi if [ $2 ] then PGM=$2 else PGM=Add_customer fi JARHOME=/u/db2inst3/sqllib/function/jar echo "setting PKG to $PKG" echo "setting PGM to $PGM"
echo "Beginning JAR" jar cvf ${PKG}.jar ${PKG}/*.class echo "Updating DB2 environment"
if [ -f ${JARHOME}/${PKG}/${PKG}.jar ] then echo "found ${JARHOME}/${PKG}/${PKG}.jar " db2 -tvf replace_jar.sql else echo "failed find of ${JARHOME}/${PKG}/${PKG}.jar " db2 -tvf install_jar.sql db2 -tvf define_sp_${PGM}.sql
319
fi
define_sp_Add_customer.sql
--------------------------------------------------------------------------------- SQL statements to define or redefine stored procedure ----- Note that JAR file must exist before CREATE PROCEDURE is executed, --- which is why we have put it in here rather than in the main DDL file. ----------------------------------------------------------------------------------- Connect to database -CONNECT TO ACMES; --- Drop procedure and JAR files if they exist -DROP PROCEDURE ACMEJUS.Add_customer; CALL SQLJ.REMOVE_JAR('ACMEJUS.ACMEJUS'); --- Define jar file to DB2 -call sqlj.install_jar ('file:/data/db2inst7/apps/ACMEJUS/ACMEJUS.jar','ACMEJUS.ACMEJUS'); --- Create procedure --- External name is in format ' " CREATE PROCEDURE ACMEJUS.Add_customer ( IN IN_CUST_FIRSTNAME CHAR(20), IN IN_CUST_LASTNAME CHAR(20), IN IN_CUST_ADDRESS CHAR(30), OUT OUT_CUST_NO INT,
320
OUT MARK CHAR(40), OUT MARK_ERROR_TEXT CHAR(200) ) EXTERNAL NAME 'ACMEJUS.ACMEJUS:ACMEJUS.Add_customer.add_customer' RESULT SETS 0 LANGUAGE JAVA PARAMETER STYLE JAVA FENCED NO DBINFO NULL CALL MODIFIES SQL DATA ;
The batch file prep.bat invokes DB2 UDB in a batch mode to define the stored procedure and to install the JAR file.
Prep.bat
echo off cls echo Preparing ACMEJNS\Add_customer.java... echo echo Beginning Java compile... javac ACMEJNS\Add_customer.java echo Beginning JAR... jar cvf ACMEJNS.jar ACMEJNS\Add_customer.class echo Updating DB2 environment... db2 -tvf define_sp.sql echo Preparation complete!
321
Define_sp.sql
--------------------------------------------------------------------------------- SQL statements to define or redefine stored procedure ----- Note that JAR file must exist before CREATE PROCEDURE is executed, --- which is why we have put it in here rather than in the main DDL file. ----------------------------------------------------------------------------------- Connect to database -CONNECT TO ACMES; --- Drop procedure and JAR files if they exist -DROP PROCEDURE ACMEJNS.Add_customer; CALL SQLJ.REMOVE_JAR('ACMEJNS.ACMEJNS'); --- Define jar file to DB2 -CALL SQLJ.INSTALL_JAR('file:S:\Kirk\Samples\Code - Stored Procedures\JDBC\NT\acmejns\acmejns.jar','ACMEJNS.ACMEJNS'); --- Create procedure --- External name is in format ' " CREATE PROCEDURE ACMEJNS.Add_customer ( IN IN_CUST_FIRSTNAME CHAR(20), IN IN_CUST_LASTNAME CHAR(20), IN IN_CUST_ADDRESS CHAR(30), OUT OUT_CUST_NO INT, OUT MARK CHAR(40), OUT MARK_ERROR_TEXT CHAR(200)
322
) EXTERNAL NAME 'ACMEJNS.ACMEJNS:ACMEJNS.Add_customer.add_customer' RESULT SETS 0 LANGUAGE JAVA PARAMETER STYLE JAVA FENCED NO DBINFO NULL CALL MODIFIES SQL DATA ; CALL SQLJ.REFRESH_CLASSES(VOID);
B.5.3.2 SQLJ stored procedure preparation The following shows a complex preparation script for SQLJ stored procedures on NT.
Highlights of this script include: The SQLJ preparation step includes checking valid syntax against the DBMS (by arguing the userid/password and the URL) The automatic JAVA compile step is turned off during the SQLJ step. The class files are collected into the JAR once, after everything has been completed. Error checking within the batch file has been inserted where feasible.
Prep.bat
echo off cls echo Beginning SQLJ precompile/compile...Query_oi_summ sqlj -user=drdares2/drdares2 -url=jdbc:db2:ACMEE -compile=false -status ACMESNE\Query_oi_summ.sqlj if errorlevel 1 goto error echo Begin javac.... javac ACMESNE\Query_oi_summ.java if errorlevel 1 goto error echo Beginning profile customisation... db2profc -url=jdbc:db2:ACMEE -prepoptions="package using ACMESNE" ACMESNE\Query_oi_summ_SJProfile0 echo Beginning SQLJ precompile/compile...Add_customer
323
sqlj -user=drdares2/drdares2 -url=jdbc:db2:ACMEE -compile=false -status ACMESNE\Add_customer.sqlj if errorlevel 1 goto error javac ACMESNE\Add_customer.java if errorlevel 1 goto error echo Beginning profile customisation... db2profc -url=jdbc:db2:ACMEE ACMESNE\Add_customer_SJProfile0 if errorlevel 1 goto error echo Beginning JAR... jar cvf ACMESNE.jar ACMESNE\Defi*.class ACMESNE\Qu*.class ACMESNE\Qu*.ser ACMESNE\Add_c*.ser ACMESNE\Add_c*.class if errorlevel 1 goto error echo Updating DB2 environment... db2 -tvf define_acmesne.sql if errorlevel 1 goto error echo Preparation complete! goto exit :error echo Problem encountered!!! :exit
define_acmesne.sql
--------------------------------------------------------------------------------- SQL statements to define or redefine stored procedure ----- Note that JAR file must exist before CREATE PROCEDURE is executed, --- which is why we have put it in here rather than in the main DDL file. ----
324
-------------------------------------------------------------------------------- Connect to database -CONNECT TO ACMEE ; drop PROCEDURE ACMESNE.Query_oi_summ drop PROCEDURE ACMESNE.Add_customer; ;
CREATE PROCEDURE ACMESNE.Query_oi_summ ( IN IN_CUST_NO CHAR(10), IN IN_ORDER_NO CHAR(10), OUT MARK CHAR(40), OUT MARK_ERROR_TEXT CHAR(200) ) EXTERNAL NAME 'ACMESNE.ACMESNE:ACMESNE.Query_oi_summ.query_oi_summ' RESULT SETS 1 LANGUAGE JAVA PARAMETER STYLE JAVA FENCED NO DBINFO NULL CALL MODIFIES SQL DATA ; CREATE PROCEDURE ACMESNE.Add_customer ( IN IN_CUST_FIRSTNAME CHAR(20), IN IN_CUST_LASTNAME CHAR(20), IN IN_CUST_ADDRESS CHAR(30), OUT OUT_CUST_NO INT, OUT MARK CHAR(40), OUT MARK_ERROR_TEXT CHAR(200) ) EXTERNAL NAME 'ACMESNE.ACMESNE:ACMESNE.Add_customer.add_customer' RESULT SETS 0 LANGUAGE JAVA PARAMETER STYLE JAVA
325
call sqlj.refresh_classes(void);
B.5.3.3 SQLJ stored procedure preparation - parameter driven Included here is parameter-driven preparation batch file for SQLJ stored procedures on NT. This might be useful for programmers planning to build one generic script to be applied to many stored procedures.
Prep.bat
echo off REM REM GENERIC SQLJ PREP ROUTINE REM REM File <package>.sql must exist, containing necessary CREATE PROCEDURE REM and REFRESH_JAR commands rem rem Example call: prep Add_customer ACMEBNS ACMEBNS ACMES ACMES DEFINE
cls echo. echo SQLJ Prog Prep script echo. echo Input parms: echo Class name = echo Java Package\subdirectory name = echo DB2 Package name = echo Database name = echo Table qualifier = echo Action = echo.
%1 %2 %3 %4 %5 %6
REM Check Valid Action if %6 == DEFINE goto cont1 if %6 == REFRESH goto cont2 echo Error: Action must be DEFINE or REFRESH. goto error :cont1
326
REM Check SQL define file exists if exist define_%2.sql goto cont3 echo Error: file define_%2.sql not found.... echo File must exist, and contain the necessary SQL CREATE PROCEDURE and echo REFRESH_JAR commands... echo. goto error :cont2 REM Check SQL refresh file exists if exist refresh_%2.sql goto cont3 echo Error: file refresh_%2.sql not found.... echo File must exist, and contain the necessary REPLACE_JAR commands... echo. goto error :cont3 echo Preparing %2\%1... echo. echo Beginning SQLJ precompile/compile... set CLASSPATH=.\%2;%CLASSPATH% echo start sqlj compile sqlj -compile=false %2\%1.sqlj if errorlevel 1 goto error echo start javac compile javac %2\%1.java if errorlevel 1 goto error echo Beginning profile customisation... db2profc -prepoptions="qualifier %5 package using %3" -url=jdbc:db2:%4 %2\%1_SJProfile0 if errorlevel 1 goto error echo Beginning JAR... jar cvf %2.jar %2\*.class %2\*.ser if errorlevel 1 goto exit echo Updating DB2 environment... if %6 == DEFINE db2 -tvf define_%2.sql if %6 == REFRESH db2 -tvf refresh_%2.sql
327
echo Preparation complete! goto exit :error echo Problem encountered!!! :exit
328
Stored procedures address space entries are required in the RACF started procedures table. The associated RACF user ID and group name do not need to match those used for the DB2 address spaces, but they must be authorized to run the call attachment facility (for the DB2-established stored procedure address space) or RRSAF (for WLM-established stored procedure address spaces).
329
Changing the RACF started-procedures table: To change the RACF started-procedures table (ICHRIN03), change, reassemble, and link edit the resulting object code to MVS.
330
WLM-established stored procedure address spaces are required if you wish to write Java stored procedures. You cannot run Java stored procedures in a DB2 established stored procedure address space. Member DSNTIJMV of data set DSN610.SDSNSAMP contains sample JCL procedures for starting WLM-established address spaces. This will have to be modified for the JAVA support. Define WLM application environments for groups of JAVA stored procedures and associate a JCL start-up procedure with each application environment.
331
332
In order for all systems in a sysplex to process with an active service policy, they must all be able to access a service policy. They all access the policy from a WLM couple data set. To use workload management, you must allocate a WLM couple data set, define it to the sysplex, and install your service definition onto it. You can allocate the WLM couple data set from the application. Only one service definition can be installed on the WLM couple data set. MVS partitioned data set (PDS) You do not need to preallocate the data sets. You specify a data set name, and the application allocates it for you. You can save one service definition per MVS PDS.
Note
If you use customized data sets in your installation, or if you use DFSMS, you can use WLM application exits IWMAREX1 and IWMAREX2 to specify those changes. The data set userid.WLM.SAVExx (where userid is the TSO ID running the application and xx is some numeric value such as SAVE01) is allocated by the WLM application for recovery and is deleted by WLM upon exiting the application. This naming convention should therefore not be used for a new service definition.
If you have different data set conventions for your IPCS data sets, or if you use storage managed data sets, you should use the WLM application exits IWMAREX1 and IWMAREX2. Within a workload, you group work with similar performance characteristics into service classes; for example:
333
Performance goals Resource requirements Business importance to the installation Because some work may have variable resource requirements, you can define multiple periods for a service class. Periods are a way of defining different goals for work depending on the amount of resources the work consumes. Typically, periods are used to give shorter transactions more aggressive goals and to give longer running work of the same type less aggressive goals. If you have multiple periods, each period except the last has a duration. Duration is the amount of resources, in service units, that the work consumes before it is switched to the goals of the next period. You can also group work into a service class based on resource requirements. If you have a group of batch work that can consume vast amounts of resources, and you want to limit it, you can define a service class and assign it to a resource group with a maximum amount of capacity. If the work exceeds that capacity, workload management slows the execution rate. Also, if a certain group of work needs a minimum amount of processor capacity, you can set up a service class and assign it to a resource group. Classification rules are the rules workload management uses to associate a performance goal and/or a resource group with work by associating incoming work with a service class. Optionally, classification rules can also associate incoming work with a report class, similar to a report performance group. Classification rules work in much the same way as the IEAICSxx PARMLIB member in compatibility mode (except that classification rules are more flexible). The classification rules for a subsystem are specified in terms of transaction qualifiers such as job name or transaction class. These qualifiers identify groups of transactions that should have the same performance goals and importance. The attributes of incoming work are compared to these qualifiers and, if there is a match, the rule is used to assign a service class to the work. A subsystem can also have a default class for work that does not match any of the rules.
334
creating a stored procedure in a sensitive WLM environment, DB2 invokes RACF to determine if the user is allowed to create stored procedures in the specified WLM environment. The WLM ENVIRONMENT keyword on the CREATE PROCEDURE statement (for Version 6) or the WLM_ENV column of SYSIBM.SYSPROCEDURES for Version 5) identifies the WLM environment to use for running a given stored procedure. Attempts to create a procedure fail if the user is not properly authorized. DB2 performs a resource authorization check using the DSNR RACF class as follows: In a DB2 data sharing environment, DB2 uses the RACF resource name: db2_groupname.WLMENV.wlm_environment. In a non-data sharing environment, DB2 checks the RACF resource name: db2_subsytem_id.WLMENV.wlm_environment. The RACF RDEFINE command can be used to create RACF profiles that prevent users from creating stored procedures and user-defined functions in sensitive WLM environments. For example, you can prevent all users on DB2 subsystem DB2A (non-data sharing) from creating a stored procedure or user-defined function in the WLM environment named PAYROLL:
RDEFINE DSNR (DB2A.WLMENV.PAYROLL) UACC(NONE)
The RACF PERMIT command authorizes a user to create a stored procedure or user-defined function in a WLM environment. For example, you can authorize a DB2 user (DB2USER1) to create stored procedures on DB2 subsystem DB2A (non-data sharing) in the WLM environment named WLMENV1.
PERMIT DB2A.WLMENV.WLMENV1 CLASS(DSNR) ID(DB2USER1) ACCESS(READ)
You must define a RACF user IDs for DB2 stored procedure started tasks as mention in the RRS section. You must associate each of these address spaces with a RACF user ID. Each of them can also be assigned a RACF group name.
335
with the MVS command d wlm. This will give you the active service policy and the related service definition name.
D WLM
HQX1900------------------ SDSF PRIMARY OPTION MENU -- COMMAND ISSUED COMMAND INPUT ===> /d wlm SCROLL ===> PAGE RESPONSE=SC53 IWM025I 12.00.02 WLM DISPLAY 790 ACTIVE WORKLOAD MANAGEMENT SERVICE POLICY NAME: SPSTPC ACTIVATED: 2000/03/10 AT: 11:42:37 BY: DB2RES3 FROM: SC61 DESCRIPTION: serv pol for db2 stor proc resid RELATED SERVICE DEFINITION NAME: DB2JODBA INSTALLED: 2000/03/10 AT: 11:41:49 BY: DB2RES3 FROM: SC61 WLM VERSION LEVEL: LEVEL008
To set up your application environment definition, start up the WLM ISPF panels with TSO command WLM. Follow these steps to define a new application environment for your Java stored procedure. 1. Select option 2; Extract definition from WLM couple data set, from the Choose Service Definition Panel. 2. Select option 9; Application Environments, from the Definition Menu Panel. 3. Select option 1; create in the Action column from the Application Environment Selection List Panel. 4. PF3 to get back to the Definition Menu Panel. 5. Move the cursor to Utilities; on top of this panel, select option: 1. Install definition and press Enter. 6. Move the cursor to Utilities; on top of this panel, select option: 3. Activate service policy, and press Enter. 7. Select Policy to activate and press Enter. Here is a sample WLM Application Environment Definition:
Appl Environment Name . . WLMJAVADB21 Description . . . . . . . Java application for DB21 Subsystem type . . . . . DB2 Procedure name . . . . . DB21JAVA Start parameters . . . . APPLENV=CC51WLM1,NUMTCB=20,DB2SSN=&IWMSSNM Limit on starting server address spaces for a subsystem instance 1 1. No limit
336
2. 3.
Single address space per system Single address space per sysplex
Verify that you have a DB2 workload defined, service class for DDF, and classification rules defined to WLM for your Java stored procedure workload. For additional information on setting up your WLM environment see the chapter WLM-Established Stored Procedures Address Spaces in Getting Started with DB2 Stored Procedures: Give Them a Call through the Network , SG24-4693. For a complete explanation of how to use and set up the OS/390 WLM, refer to OS/390 MVS Workload Management Services, GC28-1773. To define an application environment specify the subsystem type under which the applications are running. In this case, DB2 should be your subsystem type You can define whether requests can execute in multiple server address spaces and on multiple systems, or single address space per system or sysplex. If you wish workload management to automatically manage the number of servers in goal mode, set the field for Limit on starting server address spaces for a subsystem instance to 1, no limit. In the PROCEDURE NAME field put the name of the JCL procedure you want started. This JCL procedure member must reside in an accessible PROCLIB library. Any required start parameters can be passed by WLM. You can, for example, pass as a parameter the number of TCBs that should be available in the address space and the application environment name to use.
In this command, name is the name of a WLM application environment associated with a group of stored procedures. This means that when you execute this command, you affect all stored procedures associated with the application environment. To stop all stored procedures address spaces associated with the WLM application environment name, use the MVS command:
337
VARY WLM,APPLENV=name,QUIESCE
To start all stored procedures address spaces associated with the WLM application environment name, use the MVS command:
VARY WLM,APPLENV=name,RESUME
You also need to use the VARY WLM command with the RESUME option when WLM puts an application environment in the unavailable state. An application environment in which stored procedures run becomes unavailable when WLM detects five abnormal terminations within 10 minutes. When an application environment is in the unavailable state, WLM does not schedule stored procedures for execution in it. If WLM is operating in compatibility mode use the MVS command:
CANCEL WLM address space name
338
Warning
You should use the VARY WLM,APPLENV command to manage application environment servers rather than the CANCEL command. If there are more than five server cancellations in 10 minutes, workload management stops creating new servers for the application environment.
339
Commands that can be used to perform actions on an application environment: An application environment initially enters the AVAILABLE state when the service policy that contains its definition is activated. AVAILABLE means the application environment is available for use, and servers are allowed to be started for it. There are three options on the VARY command that you can use to change the state of an application environment after it has been made available: VARY WLM,APPLENV=xxxx,QUIESCE The quiesce option causes workload management to request the termination of server address spaces for the application environment upon completion of any active requests. Additional work requests are not handled by the servers, although work requests can continue to be queued, waiting for a server. If you do not want work queued, use subsystem functions to stop the queueing. You can issue a quiesce action for an application environment that is in the AVAILABLE state. When a quiesce action is issued for an application environment, it first enters the QUIESCING state until all servers have been requested to terminate. It then enters the QUIESCED state. VARY WLM,APPLENV=xxxx,RESUME The resume option restarts an application environment that was previously quiesced and is in the QUIESCED state. It indicates to workload management that server address spaces can once again be started for this application environment. The new servers process any queued requests and all new requests. When a resume action is issued for an application environment, it first enters the RESUMING state until all systems in the sysplex have accepted the action. It then enters the AVAILABLE state. VARY WLM,APPLENV=xxxx,REFRESH The refresh option requests the termination of existing server address spaces and starts new ones in their place. Existing servers finish their current work requests and end. The new servers process any queued requests and all new requests. You can issue a refresh action for an application environment that is in the AVAILABLE state. When a refresh action is issued for an application environment, it first enters the REFRESHING state until all servers have been requested to terminate. It then enters the AVAILABLE state.
340
Establishes an arbitrary USERID to use in a subsequent RDEFINE command to tie an MVS procedure name to a server:
ADDUSER DB2SERV
Defines server profiles in the form: subsys_type.subsys_name.applenv where, subsys_type is the subsystem type, as specified in the service definition osubsys_name is the instance name of the subsystem associated with this server. The subsystem uses this name when establishing itself as the work manager for application environment server requests. APPLENV is the application environment name, as specified in the service definition:
RDEFINE SERVER DB2.DB2A.* UACC(NONE) RDEFINE SERVER DB2.DB2B.* UACC(NONE)
Permits the USERID to the servers. This completes the association between the MVS procedure names and the servers:
PERMIT DB2.DB2A.* CLASS(SERVER) ID(DB2SERV) ACCESS(READ) PERMIT DB2.DB2B.* CLASS(SERVER) ID(DB2SERV) ACCESS(READ)
Refreshes the classes to refresh the RACF data base and make these changes go into effect:
SETR RACLIST(STARTED) REFRESH SETR RACLIST(SERVER) REFRESH
341
You can override only goals, number of periods, and resource group assignments and values. All of the workloads, service class names, classification rules, scheduling environments, and application environments defined in the service definition remain the same for any policy. If you need to change any of these, you will need to change the base service definition, re-install the service definition, and then activate a policy from that changed service definition.
342
Policy Definition
You need to define all of your policies at the outset, while you are defining the rest of the service definition. Once the service definition is installed, then you can switch from one defined policy to another. If you need to create a new policy or change the overrides in an existing policy, you will need to re-install the service definition with the new or changed policy definition before you can activate the new policy
Watch out for work defaulting to SYSOTHER . Work in subsystems that use enclaves (DB2 is one) can suffer performance degradation if left unclassified in the service definition. If you do not add classification rules for this work in your service definition, then when you switch to goal mode, that work will be assigned to the SYSOTHER service class, which has a discretionary goal. Using the WLM application, you need to add classification rules to assign the work to service classes with appropriate response time or velocity goals. As a general rule, its a good idea to keep an eye on the SYSOTHER service class through RMF or another monitor. Any service accumulating in the SYSOTHER service class is a signal that you have unclassified work in your system. Workload management can dynamically manage the number of batch initiator address spaces is a JES2 environment. You can selectively turn over control of the batch initiator management to WLM for one or more job classes. WLM will start new initiators, as needed, to meet the performance goals of this work. By specifying or defaulting MODE=JES on the JES2 JOBCLASS initiator start, you indicate that the initiators for the job class should be JES-managed, as in the past. By specifying MODE=JES, you keep the job class in JES-managed mode. (JES will manage the batch initiators for that job class, in the same way it has in prior releases.) By specifying MODE=WLM, you put that class into WLM-managed mode. You can switch as many job classes to WLM-managed mode as you wish. You can easily switch any job class back to JES-managed mode by using the $TJOBCLASS JES2 command. A service definition contains all of the information necessary for workload management processing. Enter your service definition into the ISPF administrative application. The service definition is the way to express your installations business goals to your sysplex. In order to do this, you must understand your installations business environment.
343
A high velocity goal for a service class whose name you define, such as PRODREGN, for the following: DB2 (all address spaces including WLM-established stored procedures, except for the DB2-established stored procedures address space) CICS (all region types) IMS (all region types except BMPs) The velocity goals for WLM-established stored procedures, CICS and IMS regions are only important during startup or restart. After transactions begin running, WLM ignores the WLM-established stored procedures, CICS or IMS velocity goals and assigns priorities based on the goals of the transactions or packages that are running in the regions. A high velocity goal is good for ensuring that startups and restarts are performed as quickly as possible. If a CICS or IMS transaction calls a DB2 stored procedure, WLM will assign priorities base on goals of the package running in the WLM-established address space. Similarly, when you set response time goals for DDF threads or for stored procedures in a WLM-established address space, the only work controlled by the DDF or stored procedure velocity goals are the DB2 service tasks (work performed for DB2 that cannot be attributed to a single user). The user work runs under separate goals for the enclave. For the DB2-established stored procedures address space, use a velocity goal that reflects the requirements of your distributed work. Depending on
344
what type of distributed work you do, this might be equal to or lower than the goal for PRODREGN. IMS BMPs can be treated along with other batch jobs, or can be given a velocity goal, depending on what business and functional requirements you have at your site.
345
and any WLM-established address spaces for stored procedures and user-defined functions to the same service class as the DB2 database services address space (ssnmDBM1). Define this service class with a velocity goal. You can control which address spaces can be WLM-established server address spaces that run stored procedures. To do this, use the server resource class, which WLM uses to identify valid address spaces to which work can be sent. If the server class is not defined or activated, then any address space is allowed to connect to WLM as a server address space and to identify itself as a server address space that runs stored procedures.To use the server resource class, perform the following steps: 1. Run a version of RACF in which the resource class SERVER is included as part of the predefined resource classes (RACF Version 2 Release 2 and subsequent releases). 2. Define a RACF profile for resource class SERVER: RDEFINE SERVER (DB2.ssnm.applenv) where APPLENV is the name of the application environment associated with the stored procedure. 3. Activate the SERVER resource class: SETROPTS RACLIST(SERVER) REFRESH 4. Permit read access to the server resource name to the user IDs associated with the stored procedures address space.
PERMIT DB2.DB2T.TESTPROC CLASS(SERVER) ID(SYSDSP) ACCESS(READ) PERMIT DB2.DB2P.PAYROLL CLASS(SERVER) ID(SYSDSP) ACCESS(READ) PERMIT DB2.DB2P.QUERY CLASS(SERVER) ID(SYSDSP) ACCESS(READ)
You can find additional information in the chapter WLM_Established Stored Procedures in Getting Started with DB2 Stored Procedures, SG24-4693.
346
347
E.1.1.1 OS/390 sample client code These files can be found in directory \Samples\Code_Clients\OS390
\Samples\Code_Clients\OS390\cscallac.txt \Samples\Code_Clients\OS390\jecall_Query_oi_summ.java \Samples\Code_Clients\OS390\jscall_Add_customer.java \Samples\Code_Clients\OS390\readme.txt
348
\Samples\Code_Clients\OS390\sscall_Add_customer.sqlj
E.1.1.2 UNIX / NT Sample client code These files can be found in directory \Samples\Code_Clients\Unix_and_NT
\Samples\Code_Clients\Unix_and_NT \Samples\Code_Clients\Unix_and_NT\jecall_Query_oi_summ.java \Samples\Code_Clients\Unix_and_NT\jscall_Add_customer.java \Samples\Code_Clients\Unix_and_NT\prep.sh \Samples\Code_Clients\Unix_and_NT\prep_sscall.bat \Samples\Code_Clients\Unix_and_NT\sscall_Add_customer.sqlj
E.1.2.1 COBOL sample stored procedure code These files can be found in directory \Samples\Code_Stored_Procedures\COBOL
\Samples\Code_Stored_Procedures\COBOL\S390 \Samples\Code_Stored_Procedures\COBOL\S390\Acmecoe \Samples\Code_Stored_Procedures\COBOL\S390\Acmecos \Samples\Code_Stored_Procedures\COBOL\S390\Acmecos\addcust.txt
E.1.2.2 JDBC sample stored procedure code These files can be found in directory \Samples\Code_Stored_Procedures\JDBC
\Samples\Code_Stored_Procedures\JDBC\readme_jdbc.txt
JDBC sample stored procedure code - NT These files can be found in directory \Samples\Code_Stored_Procedures\JDBC\NT
\Samples\Code_Stored_Procedures\JDBC\NT\Acmejne \Samples\Code_Stored_Procedures\JDBC\NT\Acmejns \Samples\Code_Stored_Procedures\JDBC\NT\Acmejne\ACMEJNE \Samples\Code_Stored_Procedures\JDBC\NT\Acmejne\define_sp.sql \Samples\Code_Stored_Procedures\JDBC\NT\Acmejne\prep.bat \Samples\Code_Stored_Procedures\JDBC\NT\Acmejne\ACMEJNE\Add_customer.java \Samples\Code_Stored_Procedures\JDBC\NT\Acmejne\ACMEJNE\Add_order.java \Samples\Code_Stored_Procedures\JDBC\NT\Acmejne\ACMEJNE\Query_oi_summ.java \Samples\Code_Stored_Procedures\JDBC\NT\Acmejns\ACMEJNS \Samples\Code_Stored_Procedures\JDBC\NT\Acmejns\define_sp.sql \Samples\Code_Stored_Procedures\JDBC\NT\Acmejns\prep.bat \Samples\Code_Stored_Procedures\JDBC\NT\Acmejns\ACMEJNS\Add_customer.java
349
JDBC sample stored procedure code - S390 These files can be found in directory
\Samples\Code_Stored_Procedures\JDBC\S390 \Samples\Code_Stored_Procedures\JDBC\S390\ACMEJOS \Samples\Code_Stored_Procedures\JDBC\S390\ACMEJOS\Add_customer.java
JDBC sample stored procedure code - UNIX These files can be found in directory
\Samples\Code_Stored_Procedures\JDBC\UNIX \Samples\Code_Stored_Procedures\JDBC\UNIX\ACMEJUE \Samples\Code_Stored_Procedures\JDBC\UNIX\ACMEJUS \Samples\Code_Stored_Procedures\JDBC\UNIX\ACMEJUE\ACMEJUE \Samples\Code_Stored_Procedures\JDBC\UNIX\ACMEJUE\define_sp_Query_oi_summ. sql \Samples\Code_Stored_Procedures\JDBC\UNIX\ACMEJUE\install_jar.sql \Samples\Code_Stored_Procedures\JDBC\UNIX\ACMEJUE\prep.sh \Samples\Code_Stored_Procedures\JDBC\UNIX\ACMEJUE\replace_jar.sql \Samples\Code_Stored_Procedures\JDBC\UNIX\ACMEJUE\ACMEJUE\Query_oi_summ.ja va \Samples\Code_Stored_Procedures\JDBC\UNIX\ACMEJUS\ACMEJUS \Samples\Code_Stored_Procedures\JDBC\UNIX\ACMEJUS\define_sp_Add_customer.s ql \Samples\Code_Stored_Procedures\JDBC\UNIX\ACMEJUS\install_jar.sql \Samples\Code_Stored_Procedures\JDBC\UNIX\ACMEJUS\prep.sh \Samples\Code_Stored_Procedures\JDBC\UNIX\ACMEJUS\replace_jar.sql \Samples\Code_Stored_Procedures\JDBC\UNIX\ACMEJUS\ACMEJUS\Add_customer.jav a
E.1.2.3 SQLJ sample stored procedure code These files can be found in directory \Samples\Code_Stored_Procedures\SQLJ
\Samples\Code_Stored_Procedures\SQLJ\readme.txt
SQLJ sample stored procedure code - NT These files can be found in directory \Samples\Code_Stored_Procedures\SQLJ\NT
\Samples\Code_Stored_Procedures\SQLJ\NT\Acmesne \Samples\Code_Stored_Procedures\SQLJ\NT\ACMESNS \Samples\Code_Stored_Procedures\SQLJ\NT\Acmesne\acmesne \Samples\Code_Stored_Procedures\SQLJ\NT\Acmesne\define_acmesne.sql \Samples\Code_Stored_Procedures\SQLJ\NT\Acmesne\prep.bat \Samples\Code_Stored_Procedures\SQLJ\NT\Acmesne\acmesne\Add_customer.sqlj \Samples\Code_Stored_Procedures\SQLJ\NT\Acmesne\acmesne\Query_oi_summ.sqlj \Samples\Code_Stored_Procedures\SQLJ\NT\ACMESNS\ACMESNS \Samples\Code_Stored_Procedures\SQLJ\NT\ACMESNS\define_sp.sql
350
SQLJ sample stored procedure code - S390 These files can be found in directory
\Samples\Code_Stored_Procedures\SQLJ\S390 \Samples\Code_Stored_Procedures\SQLJ\S390\Acmesos \Samples\Code_Stored_Procedures\SQLJ\S390\Acmesos\Add_customer.sqlj
SQLJ sample stored procedure code - UNIX These files can be found in directory
\Samples\Code_Stored_Procedures\SQLJ\Unix \Samples\Code_Stored_Procedures\SQLJ\Unix\ACMESUE \Samples\Code_Stored_Procedures\SQLJ\Unix\ACMESUS \Samples\Code_Stored_Procedures\SQLJ\Unix\ACMESUE\ACMESUE \Samples\Code_Stored_Procedures\SQLJ\Unix\ACMESUE\define_sp_Query_oi_summ. sql \Samples\Code_Stored_Procedures\SQLJ\Unix\ACMESUE\install_jar.sql \Samples\Code_Stored_Procedures\SQLJ\Unix\ACMESUE\prep.sh \Samples\Code_Stored_Procedures\SQLJ\Unix\ACMESUE\replace_jar.sql \Samples\Code_Stored_Procedures\SQLJ\Unix\ACMESUE\ACMESUE\Query_oi_summ.sq lj \Samples\Code_Stored_Procedures\SQLJ\Unix\ACMESUS\ACMESUS \Samples\Code_Stored_Procedures\SQLJ\Unix\ACMESUS\define_sp_Add_customer.s ql \Samples\Code_Stored_Procedures\SQLJ\Unix\ACMESUS\install_jar.sql \Samples\Code_Stored_Procedures\SQLJ\Unix\ACMESUS\prep.sh \Samples\Code_Stored_Procedures\SQLJ\Unix\ACMESUS\replace_jar.sql \Samples\Code_Stored_Procedures\SQLJ\Unix\ACMESUS\ACMESUS\Add_customer.sql j
E.1.2.4 SQLJ & JDBC sample stored procedure code These files can be found in directory \Samples\Code_Stored_Procedures\Both
\Samples\Code_Stored_Procedures\Both\readme.txt
SQLJ & JDBC sample stored procedure code - S390 These files can be found in directory
\Samples\Code_Stored_Procedures\Both\S390 \Samples\Code_Stored_Procedures\Both\S390\Acmebos \Samples\Code_Stored_Procedures\Both\S390\Acmebos\Add_customer.sqlj
351
SQLJ & JDBC sample stored procedure code - NT These files can be found in directory \Samples\Code_Stored_Procedures\Both\NT
\Samples\Code_Stored_Procedures\Both\NT\ACMEBNS \Samples\Code_Stored_Procedures\Both\NT\ACMEBNS\ACMEBNS \Samples\Code_Stored_Procedures\Both\NT\ACMEBNS\define_acmebns.sql \Samples\Code_Stored_Procedures\Both\NT\ACMEBNS\prep.bat \Samples\Code_Stored_Procedures\Both\NT\ACMEBNS\refresh.bat \Samples\Code_Stored_Procedures\Both\NT\ACMEBNS\refresh_acmebns.sql \Samples\Code_Stored_Procedures\Both\NT\ACMEBNS\ACMEBNS\Add_customer.sqlj
SQLJ & JDBC sample stored procedure code - UNIX These files can be found in directory
\Samples\Code_Stored_Procedures\Both\Unix \Samples\Code_Stored_Procedures\Both\Unix\ACMEBUS \Samples\Code_Stored_Procedures\Both\Unix\ACMEBUS\ACMEBUS \Samples\Code_Stored_Procedures\Both\Unix\ACMEBUS\define_sp_Add_customer.s ql \Samples\Code_Stored_Procedures\Both\Unix\ACMEBUS\install_jar.sql \Samples\Code_Stored_Procedures\Both\Unix\ACMEBUS\prep.sh \Samples\Code_Stored_Procedures\Both\Unix\ACMEBUS\replace_jar.sql \Samples\Code_Stored_Procedures\Both\Unix\ACMEBUS\ACMEBUS\Add_customer.sql j
E.1.3.1 Sample S390 installation utilities These files can be found in directory \Samples\S390_Utilities\Installation
\Samples\S390_Utilities\Installation\.profile \Samples\S390_Utilities\Installation\db2jdbc.cursors \Samples\S390_Utilities\Installation\db2sqljjdbc.properties \Samples\S390_Utilities\Installation\dbz2java \Samples\S390_Utilities\Installation\javaenv \Samples\S390_Utilities\Installation\jdbcbind \Samples\S390_Utilities\Installation\readme.txt \Samples\S390_Utilities\Installation\sqljplan
Note:
The .profile file was recorded in the CD-ROM as profile (without the dot). Once you have downloaded it, you need to rename the file to .profile.
352
E.1.3.2 Sample S390 program preparation utilities These files can be found in directory\Samples\S390_Utilities\Program_Preparation
\Samples\S390_Utilities\Program_Preparation\bindcl.rexx \Samples\S390_Utilities\Program_Preparation\bindsp.rexx \Samples\S390_Utilities\Program_Preparation\driver_bos \Samples\S390_Utilities\Program_Preparation\driver_cl \Samples\S390_Utilities\Program_Preparation\driver_joe \Samples\S390_Utilities\Program_Preparation\driver_jos \Samples\S390_Utilities\Program_Preparation\driver_soe \Samples\S390_Utilities\Program_Preparation\driver_sos \Samples\S390_Utilities\Program_Preparation\hpjcust \Samples\S390_Utilities\Program_Preparation\hpjsp \Samples\S390_Utilities\Program_Preparation\javacl \Samples\S390_Utilities\Program_Preparation\javasp \Samples\S390_Utilities\Program_Preparation\javaspj \Samples\S390_Utilities\Program_Preparation\oebind \Samples\S390_Utilities\Program_Preparation\readme.txt
E.1.4.1 Sample SQL - S390 These files can be found in directory \Samples\SQL\S390
\Samples\SQL\S390\ddle.txt \Samples\SQL\S390\ddls.txt \Samples\SQL\S390\procbos.txt \Samples\SQL\S390\proccoe.txt \Samples\SQL\S390\proccos.txt \Samples\SQL\S390\procjoe.txt \Samples\SQL\S390\procjos.txt \Samples\SQL\S390\procsoe.txt \Samples\SQL\S390\procsos.txt \Samples\SQL\S390\readme.txt
E.1.4.2 Sample SQL - UNIX and NT These files can be found in directory \Samples\SQL\Unix_and_NT
\Samples\SQL\Unix_and_NT\ddle_nt_db2v7.txt \Samples\SQL\Unix_and_NT\ddle_unix_db2v6.txt \Samples\SQL\Unix_and_NT\ddls.txt
353
Select the Additional materials and open the directory that corresponds with the redbook form number.
354
355
responsibility and depends on the customer's ability to evaluate and integrate them into the customer's operational environment. While each item may have been reviewed by IBM for accuracy in a specific situation, there is no guarantee that the same or similar results will be obtained elsewhere. Customers attempting to adapt these techniques to their own environments do so at their own risk. Any pointers in this publication to external Web sites are provided for convenience only and do not in any manner serve as an endorsement of these Web sites. Any performance data contained in this document was determined in a controlled environment, and therefore, the results that may be obtained in other operating environments may vary significantly. Users of this document should verify the applicable data for their specific environment. This document contains examples of data and reports used in daily business operations. To illustrate them as completely as possible, the examples contain the names of individuals, companies, brands, and products. All of these names are fictitious and any similarity to the names and addresses used by an actual business enterprise is entirely coincidental. Reference to PTF numbers that have not been released through the normal distribution process does not imply general availability. The purpose of including these reference numbers is to alert IBM customers to specific information relative to the implementation of the PTF when it becomes available to each customer according to the normal IBM PTF distribution process. The following terms are trademarks of the International Business Machines Corporation in the United States and/or other countries:
AIX AT CICS DATABASE2 DB2 Connect Enterprise Storage Server Language Environment Netfinity Parallel Sysplex RACF RETAIN RS/6000 SP VisualAge XT AS/400 C/MVS CT DB2 DRDA IBM Net.Data OS/390 QMF RAMAC RMF S/390 System/390 VTAM 400
356
The following terms are trademarks of other companies: Tivoli, Manage. Anything. Anywhere.,The Power To Manage., Anything. Anywhere.,TME, NetView, Cross-Site, Tivoli Ready, Tivoli Certified, Planet Tivoli, and Tivoli Enterprise are trademarks or registered trademarks of Tivoli Systems Inc., an IBM company, in the United States, other countries, or both. In Denmark, Tivoli is a trademark licensed from Kjbenhavns Sommer - Tivoli A/S. C-bus is a trademark of Corollary, Inc. in the United States and/or other countries. Java and all Java-based trademarks and logos are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and/or other countries. Microsoft, Windows, Windows NT, and the Windows logo are trademarks of Microsoft Corporation in the United States and/or other countries. PC Direct is a trademark of Ziff Communications Company in the United States and/or other countries and is used by IBM Corporation under license. ActionMedia, LANDesk, MMX, Pentium and ProShare are trademarks of Intel Corporation in the United States and/or other countries. UNIX is a registered trademark in the United States and other countries licensed exclusively through The Open Group. SET and the SET logo are trademarks owned by SET Secure Electronic Transaction LLC. Other company, product, and service names may be trademarks or service marks of others.
357
358
Collection Kit Number SK2T-2177 SK2T-6022 SK2T-8038 SK2T-8039 SK2T-8044 SK2T-2849 SK2T-8046 SK2T-8040 SK2T-8043 SK2T-8037 SK3T-3694
359
360
AIX documentation; many commands also work in UNIX System Services. http://service.software.ibm.com/db2/support/dbssup.html DB2 software updates. http://www.sqlj.org SQLJ home page. http://www.ibm.com/s390/corner/ Java on S/390. http://www.software.ibm.com/data/db2/ DB2 Family http://www.software.ibm.com/data/db2/os390/ DB2 for OS/390. http://www.ibm.com/software/db2os390/downloads.html DB2 downloads. http://www.ibm.com/solutions/businessintelligence/teraplex/index.html Teraplex Center.
361
362
e-mail address usib6fpl@ibmmail.com Contact information is in the How to Order section at this site: http://www.elink.ibmlink.ibm.com/pbl/pbl
Fax Orders United States (toll free) Canada Outside North America 1-800-445-9269 1-403-267-4455 Fax phone number is in the How to Order section at this site: http://www.elink.ibmlink.ibm.com/pbl/pbl
This information was current at the time of publication, but is continually subject to change. The latest information may be found at the Redbooks Web site.
363
First name Company Address City Telephone number Invoice to customer number Credit card number
Last name
Card issued to
Signature
We accept American Express, Diners, Eurocard, Master Card, and Visa. Payment by credit card not available in all countries. Signature mandatory for credit card payment.
364
Glossary
The following terms and abbreviations are defined as they are used in the DB2 library. If you do not find the term you are looking for, refer to the index or to IBM Dictionary of Computing. Also, it brings term and abbreviations related to Java and other products, mentioned in this book.
AFC
allied address space. An area of storage external to DB2 that is connected to DB2 and is therefore capable of requesting DB2 services. American National Standards Institute (ANSI) . An organization consisting of producers, consumers, and general interest groups, that establishes the procedures by which accredited organizations create and maintain voluntary industry standards in the United States. ANSI. American National Standards Institute. API
See Application Program Interface.
A
abstract class A class that provides common information for subclasses, and therefore cannot be instantiated. Abstract classes provide at least one abstract method. abstract method A method with a signature, but no implementation. You provide the implementation of the method in the subclass of the abstract class that contains the abstract method. abstract window toolkit (AWT) The Abstract Window Toolkit API provides a layer between the application and the hosts windowing system. It enables programmers to port Java applications from one window system to another. The AWT provides access to basic interface components such as events, color, fonts, and controls such as button, scroll bars, text fields, frames, windows, dialogs, panels, canvases, and check boxes. actual parameter list Parameters specified in a call to a method. See also formal parameter list. address space. A range of virtual storage pages identified by a number (ASID) and a collection of segment and page tables which map the virtual pages to real pages of the computer's memory. address space connection. The result of connecting an allied address space to DB2. Each address space containing a task connected to DB2 has exactly one address space connection, even though more than one task control block (TCB) can be present. See allied address space and task control block.
applet A Java program designed to run within a Web browser. Contrast with application. application. (1) A program or set of programs that perform a task; for example, a payroll application. (2) In Java programming, a self-contained, stand-alone Java program that includes a static main method. It does not require an applet viewer. Contrast with applet. Application Foundation Classes (AFCs) Microsofts version on the Java Foundation Classes (JFCs). AFCs deliver similar functions to JFCs but only work on Windows 32-bit platforms. application plan. The control structure produced during the bind process and used by DB2 to process SQL statements encountered during statement execution. application program interface (API) . A functional interface supplied by the operating system or by a separately orderable licensed program that allows an application program written in a high-level language to use specific data or functions of the operating system or licensed program. application requester (AR) . See requester. AR. application requester. See requester. AS. application server.
365
ASCII (1) American Standard Code for Information Interchange.A standard assignment of 7-bit numeric codes to characters. See also Unicode. (2) An encoding scheme used to represent strings in many environments, typically on PCs and workstations. Contrast with EBCDIC. attachment facility. An interface between DB2 and TSO, IMS, CICS, or batch address spaces. An attachment facility allows application programs to access DB2. authorization ID. A string that can be verified for connection to DB2 and to which a set of privileges are allowed. It can represent an individual, an organizational group, or a function, but DB2 does not determine this representation. AWT
See Abstract Window Toolkit.
automatic bind. (More correctly automatic rebind). A process by which SQL statements are bound automatically (without a user issuing a BIND command) when an application process begins execution and the bound application plan or package it requires is not valid. dynamic bind. A process by which SQL statements are bound as they are entered. incremental bind. A process by which SQL
statements are bound during the execution of an application process, because they could not be bound during the bind process, and VALIDATE(RUN) was specified.
B
base table. (1) A table created by the SQL CREATE TABLE statement that is used to hold persistent data. Contrast with result table and temporary table. (2) A table containing a LOB column definition. The actual LOB column data is not stored along with the base table. The base table contains a row identifier for each row and an indicator column for each of its LOB columns. Contrast with auxiliary table. base type In Java, a type establishes an interface to anything inherited from itself. See type, derived type . bean A definition or instance of a JavaBeans component. See JavaBeans. BeanInfo (1) A Java class that provides explicit information about the properties, events, and methods of a bean class. (2) In the VisualAge for Java Integrated Development Environment, a page in the class browser that provides bean information. binary large object (BLOB). See BLOB. bind. The process by which the output from the DB2 precompiler is converted to a usable control structure called a package or an application plan. During the process, access paths to the data are
static bind. A process by which SQL statements are bound after they have been precompiled. All static SQL statements are prepared for execution at the same time. Contrast with dynamic bind. BLOB. A sequence of bytes, where the size of the sequence ranges from 0 bytes to 2 GB - 1. Such a string does not have an associated CCSID. The size of binary large object values can be anywhere up to 2 GB - 1. browser (1) In VisualAge for Java, a window that provides information on program elements. There are browsers for projects, packages, classes, methods, and interfaces. (2) An Internet-based too that lets users browse Web sites. built-in function. A function that is supplied by DB2. Contrast with user-defined function. business object (1) An object that represents a business function. Business objects contain attributes that define the state of the object, and methods that define the behavior of the object. A business object also has relationships with other business objects. Business objects can be used in combination to perform a desired task. Typical examples of business objects are Customer, Invoice, or Account. (2) In the Enterprise Access Builder, a class that implements the IBusinessObject interface. Business objects are used to map interactions with an existing home.
366
bytecode Machine-independent code generated by the Java compiler and executed by the Java interpreter.
class hierarchy The relationships between classes that share a single inheritance. All Java classes inherit from the Object class. class method Methods that apply to the class as a whole rather than its instances (also called a static method). class path When running a program in VisualAge for Java, a list of directories and JAR files that contain resource files or Java classes that a program can load dynamically at run time. A program's class path is set in its Properties notebook. CLASSPATH In your deployment environment, the environment variable keyword that specifies the directories in which to look for class and resource files. class variable Variables that apply to the class as a whole rather than its instances (also called a static field ). CLI. See call level interface. client. (1)A networked computer in which the IDE is connected to a repository on a team server. (2) See requester. CLOB. A sequence of bytes representing single-byte characters or a mixture of single and double-byte characters where the size can be up to 2 GB - 1. Although the size of character large object values can be anywhere up to 2 GB - 1, in general, they are used whenever a character string might exceed the limits of the VARCHAR type. codebase An attribute of the <APPLET> tag that provides the relative path name for the classes. Use this attribute when your class files reside in a different directory than your HTML files. column function. An SQL operation that derives its result from a collection of values across one or more rows. Contrast with scalar function. commit. The operation that ends a unit of work by releasing locks so that the database changes made by that unit of work can be perceived by other processes.
C
CAF. Call attachment facility. call attachment facility (CAF). A DB2 attachment facility for application programs running in TSO or MVS batch. The CAF is an alternative to the DSN command processor and allows greater control over the execution environment. call level interface (CLI). A callable application program interface (API) for database access, which is an alternative to using embedded SQL. In contrast to embedded SQL, DB2 CLI does not require the user to precompile or bind applications, but instead provides a standard set of functions to process SQL statements and related services at run time. cast function. A function used to convert instances of a (source) data type into instances of a different (target) data type. In general, a cast function has the name of the target data type. It has one single argument whose type is the source data type; its return type is the target data type. casting Explicitly converting an object or primitives data type. catalog. In DB2, a collection of tables that contains descriptions of objects such as tables, views, and indexes. catalog table. Any table in the DB2 catalog. C++ Access Builder A VisualAge fro Java, Enterprise Edition tool that generates beans and C++ wrappers that let your Java programs access C++ DLLs. character large object (CLOB) . See CLOB. class An encapsulated collection of data and methods to operate on the data. A class may be instantiated to produce an object that is an instance of the class.
367
Common Connector Framework In the Enterprise Access Builder, interface and class definitions that provide a consistent means of interacting with enterprise resources (for example, CICS and Encina transactions) from any Java execution environment. Common Object Request Broker Architecture (CORBA) Common Object Request Broker Architecture. A specification produced by the Object Management Group (OMG) that presents standards for various types of object request brokers (such as client-resident ORBs, server-based ORBs, system-based ORBs, and library-based ORBs). Implementation of CORBA standards enables object request brokers from different software vendors to interoperate. Common RFC Interface for Java A set of Java interfaces and classes that defines a middleware-independent layer to access R/3 systems from Java. If applications are built on top of this interface, they can leverage different middleware at run time without recoding. The generated beans are based on this interface and provide the same flexibility. common server. Describes the set of DB2 products that run on various platforms and have the same source code. These platforms include OS/2, Windows, and UNIX. component model An architecture and an API that allows developers to define reusable segments of code that can be combined to create a program. VisualAge for Java uses the JavaBeans component model. composite bean A bean that can contain both visual and nonvisual components. A composite bean is composed of embedded beans. connection In the VisualAge for Java Visual Composition Editor, a visual link between two components that represents the relationship between the components. Each connection has a source, a target, and other properties. connection handle. The data object that contains information associated with a connection managed by DB2 CLI. This includes general status information, transaction status, and diagnostic information.
Console In VisualAge for Java, the window that acts as the standard input (System.in) and standard output (System.out) device for programs running in the VisualAge for Java environment. constructor A method called to set up a new instance of a class. constant . A language element that specifies anunchanging value. Constants are classified as string constants or numeric constants. Contrast with variable. container A component that can hold other components. In Java, examples of containers include applets, frames, and dialogs. In the Visual Composition Editor, containers can be graphically represented and generated. context. The application's logical connection to the data source and associated internal DB2 ODBC connection information that allows the application to direct its operations to a data source. A DB2 ODBC context represents a DB2 thread. cookie (1) A small file stored on an individual's computer; this file allows a site to tag the browser with a unique identification. When a person visits a site, the site's server requests a unique ID from the person's browser. If this browser does not have an ID, the server delivers one. On the Wintel platform, the cookie is delivered to a file called'cookies.txt,' and on a Macintosh platform, it is delivered to 'MagicCookie.' Just as someone can track the origin of a phone call with Caller ID, companies can use cookies to track information about behavior. (2) Persistent data stored by the client in the Servlet Builder. CORBA Common Objects Request Broker Architecture. Core API Part of the minimal set of APIs that form the standard Java Platform. Core APIs are available on the Java Platform regardless of the underlying operating system. The Core API grows with each release of the JDK; the current core API is based on JDK 1.1. Also called core classes. cursor. A named control structure used by an application program to point to a row of interest
368
within some set of rows, and to retrieve rows from the set, possibly making updates or deletions.
D
Data Access Bean In the VisualAge for Java Visual Composition Editor, a bean that accesses and manipulates the content of JDBC/ODBC-compliant relational databases. Data Access Builder A VisualAge for Java Enterprise tool that generates beans to access and manipulate the content of JDBC/ODBC-compliant relational databases. database management system (DBMS). A software system that controls the creation, organization, and modification of a database and access to the data stored within it. data source. A local or remote relational or non-relational data manager that is capable of supporting data access via an ODBC driver which supports the ODBC APIs. In the case of DB2 for OS/390, the data sources are always relational database managers. DBCLOB. A sequence of bytes representing double-byte characters where the size can be up to 2 gigabytes. Although the size of double-byte character large object values can be anywhere up to 2 gigabytes, in general, they are used whenever a double-byte character string might exceed the limits of the VARGRAPHIC type. DBMS. Database management system. DB2 thread. The DB2 structure that describes an application's connection, traces its progress, processes resource functions, and delimits its accessibility to DB2 resources. and services. debugger A component that assists in analyzing and correcting coding errors. declaration Statement that creates an identifier and its attributes, but does not reserve storage or provide an implementation. definition Statement that reserves storage or provides an implementation. deprecation An obsolete component that may be deleted from a future version of a product.
derived type In Java, a type that overrides the definitions of a base type to provide unique behavior. The derived type extends the base type. dipping A metaphor, introduced by BeanExtender on alphaWorks, for modifying a component by hooking a special kind of Java bean onto it. Dipping lets you add new behavior or modify the Java bean's existing behavior without having to manipulate the Java bean's code. A dip is a special kind of Java bean that can be hooked on to another Java bean; it is the new feature you want to add to the component. Software examples of dips include printing and security. Dippable Java beans can have one or more dips connected to them. Almost any Java bean or class can be made dippable by extending it, a process called morphing. dip A special kind of Java bean that can be hooked on to another Java bean; the new feature you want to add to the component. Software examples of dips include printing and security.
distributed processing Processing that takes place across two or more linked systems.
distinct type. A user-defined data type that is internally represented as an existing type (its source type), but is considered to be a separate and incompatible type for semantic purposes. distributed relational database architecture (DRDA). A connection protocol for distributed relational database processing that is used by IBM's relational database products. DRDA includes protocols for communication between an application and a remote relational database management system, and for communication between relational database management systems. DLL (dynamic link library) A file containing executable code and data bound to a program at load time or run time, rather than during linking. The code and data in a dynamic link library can be shared by several applications simultaneously. The DLLs. Enterprise Access Builders also generate platform-specific DLLs for the workstation and OS/390 platforms.
369
double-byte character large object (DBCLOB). See DBCLOB. double precision A floating-point number that contains 64 bits. See also single precision . DRDA. Distributed relational database architecture. dynamic SQL. SQL statements that are prepared and executed within an application program while the program is executing. In dynamic SQL, the SQL source is contained in host language variables rather than being coded into the application program. The SQL statement can change several times during the application program's execution.
encapsulation The grouping of both data and operations into neat, manageable units that can be developed, tested, and maintained independently of one another. Such grouping is a powerful technique for building better software. The object manages its own resources and limits their visibility. enclave. In Language Environment for MVS & VM, an independent collection of routines, one of which is designated as the main routine. An enclave is similar to a program or run unit. Enterprise Access Builder (EAB) Feature of Visual Age for Java, Enterprise Edition, that creates connectors to enterprise server products such as CICS, Encina, IMS TOC, and MQSeries. Enterprise Edition See VisualAge for Java, Enterprise Edition . Enterprise Java Includes Enterprise JavaBeans as well as open API specifications for: database connectivity, naming and directory services, CORBA/IIOP interoperability, pure Java distributed computing, messaging services, managing system and network resources, and transaction services. Enterprise JavaBeans A cross-platform component architecture for the development and deployment of multi-tier, distributed, scalable, object-oriented Java applications. Enterprise ToolKit A set of VisualAge for Java Enterprise tools that enable you to develop Java code that is targeted to specific platforms, such as AS/400, OS/390, OS/2, AIX, and Windows. Entry Edition Edition.
See VisualAge for Java, Entry
E
EBCDIC. Extended binary coded decimal interchange code. An encoding scheme used to represent character data in the MVS, VM, VSE, and OS/400 environments. Contrast with ASCII. EAB
See Enterprise Access Builder.
e-business Either (a) the transaction of business over an electronic medium such as the Internet or (b) a business that uses Internet technologies and network computing in their internal business processes (via intranets), their business relationships (via extranets), and the buying and selling of goods, services, and information (via electronic commerce.) e-commerce The subset of e-business that involves the exchange of money for goods or services purchased over an electronic medium such as the Internet. EmbeddedJava An API and application environment for high-volume embedded devices, such as mobile phones, pagers, process control, instrumentation, office peripherals, network routers and network switches. EmbeddedJava applications run on real-time operating systems and are optimized for the constraints of small-memory footprints and diverse visual displays. embedded SQL. SQL statements coded within an application program. See static SQL.
equi-join. A join operation in which the join-condition has the form expression = expression. event An action by a user, program, or system that may trigger specific behavior. In the JDK, events notify the relevant listener classes to take appropriate action. environment. A collection of names of logical and physical resources that are used to support the performance of a function.
370
environment handle. In DB2 ODBC, the data object that contains global information regarding the state of the application. An environment handle must be allocated before a connection handle can be allocated. Only one environment handle can be allocated per application. exception An exception is an object that has caused some sort of new condition, such as an error. In Java, throwing an exception means passing that object to an interested party; a signal indicates what kind of condition has taken place. Catching an exception means receiving the sent object. Handling this exception usually means taking care of the problem after receiving the object, although it might mean doing nothing (which would be bad programming practice). executable content Code that runs from within an HTML file (such as an applet). extends A subclass or interface extends a class or interface if it add fields or methods, or overrides its methods. See also derived type. external function. A function for which the body is written in a programming language that takes scalar argument values and produces a scalar result for each invocation. Contrast with sourced function and built-in function.
that uses TCP and Telnet services to transfer bulk-data files between machines or hosts.
foreign key. A key that is specified in the definition of a referential constraint. Because of the foreign key, the table is a dependent table. The key must have the same number of columns, with the same descriptions, as the primary key of the parent table. form data A generated class representing the HTML form elements in a visual servlet. formal parameter list Parameters specified in a method's definition. See also actual parameter list. FTP
See File Transfer Protocol .
full outer join. The result of a join operation that includes the matched rows of both tables being joined and preserves the unmatched rows of both tables. See also join. function. A specific purpose of an entity or its characteristic action such as a column function or scalar function. (See column function and scalar function.). Furthermore, functions can be user-defined, built-in, or generated by DB2. (See built-in function, cast function, user-defined function, external function, sourced function.)
F
factory A bean that dynamically creates instances of beans. field A data object in a class; for example, a variable. first tier The client; the hardware and software with which the end user interacts. framework A set of object classes that provide a collection of related functions for a user or piece of software. free-form surface In the VisualAge for Java Visual Composition Editor, the large, open area where you can work with visual and nonvisual beans. You add, remove, and connect beans on the free-form surface. File Transfer Protocol (FTP) In the Internet suite of protocols, an application layer protocol
G
garbage collection Java's ability to clean up inaccessible unused memory areas ("garbage") on the fly. Garbage collection slows performance, but keeps the machine from running out of memory. Graphical User Interface (GUI) A type of computer interface consisting of a visual metaphor of a real-world scene, often of a desktop. Within that scene are icons, representing actual objects, that the user can access and manipulate with a pointing device.
H
handle. In DB2 CLI, a variable that refers to a data structure and associated resources. See statement handle, connection handle, and environment handle.
371
hierarchy The order of inheritance in object-oriented languages. Each class in the hierarchy inherits attributes and behavior from its superclass, except for the top-level Object class. HotJava A Java-enabled Web and intranet browser developed by Sun Microsystems, Inc. HotJava is written in Java. (Definition copyright 1996-1999 Sun Microsystems, Inc. All Rights Reserved. Used by permission.) Hypertext Markup Language (HTML) A file format, based on SGML, for hypertext documents on the Internet. Allows for the embedding of images, sounds, video streams, form fields and simple text formatting. References to other objects are embedded using URLs, enabling readers to jump directly to the referenced document. Hypertext Transfer Protocol (HTTP) The Internet protocol, based on TCP/IP, used to fetch hypertext objects from remote hosts.
to exchange data with eSuite and other InfoBus-enabled applications. The 100% Pure Java release and the InfoBus specification are available for free download from: http://java.sun.com/beans/infobus
inheritance The ability to create a subclass that automatically inherits properties and methods from its superclass. See also hierarchy. initialization file. For DB2 ODBC applications, a file containing values that can be set to adjust the performance of the database manager. inner join. The result of a join operation that includes only the matched rows of both tables being joined. See also join. Inspector In VisualAge for Java, a window in which you can evaluate code fragments in the context of an object, look at the entire contents of an object and its class, or access and modify the fields of an object. instance The specific representation of a class, also called an object.
I
IDE
See Integrated Development Environment . The name of an item in a program.
identifier
instance method A method that applies and operates on objects (usually called simply a method). Contrast with class method . instance variable A variable that defines the attributes of an object. The class defines the instance variable's type and identifier, but the object sets and changes its values. Integrated Development Environment (IDE) In VisualAge for Java, the set of windows that provide the user with access to development tools. The primary windows are the Workbench, Log, Console, Debugger, and Repository Explorer. interface A list of methods that enables a class to implement the interface itself by using the implements keyword. The Interfaces page in the Workbench lists all interfaces in the workspace. Internet Protocol (IP) In the Internet suite of protocols, a connectionless protocol that routes data through a network or interconnected networks. IP acts as an intermediary between the higher protocol layers and the physical network. However, this protocol does not provide error
IDL (Interface Definition Language) In CORBA, a declarative language that is used to describe object interfaces, without regard to object implementation. IDL Development Environment In VisualAge for Java, an integrated IDL and Java development environment. The IDL Development Environment allows you to work with IDL source code in the multipane IDLs page and generate Java code using an IDL-to-Java compiler. IDL group A container used to hold IDL objects in the IDL Development Environment. It is similar to a file system directory. IIOP (Internet Inter-ORB Protocol) A communications standard for distributed objects that reside in Web or enterprise computing environments. InfoBus A technology for flexible, vendor-independent data exchange which is used by eSuite and can be used by other applications
372
recovery and flow control and does not guarantee the reliability of the physical network.
Machine, Java Class Libraries, Java Applet Viewer, Java Debugger, and other tools.
Internet Inter-ORB Protocol (IIOP) Access Builder A tool that edits and generates CORBA-compliant Java modules. See Common Object Request Broker Architecture (CORBA). interpreter A tool that translates and executes code line-by-line. introspection For a JavaBean to be reusable in development environments, there needs to be a way to query what the bean can do in terms of the methods it supports and the types of event it raises and listens for. Introspection allows a builder tool to analyze how a bean works. IP
See Internet Protocol.
Java Foundation Classes (JFC) Developed by Netscape, Sun, and IBM, JFCs are building blocks that are helpful in developing interfaces to Java applications. They allow Java applications to interact more completely with the existing operating systems. Also called Swing Set. Java IDL Java IDL is a language-neutral way to specify an interface between an object and its client on a different platform. Provides interoperability and integration with CORBA, the industry standard for distributed computing, allowing developers to build Java applications that are integrated with heterogeneous business information assets. Java Management Application Programming Interface (JMAPI) A specification proposed by Sun Microsystems that defines a core set of application programming interfaces for developing tightly integrated system, network, and service management applications. The application programming interfaces could be used in diverse computing environments that encompass many operating systems, architectures, and network protocols. Java Media and Communications APIs Allows developers to integrate a wide range of media types into their Web pages, applets, and applications. Includes: Media, Sound, Animation, 2D, 3D, Telephony, Speech and Collaboration. Java Media Framework (JMF) Java Media Framework API specifies a unified architecture, messaging protocol and programming interface for media players, capture and conferencing. JMF provides a set of building blocks useful by other areas of the Java Media API suite. For example, the JMF provides access to audio devices in a cross-platform, device-independent manner, which is required by both the Java Telephony and the Java Speech APIs. JMF will be published as three APIs: the Java Media Player, Java Media Capture, and Java Media Conference. Java Naming and Directory Interface (JNDI) A set of APIs that assist with the interfacing to multiple naming and directory services.
J
JAE
See Java Application Environment.
JAR file format JAR (Java Archive) is a platform-independent file format that aggregates many files into one. Multiple Java applets and their requisite components (.class files, images, sounds and other resource files) can be bundled in a JAR file and subsequently downloaded to a browser in a single HTTP transaction. Java An object-oriented programming language for portable, interpretive code that supports interaction among remote objects. Java was developed and specified by Sun Microsystems, Incorporated. The Java environment consists of the JavaOS, the Virtual Machines for various platforms, the object-oriented Java programming language, and several class libraries. Java Application Environment (JAE) The source code release of the Java (TM) Development Kit. (Definition copyright 1996-1999 Sun Microsystems, Inc. All Rights Reserved. Used by permission.) Java Development Kit (JDK) The Java Development Kit is the set of Java technologies made available to licensed developers by Sun Microsystems. Each release of the JDK contains the following: the Java Compiler, Java Virtual
373
(Definition copyright 1996-1999 Sun Microsystems, Inc. All Rights Reserved. Used by permission.)
the server and administrative system resources required for developers to quickly develop their own Java servers.
Java Native Interface (JNI) A native programming interface that allows Java code running inside a Java Virtual Machine (VM) to interoperate with applications and libraries written in other programming languages, such as C and C++. Java Platform The Java Virtual Machine and the Java Core classes make up the Java Platform. The Java Platform provides a uniform programming interface to a 100%. Pure Java program regardless of the underlying operating system. (Definition copyright 1996-1999 Sun Microsystems, Inc. All Rights Reserved. Used by permission.) Java Record Editor An editor that allows you to construct and refine dynamic record types. Java Record Framework A Java framework that describes and converts record data. Java Remote Method Invocation (RMI) Java Remote Method Invocation is method invocation between peers, or between client and server, when applications at both ends of the invocation are written in Java. Included in JDK 1.1. Java Runtime Environment (JRE) A subset of the Java Development Kit for end-users and developers who want to redistribute the JRE. The JRE consists of the Java Virtual Machine, the Java Core Classes, and supporting files. (Definition copyright 1996-1999 Sun Microsystems, Inc. All Rights Reserved. Used by permission.) Java Security API A framework for developers to include security functionality in their applets and applications. Includes: cryptography with digital signatures, encryption, and authentication. An intermediate subset of the Security API known as "Security and Signed Applets" is included in JDK 1.1. Java Server An extensible framework that enables and eases the development of Java-powered Internet and intranet servers. The APIs provide uniform and consistent access to
Java Virtual Machine (JVM) A software implementation of a central processing unit (CPU) that runs compiled Java code (applets and applications). JavaBeans Java's component architecture, developed by Sun, IBM, and others. The components, called Java beans, can be parts of Java programs, or they can exist as self-contained applications. Java beans can be assembled to create complex applications, and they can run within other component architectures (such as ActiveX and OpenDoc). JavaDoc Sun's tool for generating HTML documentation on classes by extracting comments from the Java source code files. JDBC (Java Database Connectivity) In the JDK, the specification that defines an API that enables programs to access databases that comply with this standard. JavaObjs In Remote Method Invocation, the name of the user-defined default file that contains a list of server objects to be instantiated when the Remote Object Instance Manager is started. JavaOS A basic, small-footprint operating system that supports Java. Java OS was originally designed to run in small electronic devices like phones and TV remotes, but it is also being targeted for use in network computers (NCs). JavaScript A scripting language used within an HTML page. Superficially similar to Java but JavaScript scripts appear as text within the HTML page. Java applets, on the other hand, are programs written in the Java language and are called from within HTML pages or run as stand-alone applications. JFC JIT
See Java Foundation Classes. See Just-In-Time Compiler.
374
JNI JRE
Just-In-Time compiler (JIT) A platform-specific software compiler often contained within JVMs. JITs compile Java bytecodes on-the-fly into native machine instructions, thereby reducing the need for interpretation. JVM
See Java Virtual Machine.
local . Refers to any object maintained by the local DB2 subsystem. A local table, for example, is a table maintained by the local DB2 subsystem. Contrast with remote. local variable A variable declared and used within a method or block. Log In the VisualAge for Java IDE, the window that displays messages and warnings during development.
L
large object (LOB) . See LOB. left outer join. The result of a join operation that includes the matched rows of both tables being joined, and preserves the unmatched rows of the first table. See also join. link-edit. To create a loadable computer program using a linkage editor. linker A computer program for creating load modules from one or more object modules or load modules by resolving cross references among the modules and, if necessary, adjusting addresses. In Java, the linker creates an executable from compiled classes. listener In the JDK, a class that receives and handles events. load module. A program unit that is suitable for loading into main storage for execution. The output of a linkage editor. LOB. A sequence of bytes representing bit data, single-byte characters, double-byte characters, or a mixture of single and double-byte characters. A LOB can be up to 2GB -1 byte in length. See also BLOB, CLOB, and DBCLOB. LOB locator. A mechanism that allows an application program to manipulate a large object value in the database system. A LOB locator is a fullword integer value that represents a single LOB value. An application program retrieves a LOB locator into a host variable; it can then apply SQL operations to the associated LOB value using the locator.
M
member In the Java language, an item belonging to a class, such as a field or method. method A fragment of Java code within a class that can be invoked and passed a set of parameters to perform a specific task. middleware A layer of software that sits between a database client and a database server, making it easier for clients to connect to heterogeneous databases. middle tier The hardware and software that resides between the client and the enterprise server resources and data. The software includes a Web server that receives requests from the client and invokes Java servlets to process these requests. The client communicates with the Web server via industry standard protocols such as HTTP and IIOP. morphing The process of extending a Java bean to accept dips. Morphed Java beans are called dippable Java beans and can have one or more dips connected to them. Almost any Java bean or class can be made dippable. See dipping. multithreaded A program where different parts can run at the same time without interfering with each other. multithreading. Multiple TCBs executing one copy of DB2 ODBC code concurrently (sharing a processor) or in parallel (on separate central processors). mutex. Pthread mutual exclusion; a lock. A Pthread mutex variable is used as a locking mechanism to allow serialization of critical
375
sections of code by temporarily blocking the execution of all but one thread.
object The principal building block of object-oriented programs. Objects are software programming modules. Each object is a programming unit consisting of related data and methods. ODBC. See Open Database Connectivity. ODBC driver. A dynamically-linked library (DLL) that implements ODBC function calls and interacts with a data source. Open Database Connectivity (ODBC) . A Microsoft database application programming interface (API) for C that allows access to database management systems by using callable SQL. ODBC does not require the use of an SQL preprocessor. In addition, ODBC provides an architecture that lets users add modules called database drivers that link the application to their choice of database management systems at run time. This means that applications no longer need to be directly linked to the modules of all the database management systems that are supported. outer join. The result of a join operation that includes the matched rows of both tables being joined and preserves some or all of the unmatched rows of the tables being joined. See also join. ORB (Object Request Broker) In object-oriented programming, software that serves as an intermediary by transparently enabling objects to exchange requests and responses. object-oriented design A software design method that models the characteristics of abstract or real objects using classes and objects. Object-oriented design focuses on the data and on the interfaces to it. For instance, an "object-oriented" carpenter would be mostly concerned with the chair he was building, and secondarily with the tools used to make it; a "non-object-oriented" carpenter would think primarily of his tools. Object-oriented design is also the mechanism for defining how modules "plug and play." The object-oriented facilities of Java are essentially those of C++, with
N
native class Machine-dependent C code that can be invoked from Java. For multi-platform work, the native routines for each platform need to be implemented. NCF
See Network Computing Framework.
Network Computing Framework (NCF) An architecture and programming model created to help customer and industry software development teams to design, deploy, and manage e-business solutions across the enterprise. Network News Transfer Protocol (NNTP) In the Internet suite of protocols, a protocol for the distribution, inquiry, retrieval, and posting of news articles that are stored in a central database. nonvisual bean A bean that is not visible to the end user in the graphical user interface, but is visually represented on the free-form surface of the Visual Composition Editor during development. Developers can manipulate nonvisual beans only as icons; that is, they cannot edit them in the Visual Composition Editor as they can edit visual beans. Examples of nonvisual beans include beans for business logic, communication access, and database queries. NNTP
See Network News Transfer Protocol.
NUL. In C, a single character that denotes the end of the string. null. A special value that indicates the absence of information. NUL-terminated host variable. A varying-length host variable in which the end of the data is indicated by the presence of a NUL terminator. NUL terminator. In C, the value that indicates the end of a string. For character strings, the NUL terminator is X'00'.
376
overloading The ability to have different methods with the same identifier, distinguished by their return type, and number and type of arguments. overriding Implementing a method in a subclass that replaces a method in a superclass.
prepared SQL statement. A named object that is the executable form of an SQL statement that has been processed by the PREPARE statement. primary key. A unique, nonnull key that is part of the definition of a table. A table cannot be defined as a parent unless it has a unique key or primary key. process A program executing in its own address space, containing one or more threads. Professional Edition Professional Edition.
See VisualAge for Java,
P
package A program element that contains classes and interfaces. part An existing, reusable software component. All parts created with the Visual Composition Editor conform to the JavaBeans component model, and are referred to as beans. See visual bean and nonvisual bean . persistence In object models, a condition that allows instances of classes to be stored externally, for example in a relational database. Persistence Builder In VisualAge for Java, a persistence framework for object models, which enables the mapping of objects to information stored in relational databases and also provides linkages to legacy data on other systems. plan. See application plan. plan name. The name of an application plan. POSIX. Portable Operating System Interface. The IEEE operating system interface standard which defines the Pthread standard of threading. See Pthread. precompilation. A processing of application programs containing SQL statements that takes place before compilation. SQL statements are replaced with statements that are recognized by the host language compiler. Output from this precompilation includes source code that can be submitted to the compiler and the database request module (DBRM) that is input to the bind process. prepare. The first phase of a two-phase commit process in which all participants are requested to prepare for commit.
program In VisualAge for Java, a term that refers to both Java applets and applications. program element In VisualAge for Java, a generic term for a project, package, class, interface, or method. project In VisualAge for Java, the topmost kind of program element. A project contains Java packages. property An initial setting or characteristic of a bean, for example, a name, font, text, or positional characteristic. Pthread. The POSIX threading standard model for splitting an application into subtasks. The Pthread standard includes functions for creating threads, terminating threads, synchronizing threads through locking, and other thread control facilities.
R
RDBMS. Relational database management system. relational database management system (RDBMS). A relational database manager that operates consistently across supported IBM systems. reentrant . Executable code that can reside in storage as one shared copy for all threads. Reentrant code is not self-modifying and provides separate storage areas for each thread. Reentrancy is a compiler and operating system concept, and reentrancy alone is not enough to guarantee logically consistent results when multithreading. See threadsafe.
377
reference An object's address. In Java, objects are passed by reference rather than by value or by pointers. remote. Refers to any object maintained by a remote DB2 subsystem; that is, by a DB2 subsystem other than the local one. A remote view, for instance, is a view maintained by a remote DB2 subsystem. Contrast with local. remote debugger A debugging tool that debugs code on a remote platform. Remote Function Call (RFC) SAP's open programmable interface. External applications and tools can call ABAB/4 functions from the SAP System. You can also call third party applications from the SAP System using RFC. RFC is a means for communication that allows implementation on all R/3 platforms. Remote Method Invocation (RMI) RMI is a specific instance of the more general term RPC. RMI allows objects to be distributed over the network; that is, a Java program running on one computer can call the methods of an object running on another computer. RMI and java.net are the only 100% pure Java APIs for controlling Java objects in remote systems. Remote Object Instance Manager In Remote Method Invocation, a program that creates and manages instances of server beans through their associated server-side server proxies. Remote Procedure Calls (RPC) RPC is a generic term referring to any of a series of protocols used to execute procedure calls or method calls across a network. RPC allows a program running on one computer to call the services of a program running on another computer. repository In VisualAge for Java, the permanent storage area containing all open and versioned editions of all program elements, regardless of whether they are currently in the workspace. The repository contains the source code for classes developed in (and provided with) VisualAge for Java, and the bytecode for classes imported from the file system. Every time you save a method in the IDE, it is automatically
updated in the repository. See also SCM repository and shared repository.
Repository Explorer In VisualAge for Java, the window from which you can view and compare editions of program elements that are in the repository. requester. Also application requester (AR). The source of a request to a remote RDBMS, the system that requests the data. resource file A non-code file that may be referred to from your Java program in VisualAge for Java. Examples include graphic and audio files. result set. The set of rows returned to a client application by a stored procedure. result set locator. A 4-byte value used by DB2 to uniquely identify a query result set returned by a stored procedure. result table. The set of rows specified by a SELECT statement. right outer join. The result of a join operation that includes the matched rows of both tables being joined and preserves the unmatched rows of the second join operand. See also join. RMI (Remote Method Invocation) Remote Method Invocation.
See
RMI Access Builder A VisualAge for Java Enterprise tool that generates proxy beans and associated classes and interfaces so you can distribute code for remote access, enabling Java-to-Java solutions. RMI compiler The compiler that generates stub and skeleton files that facilitate RMI communication. This compiler can be automatically invoked by the RMI Access Builder, and can also be invoked from the Tools menu item. RMI registry A server program that allows remote clients to get a reference to a server bean. rollback . The process of restoring data changed by SQL statements to the state at its last commit point. All locks are freed. Contrast with commit.
378
RPC
runtime system The software environment where compiled programs run. Each Java runtime system includes an implementation of the Java Virtual Machine.
serialization Turning an object into a stream, and back again. server The computer that hosts the Web page that contains an applet. The .class files that make up the applet, and the HTML files that reference the applet reside on the server. When someone on the Internet connects to a Web page that contains an applet, the server delivers the .class files over the Internet to the client that made the request. The server is also known as the originating host. server bean The bean that is distributed using RMI services and is deployed on a server. servlet Server-side programs that execute on and add function to Web servers. Java servlets allow for the creation of complicated, high-performance, cross-platform Web applications. They are highly extensible and flexible, making it easy to expand from client or single-server applications to multi-tier applications. SGML See Standardized Generalized Markup Language. single precision A floating-point number that contains 32 bits. See also double precision. SmartGuide In IBM software products, an active form of help that guides you through common tasks. Software Configuration Management (SCM) The tracking and control of software development. SCM tools typically offer version control and team programming features. sourced function. A function that is implemented by another built-in or user-defined function already known to the database manager. This function can be a scalar function or a column (aggregating) function; it returns a single value from a set of values (for example, MAX or AVG). Contrast with external function and built-in function. source type. An existing type that is used to internally represent a distinct type.
S
sandbox A restricted environment, provided by the Web browser, in which Java applets run. The sandbox offers them services and prevents them from doing anything naughty, such as doing file I/O or talking to strangers (servers other than the one from which the applet was loaded). The analogy of applets to children led to calling the environment in which they run the "sandbox." scalar function. An SQL operation that produces a single value from another value and is expressed as a function name followed by a list of arguments enclosed in parentheses. See also column function. SCM
See Software Configuration Management.
SCM repository In VisualAge for Java, a generic term for the data store of any external software configuration management (SCM) tool. Some SCM tools refer to this as an archive. scope Determines where an identifier can be used. In Java, instance and class variables have a scope that extends to the entire class. All other identifiers are local to the method where they are declared. Scrapbook In VisualAge for Java, the window from which you can write, edit, and test fragments of code without having to define an encompassing class or method. Secure Socket Layer (SSL) SSL is a security protocol which allows communications between a browser and a server to be encrypted and secure. SSL prevents eavesdropping, tampering or message forgery on your Internet or intranet network. security Features in Java that prevent applets downloaded off the Web from deliberately or inadvertantly doing damage. One such feature is the digital signature, which ensures that an applet came unmodified from a reputable source.
379
SQL Structured Query Language. A language used by database engines and servers for data acquisition and definition. SQL authorization ID (SQL ID). The authorization ID that is used for checking dynamic SQL statements in some situations. SQL Communication Area (SQLCA). A structure
used to provide an application program with information about the execution of its SQL statements.
stored procedure. A user-written application program, that can be invoked through the use of the SQL CALL statement. stream A communication path between a source of information and its destination. Structured Query Language (SQL) . A standardized language for defining and manipulating data in a relational database. subclass A class that inherits all the methods and variables of another class (its superclass). Its superclass might be a subclass of another class in the hierarchy. subtype A type that extends another type (its supertype ). superclass A class that defines the methods and variables inherited by another class (its subclass). supertype A type that is extended by another type (its subtype). Swing Set A group of lightweight, ready-to-use components developed by JavaSoft. The components range from simple buttons to full-featured text areas to tree views and tabbed folders. synchronized This Java keyword specifies that only one thread can run inside a method at once.
SQL Descriptor Area (SQLDA). A structure that describes input variables, output variables, or the columns of a result table. SQLCA. SQL communication area. SQLDA. SQL descriptor area. SQL/DS. SQL/Data System. Also known as DB2 for VSE & VM. SSL
See secure socket layer.
Standardized Generalized Markup Language An ISO/ANSI/ECMA standard that specifies a way to annotate text documents with information about types of sections of a document. statement handle. In DB2 ODBC, the data object that contains information about an SQL statement that is managed by DB2 CLI. This includes information such as dynamic arguments, bindings for dynamic arguments and columns, cursor information, result values and status information. Each statement handle is associated with the connection handle. static field
See class variable. See class method.
T
table. A named data object consisting of a specific number of columns and some number of unordered rows. Synonymous with base table or temporary table. task control block (TCB). A control block used to communicate information about tasks within an address space that are connected to DB2. An address space can support many task connections (as many as one per task), but only one address space connection. See address space connection. TCB. MVS task control block. TCP/IP See Transmission Control Protocol based on IP.
static method
static SQL. SQL statements, embedded within a program, that are prepared during the program preparation process (before the program is executed). After being prepared, the SQL statement does not change (although values of host variables specified by the statement might change).
380
temporary table. A table created by the SQL CREATE GLOBAL TEMPORARY TABLE statement that is used to hold temporary data. Contrast with result table. thin client Thin client usually refers to a system that runs on a resource-constrained machine or that runs a small operating system. Thin clients don't require local system administration, and they execute Java applications delivered over the network. third tier The third tier, or back end, is the hardware and software that provides database and transactional services. These back-end services are accessed through connectors between the middle-tier Web server and the third-tier server. Though this conceptual model depicts the second and third tier as two separate machines, the NCF model supports a logical three-tier implementation in which the software on the middle and third tier are on the same box. thread A separate flow of control within a program. threadsafe. Characteristic of code that allows multithreading both by providing private storage areas for each thread, and by properly serializing shared (global) storage areas. timestamp. A seven-part value that consists of a date and time expressed in years, months, days, hours, minutes, seconds, and microseconds. trace. A DB2 facility that provides the ability to monitor and collect DB2 monitoring, auditing, performance, accounting, statistics, and serviceability (global) data. transaction (1) In a CICS program, an event that queries or modifies a database that resides on a CICS server. (2) In the Persistence Builder, a representation of a path of code execution. (3) The code activity necessary to manipulate a persistent object. For example, a bank application might have a transaction that updates a company account. transient This Java keyword specifies that a field is not included in the serial representation of an object. See serialization .
Transmission Control Protocol based on IP (1) A network communication protocol used by computer systems to exchange information across telecommunication links. (2) An Internet protocol that provides for the reliable delivery of streams of data from one host to another. type In VisualAge for Java, a generic term for a class or interface.
U
UDF. User-defined function UDT. User-defined data type Uniform Resource Locator (URL) The unique address that tells a browser how to find a specific Web page or file. Unicode A 16-bit international character set defined by ISO 10646. See also ASCII. user-defined data type (UDT) . See distinct type. user-defined function (UDF). A function defined to DB2 using the CREATE FUNCTION statement that can be referenced thereafter in SQL statements. A user-defined function can be either an external function or a sourced function. Contrast with built-in function. URL
See Uniform Resource Locator.
V
variable (1) An identifier that represents a data item whose value can be changed while the program is running. The values of a variable are restricted to a certain data type. (2)A data element that specifies a value that can be changed. A COBOL elementary data item is an example of a variable. Contrast with constant. virtual machine A software or hardware implementation of a central processing unit (CPU) that manages the resources of a machine and can run compiled code. See Java Virtual Machine . visual bean In the Visual Composition Editor, a bean that is visible to the end user in the graphical user interface.
381
Visual Composition Editor In VisualAge for Java, the tool you can use to create graphical user interfaces from prefabricated beans, and to define relationships (called connections) between beans. The Visual Composition Editor is a page in the class browser. visual servlet A servlet that is designed to be built using the VisualAge for Java Visual Composition Editor. VisualAge for Java, Enterprise Edition An edition of VisualAge for Java that is designed for building enterprise Java applications, and has all of the Professional Edition features plus support for developers working in large teams, developing high-performance or heterogeneous applications, or needing to connect Java programs to existing enterprise systems. VisualAge for Java, Entry Edition An edition of VisualAge for Java suitable for learning and building small projects of 500 classes or less. It is available as a no-charge download from VisualAge for Java and VisualAge Developer Domain Web sites. VisualAge for Java, Professional Edition complete Java development environment, including easy access to JDBC-enabled databases for building Java applications.
A
Workbench In VisualAge for Java, the main window from which you can manage the workspace, create and modify code, and open browsers and other tools. workspace The work area that contains the Java code that you are developing and the class libraries on which your code depends. Program elements must be added to the workspace from the repository before they can be modified. wrapper Code that provides an interface for one program to access the functionality of another program. WWW
See World Wide Web.
X
X/Open. An independent, worldwide open systems organization that is supported by most of the world's largest information systems suppliers, user organizations, and software companies. X/Open's goal is to increase the portability of applications by combining existing and emerging standards. 100% Pure Java Sun Microsystems initiative to certify that applications and applets are purely Java-written.
W
WebSphere WebSphere is the cornerstone of IBM's overall Web strategy, offering customers a comprehensive solution to build, deploy and manage e-business Web sites. The product line provides companies with an open, standards-based, Web server deployment platform and Web site development and management tools to help accelerate the process of moving to e-business. world readable files A permission level on Web servers specifying that files can be read by any user. World Wide Web A network of servers that contain programs and files. Many of the files contain hypertext links to other documents available through the network.
382
CFRM CLI CLP CPU CSA DASD DB2 PM DBAT DBCTL DBD DBID DBRM DCL DDCS DDF DDL DLL DML DNS DRA DRDA DTT
coupling facility resource management call level interface command line processor central processing unit common storage area direct access storage device DB2 performance monitor database access thread database control subsystem database descriptor database identifier database request module data control language distributed database connection services distributed data facility data definition language dynamic load library manipulation language data manipulation language domain name server
AR ARM AS ASCII
383
EA EBCDIC
extended addressability extended binary coded decimal interchange code enhanced catalog sharing extended common storage area environment descriptor management enterprise resource planning Enterprise Systems Architecture external CICS interface functional track directory File Transfer Program gigabyte (1,073,741,824 bytes) group buffer pool global resource serialization graphical user interface high performance Java or the high performance Java compiler International Business Machines Corporation integrated catalog facility integrated coupling facility internal coupling migration facility instrumentation facility component identifier instrumentation facility interface internal resource lock manager
ISPF ISV I/O ITSO IVP JDBC JFS JVM KB LPAR LOB LPL LRSN LVM MB MQ MQA MQI OBD ODBC OS/390 PAV PDS PSID PSP
interactive system productivity facility independent software vendor input/output International Technical Support Organization installation verification process Java Database Connectivity journaled file systems Java Virtual Machine kilobyte (1,024 bytes) logically partitioned mode large object logical page list log record sequence number logical volume manager megabyte (1,048,576 bytes) message and queueing (IBM software) message queue agent message queue interface object descriptor in DBD Open Data Base Connectivity Operating System/390 parallel access volume partioned data set pageset identifier preventive service planning
ECS ECSA EDM ERP ESA EXCI FDT FTP GB GBP GRS GUI HPJ
384
PTF PUNC QMF RACF RBA RID RRS RRSAF RS RR SDK SMIT SNA SP SRB STC TCB WLM
program temporary fix possibly uncommitted Query Management Facility Resource Access Control Facility relative byte address record identifier resource recovery services resource recovery services attach facility read stability repeatable read software developers kit System Management Interface Tool systems network architecture stored procedure system resource block started task task control block workload manager
385
386
Index Symbols
"CALL" is not a valid database alias name 115 .class files 149 .jar file 150 .java file 149 .profile 59, 63, 64, 72, 80, 81, 170 DB2SQLJPROPERTIES 71 .ser files 149 EBCDIC 162 USS 162 COLLID 123, 126, 131, 168 COMMENT ON 197 COMMENT ON PROCEDURE 269 COMMIT ON RETURN 262, 274 CONNECT statement 187, 193 savepoint 209 connection pooling DDF 202 CREATE PROCEDURE 123, 181, 257 schema 269 CREATE TRIGGER 226 CURRENT PATH 181, 234, 237, 238, 239, 240 schema 236 CURRENT SERVER 192 CURRENT SQLID 233 customize 119
A
AIX JDBC program preparation 144 SQLJ program preparation 149 ALLOCATE CURSOR 193, 194 ALTER INDEX 183 ALTER PROCEDURE 182 ALTER TABLESPACE 183 ASSOCIATE LOCATORS 193 authorization client application 174 hopping 197 Java stored procedures 120 JDBC client 174 authorization checking 121
D
data propagation identity columns 229 data set passwords 181 Data sharing 73 data sharing identity columns 230 DB2 data set passwords 181 JDBC programs 7 package 89 schema 233 shared read-only data 181 SQLJ programs 8 type 1 indexe 181 type 2 indexes 181 DB2 Connect 106 DB2 package 119, 167 DB2 plan 167 DB2 Stored Procedure Builder 105 DB2 utilities identity columns 218 db2jdbc.cursors 71 db2profc 9, 79, 130, 133, 150, 160, 167 db2profile 80, 81 DB2SQLJATTACHTYPE 72 DB2SQLJDBRMLIB 73 DB2SQLJJDBCPROGRAM 72
B
BEGIN ATOMIC 226 Bind DBPROTOCOL option 193 PATH option 181, 240
C
CALL statement 171 Cannot call a schema-qualified stored procedure 118 CATMAINT 111 catmaint 183 class files 133 Class Not Found at runtime 106 Class.forName 162 CLASSPATH 60, 61, 65, 70, 80, 81, 143 COBOL 23, 172 Code translation 162 ASCII 162
387
DB2SQLJPLANNAME 72, 167 DB2SQLJPROPERTIES 61, 64, 71, 167, 170 DB2SQLJSSID 72 DBPROTOCOL bind option 193 DBRM 119, 133, 167 DDF connection pooling 202 DRDA enhancements 197 MODE(SUSPEND) 203 debugging SPB 104 stored procedures 103 writing to a text file 104 DESCRIBE CURSOR 193, 194 DESCRIBE PROCEDURE 193 DISPLAY PROCEDURE command 280 DRDA 187 DDF enhancements 197 hopping 195 Loop back 195 OPTIMIZE FOR n ROWS 198 query block size 198 savepoint 209 SNA connections 188 stored procedures 243 TCP/IP connections 188 Three-part name 189 DROP PROCEDURE 151 DYNAMICRULES 120, 121 DYNAMICRULES(DEFINEBIND) JDBC 121 DYNAMICRULES(INVOKERUN) JDBC 122
E
Enterprise Toolkit for OS/390 4, 58 ENVAR 71 error message SQLCODE -965 77 error messages DB2 RC 00E79107 76, 77 00E79108 77 HPJ HPJ3115(S) 76, 106 Out of storage -- HPJ compile JDBC and
SQLJ classes 76 Unable to load HPJ module during HPJ compile 76 Java Class Not Found at runtime 106 JAR files - removing, refreshing 146 JNI panic during db2profc 118 Method Not Found at runtime 107 Path or file name "Java" not found 79 SQL20201N 114 Unable to find user class 76 Unable to find user method 77 Other Cannot call a schema-qualified stored procedure 118 other CEE5207E 77 DSNL065I 285 DSNL066I 285 DSNL067I 285 DSNL068 285 DSNL069I 285 DSNL070I 286 DSNL071I 286 DSNL072 286 DSNL073I 286 ICH408I 77 SQLCODE +585 239 -104 107 -113 108, 111 -151 218 -204 110 -390 111 -426 255 -440 108, 270, 272 -471 77, 117 -487 264 -577 264 -579 264 -585 239 -586 240 -713 239 -728 188 -729 274 -751 264 -805 191 -818 115 -950 111
388
-965 78, 116 SQL10013N The specified library could not be loaded 113 SQL20201N JAR name is invalid during sqlj.install_jar 114 SQL4301N Java interpreter start-up 112 SQL4304N 116 SQLSTATE 01625 239 42602 108, 111 42705 111 42732 239 42808 218 42815 239 42907 240 51021 116 55023 117 executable-centric migration 159, 161 external savepoint 209
I
identity columns 210, 211 altering 215 copying tables 216 data definition 211 data manipulation 217 data propagation 229 data sharing 230 DB2 family 230 DB2 utilities 218 Indexing 222 properties 220 retrieving values 222 ROWID columns 228 IDENTITY_VAL_LOCAL 224, 225 INCREMENT BY 229 installVAJDLLs 68 Iterator SQLJ 100
F
Fallback Version 6 to Version 5 184
G
GENERATED ALWAYS 217 getConnection method 170 global transactions savepoint 210
H
HOME path 61, 73, 77 Home path 74 Hopping authorization 197 DRDA and pivate protocol 195 Loop back 195 host variables 181 HPJ 58, 62, 68, 70, 74, 93, 96 base libraries 60 dynamic load library 70 JDBC/SQLJ drivers 57 HPJ3115(S) message received during HPJ compile 106 HPJ3TBY 76
JAR file 146, 147, 148, 150, 151, 153, 154, 155 JAR routines sqlj.install_jar 146, 155 sqlj.remove_jar 146 sqlj.replace_jar 155 Java classes 4 CLASSPATH 4 JAR file 4, 88 methods 4 package 4, 86, 91, 93, 95, 96 Java Development Kit 4 Java method 86 Java package statement 124, 131 Java stored procedures case sensitive 92 data sharing 73 DB2 portability 24 deployment 157 execution OS/390 163 UNIX 163 Windows NT 163 LOBs 90 migrating between environments on S/390 157 naming 83
389
output parameters 90 parameters 90 preparation 119 system setup 76 OS/390 57 UNIX 80 Windows NT 78 Java stored procedures, compiled 57 JAVA_HOME 65, 80, 81 javac command 149 JAVAENV data set 57, 60, 62, 63, 69 contents 70 JDBC 7, 23, 120, 172 client call stored procedure 173 create SQL string 172 input parameters 173 output parameters 173 client applications 167 client authorization 174 client coding 170 cursors file 71 dynamic load libraries 70 DYNAMICRULES(DEFINEBIND) 121 DYNAMICRULES(INVOKEBIND) 122 insenting a null 99 migration 160 program preparation 122 OS/390 124 serialized profile 61 stored procedures 119 null handling 97 JDBC DBRM DSNJDBC1 76 DSNJDBC2 76 DSNJDBC3 76 DSNJDBC4 76 JDBC driver 11 JDK 57, 78, 79, 80, 123 JNI panic during db2profc 118 JSPDEBUG 67, 104 JVM 3, 5, 119
M
Method Not Found at runtime 107 migration executable-centric 159 source-centric 158 MODE(SUSPEND) Command syntax 204 DDF 203
N
nested stored procedures 274 COMMIT ON RETURN 274 three-part name 275 NT JDBC program preparation 144 SQLJ program preparation 149 Null handling JDBC inserting 99 JDBC stored procedures 97 null values 97
O
ODBC 19 OPTIMIZE FOR n ROWS 197 OS/390 High Performance Java Compiler 5 OS/390 UNIX System Services 4, 143
P
PATH bind option 181, 240 PATH system variable 79 PDSE 62, 66, 124, 133 porting stored procedutes UNIX/NT and S/390 161 prepareCall 173 printStackTrace 102 private protocol hopping 195 SNA connections 188 program preparation JDBC 122 SQLJ 129
L
LABEL ON 197 LD_LIBRARY_PATH 65, 69, 70, 80, 81 LIBPATH 60, 65, 69, 70, 80, 81
390
Q
Query_oi_summ 34
RACF 66, 329, 330, 335 PERMIT command 335 profiles 335 RDEFINE command 335 RACF user IDs stored procedures 335 RELEASE SAVEPOINT 208 ResultSet SQLJ 100 ROLLBACK TO SAVEPOINT 209 ROWID columns identity columns 228 RRS 57, 58, 59, 66
S
sample application 19 components 21 naming conventions 22 package names 22 savepoint 208 DRDA access 209 global transactions 210 roll back 209 stored procedures 210 triggers 210 UDFs 210 UNIQUE option 208 schema 125 characteristics 234 CURRENT PATH 236 DB2 support 233 explicit specification 234 implicit specification 235 SET CURRENT PATH 237 SYSFUN 237 SYSIBM 237 SYSPROC 237 Serialized profiles directory 61 SET CONNECTION 192, 193 SET CURRENT PATH 240 SET CURRENT SQLID 121 setNull 97 shared read-only dat 181 SNA connections
DRDA 188 private protocol 188 source-centric migration 158, 161 SPB 105 SQL string 172 preparation 173 SQL10013N 113 SQL4301N 112 SQL4304N 116 SQLJ 8, 23, 120, 174 client application 100 client applications 167 client coding 174 command 132 dynamic load libraries 70 Iterators 100 migration 160 program preparation OS/390 129 ResultSets 100 serialized profile 149 stored procedures 119, 160 authorization 120 error handling 102 inserting a null 100 receiving a null 100 SQLJ properties 57, 60, 61, 70, 71, 72 sqlj.install_jar 145, 146, 148, 151, 153, 155, 161 sqlj.remove_jar 146, 151, 153, 155 sqlj.replace_jar 148, 155 SQLJ/JDBC base libraries 60 SQLJPLAN 167, 170 -START DATABASE 183 START WITH 229 -STOP DATABASE 183 stored procedure 12 Stored Procedure Builder 164 stored procedures authorization 258, 275 calling with a null value 97 COMMIT_ON_RETURN 254 CONNECT statement 246, 248, 249 , 258 CONNECT TYPE 1 248, 249 CONNECT TYPE 2 248 debugging 103 DLI support 255 DML 258 LOBs 259
391
nested 274 parameters 97, 262 privileges 268 result sets 251, 252, 253 savepoint 210 SQL CALL 246 time line characteristics 247 triggers 259 UDFs 258 UDTs 259 usage of schemas 258, 268 SYSCAT.PROCEDURES 182 SYSIBM.SYSCOLDIST 183 SYSIBM.SYSCOLDISTSTATS 183 SYSIBM.SYSJARCONTENTS 145, 150 SYSIBM.SYSPARMS 181, 182, 257 , 267, 281 SYSIBM.SYSPROCEDURES 96, 123, 125, 181, 182, 250, 251, 257, 267, 270, 281, 335 SYSIBM.SYSROUTINES 96, 181, 182, 257, 267, 281 SYSIBM.SYSSEQUENCES 221 SYSIBM.SYSSEQUENCESDEP 221
compatibility mode 338, 345 enable stored procedure support 331 goal mode 339, 345 Java stored procedures 66 JAVAENV data set 67 RACF 335 recommendations 344 service definition 342 service policy 342
T
TCP/IP connections DRDA 188 Three-part name DRDA 189 Package requirements 191 trigger savepoint 210 type 1 indexes 181 type 2 indexes 181
U
UNIQUE OPTION savepoint 208 UNIX Systems Services 57
V
VisuaAge for Java Enterprise Edition 58 VisualAge for Java 4, 8 Enterprise Edition for OS/390 119
W
wasNull 99 WLM 58, 59, 66, 163
392
What other subjects would you like to see IBM Redbooks address?
Please rate your overall satisfaction: Please identify yourself as belonging to one of the following groups: Your email address: The data you provide here may be used to provide you with information from IBM or our business partners about our products, services or activities. Questions about IBMs privacy policy?
O Very Good
O Good
O Average
O Customer O Business Partner O IBM, Lotus or Tivoli Employee O None of the above
O Please do not use the information collected here for future marketing or promotional contacts or other communications beyond the scope of this transaction.
The following link explains how we protect your personal information. ibm.com/privacy/yourprivacy/
393
Implementation guide for DB2 Java stored procedures DB2 Java stored procedures across platforms Reference guide for network computing enhancements in DB2 UDB for OS/390 V6
Stored procedures can provide major benefits in the areas of application performance, code re-use, security, and integrity. The DB2 Family of products has offered support for stored procedures for some time, with each release offering significant enhancements over the last. In the meantime, Javas inherent portability and openness, combined with the availability of skilled programming resource, has made it an increasingly attractive choice as the central plank in the e-business strategy of many organizations. Until recently, DB2 did not support stored procedures written in Java, so the advantages of the two technologies could not be combined. The latest releases of DB2 have changed all that, opening up new possibilities for secure, highly portable application development. This IBM Redbook aims to give the reader an in-depth understanding of the techniques and issues associated with the development of DB2 stored procedures written in SQLJ and JDBC. The extensive collection of sample code presented in this book and included on the accompanying CD-ROM was designed to run against DB2 UDB Server across the OS/390, Windows, and UNIX platforms.
BUILDING TECHNICAL INFORMATION BASED ON PRACTICAL EXPERIENCE IBM Redbooks are developed by the IBM International Technical Support Organization. Experts from IBM, Customers and Partners from around the world create timely technical information based on realistic scenarios. Specific recommendations are provided to help you implement IT solutions more effectively in your environment.