Accessing DB2 UDB for iSeries data from AIX Applications

58
Accessing DB2 UDB for iSeries data from AIX Applications Optimize AIX access to your DB2 UDB for iSeries database by Jarek Miszczyk IBM eServer Solutions Enablement September 2004 © Copyright IBM Corporation, 2004. All Rights Reserved. All trademarks or registered trademarks mentioned herein are the property of their respective holders.

Transcript of Accessing DB2 UDB for iSeries data from AIX Applications

Accessing DB2 UDB for iSeries data from AIX Applications

Optimize AIX access to your DB2 UDB for iSeries database

by Jarek Miszczyk

IBM eServer Solutions Enablement

September 2004

copy Copyright IBM Corporation 2004 All Rights Reserved All trademarks or registered trademarks mentioned herein are the property of their respective holders

Table of Contents Introduction 1DB2 UDB for iSeries runtime 1

DB2 SQL Runtime Interfaces 2Static SQL 2Dynamic SQL 3Extended Dynamic SQL 3

JDBC Data Access 4Initial Configuration Considerations 4

Virtual Versus Physical LAN 5Tuning DB2 UDB for iSeries Access with IBM Toolbox for Java and JTOpen Driver 6

Connection Pooling 7Extended Dynamic SQL and Statement Caching 9Reusable Open Data Paths (ODPs) 9Block Inserts 10

WebSphere Considerations 12Connection Pooling and Statement Caching 12Extended Dynamic SQL 12Changing the WebSphere Application Server default isolation level 13

Troubleshooting 16Job Log Messages 16JDBC Trace Utility 17Database Monitor 19

IBM DB2 JDBC Universal Driver 19Obtaining a Connection to DB2 UDB for iSeries 20Considerations 21

DB2 Connect data access 22DB2 Connect in a nutshell 23Prerequisites 24DB2 Connect configuration 24

Configuration steps in the iSeries partition 24ADDRDBDIRE RDB(TPLX) RMTLOCNAME(LOCAL) 24

Configuration steps in the AIX partition 26Accessing DB2 UDB for iSeries from C embedded SQL 34

Prerequisites 34Static SQL and SQL packages 34Simple embedded SQL application 34

Distributed Join 35Distributed Join Example 36

Connection Pooling and Connection Concentrator 38Troubleshooting 38Job Log Messages 39DB2 DRDA trace utility 40

Accessing DB2 for iSeries from CLI 40Prerequisites 40

Dynamic SQL and Access Plan Caching 40Simple DB2 CLI C++ Application 40

Reusable Open Data Paths (ODPs) 41Techniques to Further Improve DB2 CLI Performance 42

Connection Pooling 42Blocking 43Troubleshooting 43Job Log Messages 43CLI Trace 43

Trademarks 44

Additional Information 44Acknowledgments 44Appendix A Source Listing of TestJDBCjava 45Appendix B mdash Source Listing of cursorsjsqc 48Appendix C mdash Source Listing of testclicpp 52

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Introduction AIX 5Ltrade is quickly becoming the preferred commercial implementation of UNIX operating system The recently announced IBMreg eServertrade i5 servers can run AIX 5L in as many as 160 separate logical partitions (LPARs) This gives iSeriestrade customers a very rich portfolio of business applications that are currently available on AIXreg Traditionally many organizations use the iSeries server as a reliable and highly scalable database server The iSeries database DB2reg UDB for iSeries is fully integrated in i5OSreg and OS400reg and exploits its robust features such as single-level storage tight security and object-based architecture For these reasons IBM believes that DB2 UDB for iSeries will remain the database of choice for most iSeries shops

Generally AIX applications can use several programming environments to access the iSeries database JDBC ODBC DB2 CLI and embedded SQL However depending on the protocol and specific driver implementation an AIX application can directly communicate with a back-end database server job on an iSeries server or it may require DB2 Connecttrade Gateway services Currently only IBM Toolbox for Java JDBC driver supports a direct native connection to iSeries servers All other interfaces require DB2 Connect This paper provides connectivity options implementation tips and a number of coding examples that illustrate how to optimize the access to a DB2 UDB for iSeries database from an AIX partition for each of these programming interfaces

Disclaimer The performance information in this document is for guidance only System performance depends on many factors including system hardware system and user software and user application characteristics Customer applications must be carefully evaluated before estimating performance IBM does not warrant or represent that a user can or will achieve similar performance No warranty on system performance or price performance is expressed or implied in this document

DB2 UDB for iSeries runtime As mentioned the DB2 UDB for iSeries engine is integrated into i5OS It uses and depends on the operating system to provide many services such as locking security archivebackup buffer management and transaction services The operating system in turn uses and relies on the database engine to provide certain services From the DB2 point-of-view an AIX application running in a partition on an eServer i5 server is just a regular remote database client that uses the back-end database server jobs to submit SQL requests to SQL runtime The DB2 SQL runtime supports several interfaces that can be used to submit SQL statements The interface that is used by a particular client depends on the type of database driver used by the client to connect to DB2 For example JTOpen JDBC driver supports both dynamic and extended dynamic SQL while DB2 Universal JDBC driver supports just the dynamic SQL interface This topic will be discussed in details throughout this paper The typical data flow between an AIX client back-end database server job and DB2 SQL runtime is illustrated in Figure 1

1

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 1 - DB2 UDB for iSeries SQL runtime

DB2 SQL Runtime Interfaces Letrsquos briefly discuss the DB2 SQL runtime interfaces

Static SQL

The SQL statements are embedded in the source code of a host application program For example a stored procedure can be written in C++ and contains a number of embedded SQL statements In this case the stored procedure source code has to be processed by an SQL preshycompiler prior to compiling the host application program itself At that time the embedded SQL statements are parsed validated and optimized As a result of this process an access plan gets created for each statement The access plan is a control structure that contains information on the actions necessary to satisfy an SQL request Typically it contains

bull An access method that the optimizer selected for a given statement (for example table scan)

bull Information on associated tables and indexes that is used at runtime to determine if an access plan needs to be rebuilt due to table changes or index changes

bull Any applicable environment information such as jobrsquos code page

The access plan is then permanently stored in the program object and can be reused when the program is executed

In another scenario an embedded SQL application may be executed on a client for example in an AIX partition and access the DB2 UDB for iSeries through DB2 Connect In this case a client-side DB2 SQL precompiler stores the static SQL statements in a bind file The bind file is then

2

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

bound to the back-end database server The bind process creates an SQL package on the DB2 UDB for iSeries The package contains the access plans and other control structures that can be reused when the client program executes

Static SQL is the most efficient way to process SQL requests on an iSeries server

Dynamic SQL Dynamic SQL statements are parsed validated and optimized at the time an SQL application is executed The SQL statements are passed to the database manager in the form of a character string using the SQL statements PREPARE or EXECUTE IMMEDIATE The IBM Toolbox for JavaJTOpen JDBC driver uses this method if Extended Dynamic SQL support is not enabled The Dynamic SQL is also used by the dynamic SQL interfaces such as DB2 Call Level Interface (DB2 CLI) ODBC and JDBC when a client application connects to DB2 UDB for iSeries through DB2 Connect gateway Refer to DB2 Connect data access on page 22 of this paper for more details

Extended Dynamic SQL In Extended Dynamic SQL the SQL statements are dynamic However SQL packages are used to make the implementation of the dynamic SQL statements similar to that of static SQL The SQL statements are parsed validated and optimized and the resulting access plan is permanently stored in a SQL package Note that this process is dynamic and new statements can be added to the SQL package at the run time The IBM Toolbox for JavaJTOpen JDBC driver can take advantage of the Extended Dynamic SQL support

3

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

JDBC Data Access This section provides implementation tips and coding examples that illustrate how to optimize the access to your DB2 UDB for iSeries database from a AIX partition by using various JDBC drivers Currently IBM offers several AIX-enabled JDBC drivers that support DB2 UDB for iSeries

bull Type 4 drivers mdash IBM Toolbox for Java JTOpen and DB2 Universal JDBC Driver bull Type 2 driver mdash DB2 JDBC Type 2 Driver

The IBM Toolbox for Java iSeries driver has been implemented in pure Javatrade and optimized for accessing DB2 UDB for iSeries data It uses native iSeries protocol to communicate with the back-end database server job JTOpen is the open-source version of the IBM Toolbox for Java Licensed Program Product (LPP)

The DB2 Universal JDBC Driver is also a pure Java implementation It is a part of the DB2 UDB for AIX Version 8 product and it uses the Distributed Relational Database Architecture (DRDA) protocol for clientserver communications The driver is compatible with various DB2 UDB server platforms with appropriate DRDA Application Server (AS) level support and prerequisite stored procedures It also supports Type 2 connectivity when accessing DB2 UDB for Linuxreg UNIX and Windowsreg (DB2 UDB for LUW) databases

The traditional DB2 JDBC Type 2 Driver is built on top of DB2 Call Level Interface (CLI) It requires DB2 Connect functionality to access DB2 UDB for iSeries This is a legacy driver and IBM currently recommends that the DB2 Universal JDBC driver is used instead

Initial Configuration Considerations Practical experience shows that the JDBC application performance greatly depends on the programming techniques and the SQL access tuning However significant performance gains can be achieved by simply tweaking the AIX partition environment For example a virtual LAN connection to the back-end database can significantly streamline the data flow

4

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Virtual Versus Physical LAN One of the most significant benefits of installing AIX in an iSeries partition is the ability to utilize virtual LAN and virtual DASD This usually results in reduced hardware costs through improvements in data transfer performance and enhanced disk protection The performance tests conducted by the IBM eServer Solutions Enablement team showed that the Virtual 1Gb LAN delivered a data throughput similar to dedicated 1Gb Ethernet adapters (model 5706) connected via a dedicated Ethernet segment An example configuration is illustrated in Figure 2

Figure 2 VLAN vs 1 Gb Ethernet IOA configuration

Although similar performance can be expected for VLAN and 1Gb Ethernet the VLAN configuration has two advantages over the physical LAN connection

bull No additional communications gear is required bull It is a dedicated point-to-point connection so there is no interference from other devices on

the same network segment

On the other hand certain application scenarios may benefit from a physical LAN adapter dedicated to an AIX partition For instance in a three-tier application architecture clients connect to an application server running in a AIX partition The application server in turn connects to DB2 UDB for iSeries where data is stored and retrieved In this case configuring a separate physical LAN connection in a AIX partition has the following advantages

bull An unnecessary additional hop is eliminated from the network route bull Client-application server traffic does not unnecessarily saturate i5OS communications gear

5

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Tuning DB2 UDB for iSeries Access with IBM Toolbox for Java and JTOpen Driver This section covers JDBC implementation details for a sample Java program called TestJDBC (the source is provided at the end of this paper in Appendix A) The application uses the Java Naming and Directory Interface (JNDI) to obtain a database connection deletes 5000 records generates and inserts 5000 records and finally retrieves the newly inserted records from an SQL table called COFFEES The application executes in an AIX partition and accesses the DB2 UDB for iSeries through the JTOpen (or IBM Toolbox for Java) driver Figure 3 shows the software components involved in the execution of this simple application

Figure 3 JDBC client accessing DB2 UDB for iSeries

Apart from the JTOpen driver which can be downloaded from the IBM Toolbox for Java Web site you need three other JAR files to successfully compile and execute the JDBCTest application in a AIX partition

bull providerutiljar and fscontextjar mdashDownload a simple file system JNDI provider from Sun Microsystems JNDI Web site httpjavasuncomproductsjndidownloadsindexhtml

bull jdbc2_0-stdextjar mdash Copy the javaxsql package from the QIBMUserDataJava400ext IFS directory on the iSeries server

The location of the JAR files needs to be added to the CLASSPATH environment variable For instance the following entry could be added to the AIX profile script

6

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

CLASSPATH=homecodeJTOpenjt400jarCLASSPATH=$CLASSPATHhomecodefscontextproviderutiljarCLASSPATH=$CLASSPATHhomecodefscontextfscontextjarCLASSPATH=$CLASSPATHhomecodeJTOpenjdbc2_0-stdextjarexport CLASSPATH

To compile the source use the following command in the AIX partition

javac TestJDBCjava

Although the TestJDBC application is fairly simple it illustrates several important aspects of efficient JDBC programming for DB2 UDB for iSeries

Connection PoolingA JDBC connection can be obtained through either the DataSource or DriverManager object Either method involves significant overhead A fairly large amount of system resources is required to create and maintain the connection and then release it when it is no longer needed JTOpen allows a developer to establish a pool of database connections that can be shared by multiple client applications Connection pooling can improve the response time because the connection pool manager can locate and use an existing connection When the database request is completed the connection returns to the connection pool for reuse

In the JDBCTest sample JNDI was first used to register a connection pool-capable data source Heres an excerpt from the deployDataSource method of the sample application

Hashtable env = new Hashtable()envput(ContextINITIAL_CONTEXT_FACTORY

comsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env) [1]

Register an AS400JDBCConnectionPoolDataSource objectAS400JDBCConnectionPoolDataSource tkcpds = newAS400JDBCConnectionPoolDataSource() [2]tkcpdssetServerName(serverName) tkcpdssetDatabaseName(databaseName) tkcpdssetUser(userName) tkcpdssetPassword(password) tkcpdssetDescription(Toolkit Connection Pooling DataSourceobject) hellip ctxrebind(jdbcToolkitDataSource tkcpds) [3]

At [1] the initial JNDI context is created

Then at [2] an AS400JDBCConnectionPoolDataSource object is instantiated This is the JTOpen implementation of the javaxsqlConnectionPoolDataSource interface An AS400JDBCConnectionPoolDataSource object supports a number of methods that can be used to set iSeries-specific properties of the underlying DataSource object Some of these properties will be discussed in greater detail in the following sections of this paper

At [3] the data source object is bound to an arbitrary name that will be used in the main application Note that the deployDataSource method needs to be executed just once unless some of the data source properties need to be changed In that case the developer would need to rebind

7

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

The JNDI registered data source is then used in the main application to initialize the connection pool

AS400JDBCConnectionPoolDataSource tkcpds = [1](AS400JDBCConnectionPoolDataSource)ctxlookup(jdbcToolkitDataSource) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPool pool = newAS400JDBCConnectionPool(tkcpds)[2] Adds 1 connection to the pool that can be used by the application(creates the physical database connections based on the datasource)poolfill(1) [3] hellip con = poolgetConnection()[4]

At [1] the JNDI service is used to instantiate the AS400JDBCConnectionPoolDataSource

Then at [2] an AS400JDBCConnectionPool object is created This object is responsible for managing the connection pool

At [3] the connection pool is initialized with one connection

The pool object is used at [4] to obtain a database connection There are several additional things the developer should know about this code snippet

bull The advantage of using JNDI to register the data source object as opposed to just instantiating it in the main method is that in a more realistic scenario the data source would be registered just once at application deployment time Additionally the data source properties do not have to be hard-coded in the main method and can be changed at any time and then rebound without affecting the application

bull The AS400JDBCConnectionPool is a proprietary JTOpen implementation of a connection pool Specifically it does not implement the Referenceable interface and thus cannot be bound through JNDI services

bull The JTOpen AS400JDBCConnectionPoolDataSource does not support statement caching as described in the JDBC 30 specification Statement caching is implemented through SQL packages This feature is covered in the following section

Note The native iSeries JDBC driver supports both connection pooling and statement caching in a JDBC 30 compliant manner

8

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Extended Dynamic SQL and Statement Caching As mentioned the JTOpen data source object supports a number of properties that can be used to fine-tune the database performance In this section properties used to enable extended dynamic SQL support (see DB2 SQL Runtime Interfaces section above) and local statement caching will be discussed

Here is a relevant code excerpt from the deployDataSource method

AS400JDBCConnectionPoolDataSource tkcpds = new AS400JDBCConnectionPoolDataSource() hellip tkcpdssetExtendedDynamic(true)[1]tkcpdssetPackage(JDBCDS) [2]tkcpdssetPackageCache(true) [3]tkcpdssetPackageCriteria(select) [4]

At [1] the extended dynamic SQL support is enabled Note that the default is disabled for JTOpen The extended dynamic SQL functionality is often referred to as SQL package support The SQL packages are server-side repositories for SQL statements Packages contain the internal structures such as parse trees and access plans which are needed to execute SQL statements Because SQL packages are a shared resource the information built when a statement is prepared is available to all the users of the package This saves processing time especially in an environment where many users are using the same or similar statements Also because SQL packages are permanent this information is saved across job initiationtermination and IPLs In fact SQL packages can be saved and restored on other servers

At [2] the SQL package is named Note that the actual package name on the iSeries server is JDBCDSBAA The package name is generated by taking the name specified on the client and appending three letters that are an encoded set of the package configuration attributes By default an SQL package does not contain unparameterized select statements This behavior is overridden at [4] by setting the PackageCriteria property to select

At [3] the local statement cache is enabled A copy of the SQL package is cached on the AIX client This may improve application performance in a way similar to JDBC 30 statement caching Note however that local statement caching is not recommended for large SQL packages The copy of an SQL package is cached when the database connection is obtained This may cause increased network traffic as well as slow down the connection setup time

Reusable Open Data Paths (ODPs)An Open Data Path (ODP) definition is an internal i5OS object that is created when certain SQL statements (such as OPEN INSERT UPDATE and DELETE) are executed for the first time in a given job (or connection) The ODP can be thought of as a runtime implementation of an access plan The access plan created at the optimization time provides a recipe or in other words a sequence of steps necessary to execute the statement The ODP on the other hand provides the executable code for all requested IO operations The process of creating new ODP objects is fairly CPU- and IO-intensive so whenever possible the iSeries DB2 runtime tries to reuse existing ODPs For instance a ResultSetclose() call may close the SQL cursor but leave the ODP available to be used the next time the cursor is opened This can significantly reduce the response time in running SQL statements A reusable OPD usually requires 10 to 20 times less CPU resources than a newly created ODP Therefore it is important that the applications employ programming techniques that allow the DB2 runtime to reuse ODPs

With dynamic programming interfaces such as JDBC the most efficient way to avoid full opens is to employ the so-called prepare once execute many programming paradigm Ideally an SQL statement that is executed more than once should be prepared just once mdashfor example in the class constructor mdash and then reused for the consecutive executions At the prepare time the

9

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 engine stores the prepared statement along with the associated statement name in the QZDASOINIT jobs statement cache On the first execution the ODP created for a given statement is associated with the appropriate entry in the statement cache On consecutive executions the prepared statement and the corresponding ODP can be quickly located in the statement cache and reused The code snippet below illustrates the prepare once execute many programming technique

PreparedStatement pstmt = conprepareStatement(INSERT INTO COFFEES VALUES( ))[1] hellip for (int i = 0 i lt outerNumOfLoops i++)

insertfor (int j = 0 j lt numOfLoops j++)

pstmtsetString(1 Lavaza_ + IntegertoString(j)) hellip pstmtaddBatch()

int [] updateCounts = pstmtexecuteBatch()[2]concommit()

At [1] a PreparedStatement pstmt object is instantiated for a parameterized INSERT statement The statement is prepared just once The PreparedStatement object is then repeatedly used at [2] to perform blocked insert

Block Inserts Occasionally the developer may need to initially populate a table or insert a modified result set into a temporary table The efficiency of the insert operation for a large set of records can be dramatically improved by using the executeBatch method rather than the executeUpdate method The JTOpen driver converts parameterized insert statements in an executeBatch method to a block insert statement This significantly reduces the data flow and system resources required to perform the insert The following code snippet shows how to take advantage of the executeBatch method

10

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

PreparedStatement pstmt =conprepareStatement(INSERT INTO COFFEES VALUES( ))[1]for (int j = 0 j lt numOfLoops j++) pstmtsetString(1 Lavaza_ + IntegertoString(j))pstmtsetInt(2 i)pstmtsetFloat(3 499f)pstmtsetInt(4 0)pstmtsetInt(5 0)pstmtaddBatch() [2]

int [] updateCounts = pstmtexecuteBatch() [3]

At [1] a parameterized insert statement is prepared Note that all columns must be parameterized Otherwise the executeBatch method may throw the SQL0221 Number of rows 1 not valid exception In other words the developer should not mix parameter markers with literals or special registers in the VALUE clause

At [2] the addBatch method is used to add a new record to the client record buffer

At [3] all locally buffered data is sent to the server which in turn performs a block insert

Figure 4 shows the performance data for the executeBatch and executeUpdate methods

Figure 4 executeBatch() versus executeUpdate() performance comparison

11

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

WebSphere Considerations In certain situations an application provider may decide to deploy WebSphere Application Server in an AIX partition rather than natively in i5OS At the same time the application uses DB2 UDB for iSeries as an back-end database server Typically the WebSphere Application Server running in the AIX partition uses the virtual LAN to communicate with DB2 UDB for iSeries The WebSphere applications will access the database through a remote JDBC connection For performance and functionality reasons IBM recommends to utilize in such environments the IBM Toolbox for Java JTOpen driver Most of the tips and techniques described so far in this document hold true for WebSphere applications accessing DB2 UDB for iSeries There are however certain JDBC access aspects that are specific to this multi-tier architecture Letrsquos have a closer look at some of these considerations

Connection Pooling and Statement Caching

WebSphere Application Server provides its own connection pooling and statement caching mechanism that is by default enabled so that WebSphere applications automatically enjoy the performance benefits of these two critical programming techniques See the following link to learn more about the optimal connection pool setting in WebSphere

httppublibboulderibmcomwas40051englishinforzaiz51adminhelpudat_conpoolsethtml

Extended Dynamic SQL

For non-JTA connections WebSphere Application Server uses the comibmas400accessAS400JDBCConnectionPoolDataSource class as the iSeries JDBC provider implementation This is the DataSource implementation that has been used in all previous coding examples As mentioned the class supports a range of iSeries specific properties that can be used to fine tune JDBC performance These properties can be set through the WebSphere Application Server admin console For example herersquos the procedure to enable the extended dynamic SQL support In the WebSphere Application Server admin console navigate to the Data Source configuration dialog by selecting JDBC Providers -gt iSeriesToolbox -gt Data Sources then scroll down to the Additional Properties section Select Custom Properties link The Custom Properties dialog opens Scroll down to find the Extended Dynamic property and select it Change the default value false to true save the new configuration by clicking Apply button This is illustrated in Figure 5

12

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 5 Enabling the extended dynamic SQL through WebSphere Application Server console

The WebSphere Application Server needs to be restarted for the change to take effect The similar procedure can be followed to set other iSeries Data Source properties

Changing the WebSphere Application Server default isolation level

WebSphere Application Server V5 uses the REPEATABLE_READ (RR) isolation level for all implicit (WebSphere Application Server managed) transactions With the RR isolation level the rows selected updated deleted and inserted are locked until the end of the transaction Under certain circumstances this fairly extensive locking policy may cause locking contention especially when a WebSphere application competes for database resources with other applications that run on iSeries server For example a legacy order entry application may share data with the e-business customer care application running in WebSphere The locking contention may sometimes be eliminated by lowering the isolation level used by WebSphere Although the iSeries Data Source supports the custom transactionIsolation property resetting this property on the Data Source object will not change the default isolation level used by WebSphere for the connection objects produced by that Data Source In other words WebSphere will override the Data Source isolation level setting at the time the connection is obtained by a WebSphere application object such as servlet or Enterprise Java Bean (EJB) In order to change the default WebSphere behavior one must use the resource referencing Resource referencing allows a programmer to lookup DataSource or EJB objects using alias names rather than JNDI names Additionally by creating a resource reference a programmer can change certain properties of the underlying object Specifically a DataSource reference can be used to set a different isolation level for the connections produced by this database resource Typically resource references are defined by a programmer in a application development tool such as WebSphere Studio Application Developer The method to specify a DataSource reference differs depending on whether a programmer plans to use the reference in a servlet or in an EJB Letrsquos start with outlining the configuration process for a servlet In WebSphere Studio Application Developer open the deployment descriptor editor for the web project that contains the servlet To do so double click on the webxml file under WEB-INF directory in the web project In the deployment editor dialog select the References tab and then select Resource tab located in the top of the dialog that appears Under Resource References section select the Add button Herersquos an example of a DataSource reference created for iSeries DataSource named TestJDBCDS Note that the reference changes the default isolation level to READ_COMMITTED

13

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 6 Defining a resource reference for a servlet

Once the resource reference has been defined and saved the servlet source code needs to be changed to reflect the fact that a resource reference is used to obtain a DataSource from the JNDI service Herersquos the relevant code snippet try

ctx = new InitialContext() ds = (DataSource)ctxlookup(javacompenvTestJDBCJ2C)

catch (Exception e) eprintStackTrace(out)

Now the ds DataSource object will produce connections that by default run with the isolation level of READ_COMMITTED (RC)

As mentioned the process of defining a resource reference for an EJB differs from the process that is used in the case of a servlet In WebSphere Studio Application Developer open the deployment descriptor editor for the EJB project that contains the EJB To do so double click on the ejb-jarxml file under WEB-INF directory in the project In the deployment editor dialog select the References tab In the references section on the left locate and select the EJB for which the developer wants to change the default isolation level Click the Add button The Add Reference dialog opens Click the Resource Reference radio button and then Next Define the reference following the example shown in Figure 7

14

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 7 Adding a resource reference for an EJB

When you click ldquoFinishrdquo the reference definition is added to the EJB descriptor The new definition needs to be further modified To do so click on the (+) sign next to the EJB in the References list Click the new reference TestJDBCJ2C in this example to open the properties for the reference Change WebSphere Bindings and WebSphere Extensions sections as illustrated in Figure 8

15

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 8 Defining a resource reference for an EJB

Save the modified definition and then change the EJB source code to use the reference rather than directly DataSource

TroubleshootingTroubleshooting a multi-tier application may be a bit tricky because the developer needs to deal with software components that reside in separate partitions Three tools are particularly useful for pinning down the potential problem areas bull Joblog messages for a database server job mdash Provides enough details to isolate DB2 UDB for

iSeries runtime issues bull JDBC trace utility mdash Provides granular information about the data flow between the AIX

application and the iSeries server job bull Database Monitor ndash Provides detailed SQL runtime trace

Job Log MessagesAs mentioned a DB2 client communicates with a corresponding iSeries server job This server job runs the SQL requests on behalf of the client The iSeries database server jobs are called QZDASOINIT and they run in the QUSRWRK subsystem At any given time a large number of database server jobs may be active on the server so the first step is to identify the job that serves the particular client connection The easiest method to accomplish this task is to run the following CL command from the i5OS prompt

WRKOBJLCK OBJ(DB2USER) OBJTYPE(USRPRF)

Here DB2USER is the user profile that is used to connect to the iSeries server Note that a QZDASONIT job is assigned to a client after the connection has been established so the developer needs to set a breakpoint in the client application after the database connection has been established

Once the Work with Object Locks appears key in 5 (Work with Job) next to the only QZDASOINIT job that should be listed This shows the Work with Job dialog Select option 10 to

16

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

display the job log for the database server job Now the job log can be searched for any error messages generated by the DB2 runtime

Sometimes it is also useful to include debug messages in the job log The debug messages are informational messages written to the job log about the implementation of a query They describe query implementation methods such as the use of indexes join order ODP implementation (reusable versus non-reusable) and so on The easiest way to instruct an iSeries server to include the debug messages is to set the ServerTraceCategories property on the data source object

tkcpdssetServerTraceCategories(AS400JDBCDataSourceSERVER_TRACE_DEBUG_SERVER_JOB)

A sample of the job log messages with debug messages enabled is shown below

SET TRANSACTION completeSTATEMENT NAME FOUND QZ868F0A458E13AF8C Starting optimizer debug message for query Arrival sequence access was used for file COFFEESODP created ODP not deleted 5000 rows inserted in COFFEES in DB2USER STATEMENT NAME FOUND QZ868F0A4C144BF12EBlocking used for queryCursor CRSR0001 opened606 rows fetched from cursor CRSR0001 ODP not deleted Cursor CRSR0001 closed

So the job log offers fairly detailed information on how the AIX client requests were implemented by the DB2 runtime

JDBC Trace UtilityThe JTOpen driver provides a tracing utility which can be used to collect detailed client-side traces The JDBC tracing is turned off by default It can be enabled by setting the Trace property to true Heres an example of how to switch on tracing using the setTrace method on the data source object

tkcpdssetTrace(true)

The trace can also be enabled when using the DriverManagergetConnection() method for obtaining a connection to DB2 UDB for iSeries In this case the developer could add the trace property to the connection string This approach is illustrated in the following code snippet

ClassforName(comibmas400accessAS400JDBCDriver) [1] hellip con = DriverManagergetConnection(jdbcas400teraplextrace=true

db2userdb2pwd) [2]

At [1] an instance of the JTOpen JDBC Driver is initiated Then at [2] the driver is used to obtain a connection to the iSeries server Note how the trace property has been added to the database URL See the IBM Toolbox for Java JDBC properties documentation on the iSeries Information Center Web site for a complete list of properties supported by the JTOpen driver

Although the level of details provided by the trace utility is sufficient in most troubleshooting scenarios sometimes the developer may need to collect low-level traces scoped to a certain type

17

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

of information In V5R3 the IBM Toolbox for Java (as well as the latest JTOpen) added a comprehensive detailed trace facility The following is the complete list of detailed trace parameters and their purpose

bull None or ldquordquo ndash This setting disables the detailed trace bull datastream - This category is used by Toolbox classes to log dataflow between the local host

and the remote system It is not intended for use by application classes bull diagnostic - This category is used to log object state information bull error - This category is used to log errors that cause an exception bull information - This category is used to track the flow of control through the code bull warning - This category is used to log errors that are recoverable bull conversion - This category is used by Toolbox classes to log character set conversions

between Unicode and native code pages bull proxy - This category is used by Toolbox classes to log data flow between the client and the

proxy server bull pcml - This category is used to determine how PCML interprets the data that is sent to and

from the server bull jdbc - This category is used to track JDBC calls throughout the program bull thread - This category is used to enable tracing of thread information This is useful when

debugging multi-threaded applications bull all - This category will enable all previous categories

The detailed trace can be enabled when using the DriverManagergetConnection() method for obtaining a connection to DB2 UDB for iSeries In this case the developer could add the toolbox trace property to the connection string This is illustrated in the following code sample

String dbUrl = jdbcas400pwd1toolbox trace=diagnostic con = DriverManagergetConnection(dbUrl dbUser dbPassword)

Note that currently the driverrsquos DataSource interfaces do not allow the developer to directly activate the detailed tracing However they could set the server from the command line at the time the java program is launched The example below shows how the detailed trace properties could be enabled at the command line

java -Dcomibmas400accessTracecategory=diagnostic TestJDBC

The -D switch indicates to the java interpreter that the information following it will be a system property

In case of a WebSphere application the trace property can be set through the admin console In the console select Application Servers-gt server1-gt Process Definition -gt Java Virtual Machine Figure 9 shows how to set the Generic JVM Arguments for an application server instance

18

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 9 Setting JVM arguments to enable detailed Toolbox tracing

Database Monitor

The database monitor is the ultimate tool available on DB2 UDB for iSeries to collect low-level SQL traces It is mainly used to pin down the SQL performance problems Refer to the lsquoUsing iSeries Database Monitor to Identify and Tune SQL Queriesrsquo white paper for a detailed discussion on how to collect and analyze the database monitor traces httpibmcomserversenablesiteeducationiborecordhtmldtmon

IBM DB2 JDBC Universal Driver DB2 JDBC Universal Driver is one of the new features delivered with DB2 UDB Version 8 DB2 JDBC Universal Driver has been designed to eliminate the dependency on DB2 CLI runtime modules as well as to enable direct Type 4 connectivity to DB2 UDB for iSeries and DB2 UDB for zOSreg

The pure-Java (Type 4) remote connectivity is based on the DRDA open distributed protocol for cross-platform access to DB2 DRDA defines the rules the protocols and the semantics for accessing distributed data Applications can access data in a distributed relational environment by using SQL statements The iSeries DRDA application server implementation is based on multiple connection-oriented server jobs running in the QSYSWRK subsystem A DRDA listener job (QRWTLSTN) listens for TCP connect requests on port 446 Once an application requester connects to the listener job the listener wakes up one of the QRWTSRVR prestart jobs and assigns it to a given client connection Any further communication occurs directly between the client application and the QRWTSRVR job These concepts are illustrated in Figure 10

19

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 10 Accessing DB2 UDB for iSeries with DB2 Universal Driver

The DB2 Universal Driver can be loaded in an AIX partition by installing one of the DB2 Connect for AIX products (see the Additional Information section for details) It is also a part of a DB2 Enterprise Server Edition for AIX install Specifically the developer needs three JAR files in a AIX partition to successfully connect to an iSeries server db2jccjar db2jcc_license_cisuzjar and db2jcc_license_cujar The iSeries license is contained in db2jcc_license_cisuzjar Note that this file is not a part of DB2 Client In other words a DB2 Connect license is required to use the driver in production environments The location of the JAR files needs to be added to the CLASSPATH environment variable For instance the following entry could be added to the AIX profile script

CLASSPATH=homedb2inst2sqllibjavadb2jccjarCLASSPATH=$CLASSPATHhomedb2inst2sqllibjavadb2jcc_license_cujarCLASSPATH=$CLASSPATHhomedb2inst2sqllibjavadb2jcc_license_cisuzjarexport CLASSPATH

Java Runtime 131 is a prerequisite

Additionally the developer should install the latest database group PTF (SF99503 for i5OS V5R3) on the iSeries server The Informational APAR ii13348 is keeping track of any fixes relevant to DRDA above and beyond the current database group PTF

Obtaining a Connection to DB2 UDB for iSeries When Type 4 connectivity is used the DB2 Universal Driver connects directly to the DB2 on iSeries through TCPIP Note that this is different from the legacy DB2 Type 2 JDBC driver that requires a DB2 node and remote database configurations on the client accessing iSeries The following code snippet illustrates how to use the DB2 JDBC Universal Driver to obtain a connection to DB2 UDB for iSeries

20

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

try ClassforName(comibmdb2jccDB2Driver) [1] catch(javalangClassNotFoundException e) Systemerrprint(ClassNotFoundException )Systemerrprintln(egetMessage())

try DriverManagergetConnection(jdbcdb2teraplex446TERAPLEX[2]

db2userdb2pwd) hellip catch(SQLException ex) Systemerrprintln(

SQLException + exgetMessage())

At [1] an instance of the DB2 JDBC Universal Driver is instantiated Then at [2] the driver is used to obtain a connection to the iSeries server Note the proper form of the database URL required by the driver

Considerations There are several advantages of DB2 JDBC Universal Driver bull Ease of cross-platform development mdash Consistent coding techniques and consistent error

codes and messages bull Ease of deployment mdash Pure Java (no runtime client required) and a single driver for accessing

DB2 on different platforms

The ease of use comes at a price though The iSeries JTOpen driver is optimized for accessing DB2 UDB for iSeries data and it uses native iSeries protocol to communicate with the back-end database server job This usually results in better performance and more-efficient system resources utilization For instance when using the DB2 JDBC Universal Driver to access an iSeries server the executeBatch method results in a single record insert There are also some restrictions when using DB2 Universal JDBC Driver with Type 4 connectivity

bull Support for distributed transactions (JTA) is not enabled bull Driver built-in connection pooling is not supported

Refer to Java application support in DB2 for more details on DB2 JDBC Universal Driver

21

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 Connect data access This section will explore the most important aspects of DB2 Connect ndash iSeries integration - including configuration tips and coding examples

DB2 Connect provides functionality for accessing data stored in DB2 UDB for iSeries as well as DB2 UDB for zOS and DB2 UDB for OS390reg DB2 Connect offers capabilities to access DB2 family members via several SQL interfaces gateway functions such as connection pooling and federated database functionality Many applications supporting the DB2 family of products leverage DB2 Connect as a key middleware component DB2 Connect is offered as separate AIX license products

Enterprise Edition Application Server Edition

In addition to DB2 Connect there are several other DB2 UDB Version 81 products that are supported on AIX

DB2 Universal Database Enterprise Server Edition DB2 Universal Database Workgroup Server Unlimited Edition DB2 Universal Database Workgroup Server Edition DB2 Universal Database Universal Developers Edition All Clients

The DB2 Connect Enterprise Edition functionality is also contained in DB2 Enterprise Server Edition for AIX

22

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 Connect in a nutshell In the scenario described in this paper the DB2 Connect functions contained in DB2 Enterprise Edition for AIX are utilized DB2 Connect Enterprise Edition provides support for both local and remote DB2 clients This is illustrated in Figure 11 Accessing DB2 UDB for iSeries with DB2 Connect

Figure 11 Accessing DB2 UDB for iSeries with DB2 Connect

DB2 Connect implements the Distributed Relational Database Architecturetrade (DRDAreg) to reduce the cost and complexity of accessing data stored in DB2 UDB for iSeries and other DRDA-compliant database servers DRDA defines the rules the protocols and the semantics for accessing distributed data Applications can access data in a distributed relational environment by using SQL statements In a distributed environment the system running the application and sending the SQL requests across the network is called the application requester (AR) A remote database server that executes SQL requests submitted by an application requester is known as the application server (AS) In the example shown in Figure 11 (above) DB2 Connect plays the role of an application requester while DB2 UDB for iSeries is an application server In this case DB2 Connect communicates with the iSeries database through TCPIP The iSeries DRDA application server implementation is based on multiple connection-oriented server jobs running in the QSYSWRK subsystem A DRDA listener job (QRWTLSTN) listens for TCP connect requests on port 446 Once an application requester connects to the listener job the listener wakes up one of the QRWTSRVR prestart jobs and assigns it to a given client connection Any further communication occurs directly between the client application and the QRWTSRVR job

DB2 Connect supports a wide range of programming interfaces that can be used by AIX applications to access the iSeries database Embedded SQL frac34 Both static and dynamic SQL frac34 Various programming languages (Java CC++ Cobol Fortran REXX)

DB2 Call Level Interface (DB2 CLI) ODBC JDBC frac34 DB2 JDBC Type 2 Driver frac34 DB2 JDBC Type 4 Driver (Universal JDBC Driver)

23

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Note that DB2 Connect supports access to DB2 UDB for iSeries through DB2 JDBC Universal driver However for performance and ease of maintenance reasons IBM recommends that Java applications running in AIX use native iSeries Toolbox JDBC driver See the JDBC Data Access section of this paper (above) for more details On the other hand DB2 Connect is a very efficient and robust connectivity option for AIX applications especially in the environments that are not directly supported by the native iSeries JDBC driver Here are several possible scenarios that would require DB2 Connect installed in a AIX partition

Embedded SQL interface is used to access DB2 CLI or ODBC interface is used to access DB2 A single SQL interface is needed to access multiple back end DB2 server Specific DB2 Connect functionality is needed such as distributed join or connection

pooling

Prerequisites One of the DB2 Connect products or DB2 Enterprise Server Edition for AIX V81 is needed Additionally DB2 Application Development Client is required in the AIX partition to compile DB2 applications

For maximum database server stability the developer should install the latest database group PTF (SF99503 for i5OS V5R3) on the iSeries server The Informational APAR ii13348 is keeping track of any fixes relevant to DRDA above and beyond the current database group PTF

DB2 Connect configuration The following example employs i5OS V5R3 and DB2 UDB Enterprise Server Edition for AIX Version 81 FixPak 6

Configuration steps in the iSeries partition The following process lists the necessary steps to be performed on the iSeries server 1) Verify that the TCPIP stack is working correctly It is assumed that the Virtual LAN is used to

communicate with the i5OS partition First obtain the IP address of the iSeries server or its hostname and ping the iSeries server from the AIX partition

2) Create a relational database (RDB) entry for the iSeries database in the i5OS partition If this has already been created it can be displayed by using the DSPRDBDIRE command Make sure that the RDB entry with a location of LOCAL exists on the iSeries server If it does not exist use the ADDRDBDIRE command to add the appropriate RDB entry For example the following command would add an RDB entry named TPLX For simplicity it is recommended that the TCPIP host name and RDB entry remain the same

ADDRDBDIRE RDB(TPLX) RMTLOCNAME(LOCAL)

3) Create a collection called NULLID This is necessary because the utilities shipped with DB2 Connect and DB2 UDB for AIX store their packages in the NULLID collection Since it does not exist by default in the iSeries server you must create it using the following command

CRTLIB LIB(NULLID)

4) Products that support DRDA automatically perform any necessary code page conversions at the receiving system For this to happen both systems need a translation table from their code page to the partner code page The default Coded Character Set Identifier (CCSID) on the iSeries server is 65535 Since DB2 Connect does not have a translation table for this code page the developer needs to change the individual user profiles to contain a CCSID that can be converted properly by DB2 Connect For US English this is 037 For other languages see DB2 Connect Personal Edition Quick Beginning GC09-2967 The following command changes the CCSID for an individual user profile to 037

24

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

CHGUSRPRF userid CCSID(037)

5) Verify that the default port 446 for DRDA service is being used To do this go to the Configure TCPIP menu (CFGTCP) select Configure Related Tables and then select Work with service table entries Verify that the DRDA service is set for port 446

6) The Distributed Data Management (DDM) job must be started for DRDA to work If you want the DDM job to be automatically started whenever TCPIP is started change the attributes of the DDM job using the CHGDDMTCPA command and set the Autostart server parameter to YES

7) If the system administrator chooses not to autostart the server issue the following command to start the DDM server job

STRTCPSVR SERVER(DDM)

8) Make sure that the user profiles that will be used to connect to the iSeries server exist on the server

25

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Configuration steps in the AIX partition The following steps are required for DB2 Connect to be configured in the AIX partition 1) Sign on to the AIX partition as the DB2 administrator 2) Launch Client Configuration Assistant (db2ca from the command prompt) It is assumed that

VNC or an X-Windows server are being used on the workstation so that the db2ca GUI can be properly rendered

3) From the Selected pull-down menu select the Add Database using Wizard option The Select how you want to setup a connection dialog appears Select Manually configure a connection to a database and click Next This is shown in Figure 12

Figure 12 Accessing DB2 UDB for iSeries with DB2 Connect

26

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

4) On the Select a communications protocol choose TCPIP and select The database physical resides on a host or OS400 system Then select the option Connect directly to the server as shown in Figure 13 Click Next

Figure 13 mdash Selecting communications protocol

27

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

5) On the TCPIP tab fill in the host name of the iSeries server The port number should be 446 This is shown in Figure 14 Click Next

Figure 14 mdash Specifying TCPIP communication parameters

28

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

6) On the Database tab fill in the Relational Database name Use the RDB entry name (specified in step 2) in the Configuration steps in the iSeries partition section as shown in Figure 15 Click Next

Figure 15 mdash Specifying the remote database

7) If you plan to use the ODBC applications select Register this database for ODBC as a system data source on the ODBC tab Click Next

29

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

8) On the Specify the node option dialog select OS400 from the Operating System pull-down menu This is shown in Figure 16 Click Finish

Figure 16 mdash Specifying the node options

30

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

9) The Test Connection dialog appears This allows the developer to verify that the connection works Select both CLI and JDBC check boxes You are also prompted for an iSeries user ID and password as shown in Figure 17

Figure 17 mdash Testing the connection

31

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

10) The successful connection to the database server is confirmed by the message box shown in Figure 18

Figure 18 mdash Test Connection results 11) At this time a newly configured database connection should appear in the main DB2

Configuration Assistant window It is recommended that the DB2 utilities are also bound to the iSeries database The bind process creates the necessary SQL packages on the remote database In the main Configuration Assistant window click the TPLX database entry and then select Selected-gtBindhellip

32

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

12) The Bind dialog appears Click Select All and then enter the connection information as shown in Figure 19 Click Bind The Results message box appears This allows the developer to monitor the progress of the binding process Watch for any error and warning messages

Figure 19 mdash Binding the DB2 utilities This concludes the DB2 Connect configuration steps

33

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Accessing DB2 UDB for iSeries from C embedded SQL

As mentioned earlier DB2 Connect allows developers to compile and run embedded SQL applications that access DB2 UDB for iSeries data This section covers implementation details for a C embedded SQL application called cursorsjsqc (see Appendix B for source code)

Prerequisites An embedded SQL application running in an AIX partition will use DB2 Connect services to access DB2 UDB for iSeries therefore the developer needs to make sure that all components listed in section Prerequisites on page 24 are installed The developer also needs to create a remote database connection as described in the DB2 Connect configuration section of this paper on page 24

Static SQL and SQL packages To successfully run against a DB2 UDB for iSeries database an embedded SQL application needs to be first precompiled and bound to the back-end database This process creates an SQL package on the target iSeries server The SQL package contains the access plan information for the SQL statements executed by the application The internal structure of the package as well as the method how its content is used by the SQL runtime to facilitate the access plan reuse is similar to the Extended Dynamic SQL support covered in detail in the Extended Dynamic SQL and Statement Caching section of this paper (on page 9) There are however important differences between the packages created by the extended dynamic SQL support and the packages created for embedded SQL DRDA client applications The extended dynamic SQL packages support dynamic SQL interfaces such as JDBC

that can submit ad hoc SQL statements at the run time The SQL runtime can prepare the dynamic statements and add them to the package On the other hand the DRDA packages are created at the precompile time and contain static SQL In order to add new statements to the package the application needs to be precompiled and rebound again

The extended dynamic SQL package can dynamically grow up to 500MB by allocating new space as required The DRDA packages since they are created at the precompile time have a fix size and do not grow over their life time

Simple embedded SQL application The application is based on a source code provided in the DB2 UDB samples directory typically to be found at homedb2inst1sqllibsamples The cursorsjsqc performs a join between STAFF and ORG tables located in DB2USER schema (library) on the TPLX database server (the source is provided at the end of this paper in Appendix B) The join statement retrieves the DEPTNAME column from ORG NAME column from STAFF and calculates the total compensation for an employee by adding SALARY and COMM columns in STAFF The results are sorted by department name and total compensation Here is the SELECT statement used by the application

SELECT deptname name salary + IFNULL(comm0) as compensationFROM org o staff sWHERE odeptnumb = sdeptORDER BY deptname compensation DESC

The application iterates through the selected records and prints out the data to the standard output device The sample DB2USER schema was created with the following SQL statements

db2 CONNECT TO tplx USER db2user USING mypassworddb2 CALL QSYSCREATE_SQL_SAMPLE(DB2USER)

34

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Make sure that the AIX partition is logged into with the DB2 admin user profile If the defaults were selected at the DB2 installation time this profile name is db2inst1 It is also assumed that DB2USER user exists on the iSeries server and that it has appropriate authority

There are several steps that are required to create an executable for the cursorsjsqc source code First the DB2 PRECOMPILE utility needs to be called The utility creates a bind file that is used to bind the required SQL package to the TPLX database It also converts embedded SQL statements into DB2 run-time API calls and produces a pure C source file that can be processed by an AIX C compiler

db2 CONNECT TO tplx USER db2user USING mypassworddb2 prep cursorsjsqc bindfile

Note that the connect statement is required only if the developer is not already connected to the database on an iSeries server Watch for any error or warning messages returned by the DB2 prep utility The prepare step should produce cursorsjbnd and cursorsjc files in the current directory Now the developer can invoke the bind utility to prepare the statements contained in the bind file and create the package on the target iSeries database server

db2 bind cursorsjbnd

It is assumed that Visual C++ 60 is installed and configured in the AIX partition Refer to the ldquoDeveloping and Porting C and C++ Applications on AIXrdquo redbook for more information on how to use the Visual C++ compiler httpibmcomredbooksabstractssg245674htmlOpen

Use the following commands to compile the C source generated by the precompile utility

xlc -I$INSTHOMEsqllibinclude ndashc cursorsjcxlc ndasho cursorsj cursorsjo -L$INSTHOMEsqlliblib ndashldb2

Run the program from the AIX prompt

cursorsj db2user mypassword

Distributed Join DB2 UDB Version 8 provides core federated server functionality A federated system consists of a DB2 UDB instance that operates as a federated server a database that acts as the federated database one or more data sources and clients (users and applications) that access the database and data sources Federated server permits objects stored in multiple databases to be accessed together in the same query For example a query can refer to a table that resides in DB2 UDB for iSeries and join it to a table stored in DB2 UDB for AIX Such a query would constitute so called distributed join The support for DB2 UDB for iSeries as a federated data source is provided by core federated server functionality directly implemented in DB2 UDB Enterprise Server Edition and DB2 UDB Connect Enterprise Edition All other DB2 UDB family members are also supported directly by core DB2 UDB federated server An additional software product DB2 Information Integratortrade is required to access non-DB2 UDB databases such as Oracle Sybase or Microsoftreg SQL Server Consult the following white papers for a detailed discussion on DB2 federated server support Heterogeneous data access for iSeries applications Version 2 httpibmcomserversenablesiteeducationiborecordhtmlhetdata Fundamentals of IBM DB2 Federated Server and Relational Connect httpwww7bsoftwareibmcomdmddlibrarytecharticle0206purnell0206purnellhtml

35

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Distributed Join Example In this section the steps that are required to configure DB2 UDB for iSeries as a federated data source will be illustrated Then the cursorsjsqc program will be ldquotweakedrdquo so that it executes a distributed join query that accesses data stored on an iSeries server and in the local DB2 UDB for AIX database It is assumed that the developer is familiar with the DB2 federated server concepts

Note Run the following commands from the Command Line Processor prompt Load the utility by executing the db2 command at the AIX prompt 1) First the local DB2 UDB for AIX instance needs to be enabled as a DB2 federated server

This is done by setting the database manager configuration parameter FEDERATED to YES

db2=gt update dbm cfg using FEDERATED YES

The database instance needs to be restarted for the change to take effect

NOTE A federated database is a regular database in a DB2 UDB instance that has the FEDERATED parameter enabled Therefore in this example the SAMPLE database that was created earlier is used as the federated database A new database can also be created using the CREATE DATABASE command

2) Connect to the federated database

db2=gt connect to sample

3) Use the CREATE WRAPPER statement to register a wrapper for the iSeries data source Wrappers are library routines that are used by the federated server to perform operations such as connecting to a data source and retrieving data from it The default wrapper name for DB2 UDB for iSeries is DRDA Here is the command to register the DRDA wrapper

db2=gt create wrapper drda

4) Use the CREATE SERVER statement to register a data source as a server within the federated database The server definition specifies the type and version of the data source and the wrapper used for communications with this data source For the DB2 UDB for iSeries data source the node and the database names are also needed The node and database name parameters have been configured for our TPLX database in the Configuration steps in the AIX partition section (on page 24) Use the following DB2 UDB command to lookup these parameter on the federated server

db2=gt list database directory

In this case the command produced the following output

Database alias = TPLX Database name = DCSE99E1 Node name = NDE9BF76 Database release level = a00 Comment = Directory entry type = Remote Authentication = SERVER Catalog database partition number = -1

36

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Note that the node name is set to NDE9BF76 The name was generated by the Configuration Administrator utility (db2ca)

Here is the command to register the TPLX database as a federated server

db2=gt create server tplx type db2400 version 530 wrapperdrda authorization db2user password mypassword options(nodeNDE9BF76 dbname TPLX)

The command is quite complex so make sure that the syntax is correct

5) Define the user mappings that instructs the federated server what user ID and password should be used when connecting to the iSeries data source

db2=gt create user mapping for user server tplxoptions(remote_authid db2user remote_password mypassword)

Specify the nickname for the iSeries table or view A nickname is an identifier that is used by the federated server to reference an object located at the data source The following command creates a nickname for the STAFF table located in the DB2USER schema on the TPLX database

db2=gt create nickname tplx_staff for tplxdb2userstaff

6) Test the distributed join query

db2=gt SELECT deptname name salary + COALESCE(comm0) ascompensation FROM org o tplx_staff s WHERE odeptnumb =sdept ORDER BY deptname compensation DESC

Note that the native iSeries function IFNULL has been substituted with an equivalent DB2 UDB function COALESCE COALESCE is also supported on iSeries servers For better portability IBM encourages the use of COALESCE rather than IFNULL Note also that the query runs on the federated server rather than on TPLX It accesses the ORG table in the local DB2 UDB for AIX SAMPLE database and the STAFF table that resides in TPLX The federated server performs the necessary distributed join

7) Modify the cursorsjsqc so that it executes a distributed join There are two source code modifications - Change the CONNECT TO statements Now the application needs to connect to the

federated database SAMPLE rather than to TPLX

EXEC SQL CONNECT TO SAMPLEEXEC SQL CONNECT TO SAMPLE USER userid USING passwd

- Modify the select statement so that it performs a distributed join Use the statement (shown in step 6) above Save the new source version as cursordjsqc

- Prepare bind and compile the distributed join version of the program as described in the Simple C embedded SQL application section (on page 34)

db2 prep cursordjsqc bindfiledb2 bind cursordjbndxlc -I$INSTHOMEsqllibinclude ndashc cursordjcxlc ndasho cursordj cursordjo -L$INSTHOMEsqlliblib ndashldb2

37

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

- Run the program from the AIX prompt

cursordj

Connection Pooling and Connection ConcentratorA modern Web-based application typically executes a large number of short-lived transactions Executing a transaction in this environment means establishing a database connection executing a few SQL statements and terminating this connection Creating connections to the database server is a very costly process To reduce the unnecessary workload DB2 Connect implements connection pooling and connection concentrator Connection pooling mechanism allows DB2 Connect to reuse an existing connection infrastructure for subsequent connection requests The connection concentrator is an advanced technology that allows DB2 Connect to serve a potentially very large number of clients with a limited number of database connections This is accomplished by decoupling clients from a particular database connection

Note that currently neither connection pooling nor connection concentrator support DB2 UDB for iSeries Therefore for performance reasons the author strongly recommends that the application server that obtains and drops connections very frequently implements its own database connection pooling mechanism that would assign an existing pooled database connection to a new AIX process or thread

TroubleshootingTroubleshooting a multi-tier application may be a bit tricky because the developer needs to deal with software components that reside in separate partitions The authorrsquos experience shows that two tools are particularly useful for pinning down the potential problem areas The joblog messages for a database server job usually provide enough details to isolate DB2

UDB for iSeries runtime issues The DRDA trace utility provides granular information about the data flow between the AIX

application and the iSeries server job

38

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Job Log MessagesAs mentioned earlier a DB2 client communicates with a corresponding iSeries server job This server job runs the SQL requests on behalf of the client More precisely when a DB2 client submits an SQL statement the statement is passed to a server job that in turn calls the DB2 runtime to execute the statement The results are then reformatted and marshaled to the client The iSeries DRDA server jobs are called QRWTSRVR and they run in the QUSRWRK subsystem At any given time there may be a large number of DRDA server jobs active on the system so the first step is to identify the job that serves the particular client connection The easiest method to accomplish this task is to run the following CL command from the i5OS prompt

WRKOBJLCK OBJ(DB2USER) OBJTYPE(USRPRF)

Here DB2USER is the user profile that is used to connect to the iSeries server Note that a QRWTSRVR job is assigned to a client after the connection has been established so the developer needs to set a breakpoint in the client application below the CONNECT TO statement

Once the Work with Object Locks appears key in 5 (Work with Job) next to the only QRWTSRVR job that should be listed This shows the Work with Job dialog Select option 10 to display the job log for the database server job Now the developer can search the job log for any error messages generated by the DB2 runtime

Sometimes it is also useful to include debug messages in the job log The debug messages are informational messages written to the job log about the implementation of a query They describe query implementation methods such as use of indexes join order ODP implementation (reusable versus non-reusable) and so on The easiest way to instruct the iSeries server to include the debug messages is to call the following stored procedure just after the connection to the iSeries server is established

EXEC SQL call qsysqcmdexc(STRDBGUPDPROD(YES)000000002000000)

A sample of the job log messages with debug messages enabled is shown below in Figure 20

Arrival sequence access was used for file STAFFAccess path suggestion for file STAFFQuery options used to build the OS400 query access plan Ending debug message for query ODP created Blocking used for queryCursor SQLCUR201 opened1 rows fetched from cursor SQLCUR201Row not found for SQLCUR201ODP deleted Cursor SQLCUR201 closedDESCRIBE of prepared statement STMT0201 completed

Figure 20 mdash Joblog with debug messages enabled

So the job log offers fairly detailed information on how the AIX client requests were implemented by the DB2 runtime

39

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 DRDA trace utilityThe DB2 DRDA trace utility (db2drdat) provides detailed information about the data streams exchanged between DB2 Connect and target database server The output file produced by the utility contains send and receive communications buffers TCPIP error messages and SQL Communications Area (SQLCA) information Please refer to lsquoDB2 Connect Userrsquos Guidersquo manual for in-depth discussion of the DRDA trace utility

Accessing DB2 UDB for iSeries from CLI DB2 Call Level Interface (CLI ) is based on the Microsoft Open Database Connectivity (ODBC) specification and the ISO CLI standard The DB2 CLI interface gained popularity among DB2 application providers because the developer can build an ODBC application by simply linking the application with libdb2 library on a UNIX server In other words the developer directly utilizes the DB2 ODBC driver services without a need for an ODBC driver manager Additionally in contrast to embedded SQL the developer does not need to precompile or bind DB2 CLI applications because they use packages provided with DB2 UDB The developer simply compiles and links the application

Prerequisites A DB2 CLI application running in an AIX partition will use DB2 Connect services to access DB2 UDB for iSeries therefore make sure that all components listed in Prerequisites section of this paper on page 24 are installed The developer also needs to create a remote database connection as described in the DB2 Connect configuration section of this paper on page 24

Dynamic SQL and Access Plan Caching A DB2 CLI client application uses the dynamic SQL interface and does not have the capability to utilize the extended dynamic SQL support Therefore it runs lsquopurersquo dynamic SQL statements That does not mean however that the process of parsing validating and optimizing will be repeated for every execution of a given dynamic SQL statement

The DB2 UDB for iSeries database implements an internal object called System-Wide SQL Statement Cache (SWSC) The SWSC can improve the performance of programs using dynamic SQL statements by caching the access plans in a system-wide cache When a dynamic SQL statement is submitted the SQL runtime searches the SWSC to see if this statement has been previously executed If so then DB2 retrieves and reuses the key information associated with the cached statement and thereby the processing time and the resources utilization can be significantly reduced

Simple DB2 CLI C++ ApplicationThis section covers DB2 CLI implementation details for a sample C++ program called testclicpp (the source is provided at the end of this paper in Appendix C) To compile the source with Visual C++ complier use the following command in the AIX partition

xlC ndashI$INSTHOMEsqllibinclude ndashc testclicppxlC ndasho testcli testclio ndashL$INSTHOMEsqlliblib ndashldb2

The application performs a join between STAFF and ORG tables located in DB2USER schema (library) The join statement retrieves the DEPTNAME column from ORG NAME and JOB columns from STAFF and calculates the total compensation for an employee by adding SALARY and COMM columns in STAFF The results are sorted by total compensation The selection criterion is based on the current value of the department name parameter Here is the SELECT statement used by testcli

40

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

select name job salary + coalesce(comm0) as compensationfrom org o staff swhere odeptnumb = sdeptand deptname = order by compensation desc

Figure 21 shows the software components involved in the execution of this sample application

Figure 21 How a DB2 CLI client accesses DB2 UDB on an iSeries server

Although the testcli application is fairly simple it covers some important aspects of efficient CLI programming for DB2 UDB for iSeries

Reusable Open Data Paths (ODPs)An Open Data Path (ODP) definition is an internal i5OS object that is created when certain SQL statements (such as OPEN INSERT UPDATE and DELETE) are executed for the first time in a given job (or connection) The ODP can be thought of as a runtime implementation of an access plan The access plan created at the optimization time provides a recipe or in other words a sequence of steps necessary to execute the statement The ODP on the other hand provides the executable code for all requested IO operations The process of creating new ODP objects is fairly CPU- and IO-intensive so whenever possible the iSeries DB2 runtime tries to reuse existing ODPs For instance a SQLCloseCursor() API call may close the SQL cursor but leave the ODP available to be used the next time the cursor is opened This can significantly reduce the processing and response time in running SQL statements A reusable OPD usually requires 10 to 20 times less CPU resources than a newly created ODP Therefore it is important that the applications employ programming techniques that allow the DB2 runtime to reuse ODPs

With dynamic interfaces such as CLI full opens are avoided by using a prepare once execute many programming paradigm It means that when an SQL statement is going to be executed more than once you should prepare the statement just once and then reuse the prepared

41

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

statements for consecutive executions Although DB2 UDB does try to convert literals to parameter markers so that similar statements can be reused it is a better programming practice to explicitly implement parameter markers That way the chances for reusable ODPs are quite significantly improved The code snippet in Figure 22 illustrates how to implement the prepare once execute many programming technique

Define A SELECT SQL Statementstrcpy((char ) SQLStmt select name job salary + ifnull(comm0) ascompensation )ptr = strcat( (char ) SQLStmt from org o staff s )ptr = strcat( (char ) SQLStmt where odeptnumb = sdept)ptr = strcat( (char ) SQLStmt and deptname = )ptr = strcat( (char ) SQLStmt order by compensation desc) [1]

Prepare The SQL Statementrc = SQLPrepare(ExampleStmtHandle SQLStmt SQL_NTS) [2]

Bind The Columns In The Result Data Set Returned To Application Variablesrc = SQLBindCol(ExampleStmtHandle 1 SQL_C_CHAR (SQLPOINTER)

ExampleName sizeof(ExampleName) NULL)rc = SQLBindCol(ExampleStmtHandle 2 SQL_C_CHAR (SQLPOINTER)

ExampleJob sizeof(ExampleJob) NULL)rc = SQLBindCol(ExampleStmtHandle 3 SQL_C_DOUBLE (SQLPOINTER)

ampExampleComp sizeof(ExampleComp) NULL)

for (int i = 0 i lt LOOPS i++)rc=SQLBindParameter(ExampleStmtHandle

1SQL_PARAM_INPUTSQL_C_CHARSQL_CHAR10(SQLPOINTER) currentDepartment[i8]0NULL) [3]

rc = SQLExecute(ExampleStmtHandle) [4]cout ltlt endl ltlt Current Dept ltlt currentDepartment[i8] ltlt endl Display The Results Of The SQL QueryExampleShowResults()

Figure 22 Use the prepare once execute many programming technique

The error-handling code has been removed for clarity At [1] the statement text is assigned to a variable Note that a parameter marker is used in the WHERE clause The statement is then prepared just once at [2] The current value of the parameter is bound to the prepared statement at [3] The prepared statement is executed at [4] Steps [3] and [4] are repeatedly executed in a for loop

Techniques to Further Improve DB2 CLI Performance Thus far this paper has discussed the techniques used by a sample application to tune the CLI performance However depending on the application architecture other methods of improving CLI performance may be considered

Connection PoolingCurrently the CLI application connecting through DB2 Connect to DB2 UDB for iSeries does not take advantage of the connection pooling mechanism implemented by DB2 Connect Therefore for performance reasons the author strongly recommends that the application server that obtains and drops connections very frequently implements its own database connection pooling mechanism that would assign an existing pooled database connection to a new AIX process or thread

42

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Blocking

For queries which result in returning large data blocks from the iSeries server (usually 32K of data and above) ensure that the database manager configuration parameter RQRIOBLK is set to 32767 This can be done using the Command Line Processor (CLP) as follows

db2 update database manager configuration using RQRIOBLK 32767

TroubleshootingThe experience of the author shows that two tools are particularly useful for pinning down the potential problem areas bull Joblog messages for a database server job usually provides enough details to isolate DB2

runtime issues bull CLI trace utility provides granular information about the data flow between the AIX application

and the database server job

Job Log MessagesThe process of finding and analyzing the job log for a DB2 CLI connection is identical to the process outlined for an embedded SQL application in the Job Log Message section of this paper on page 39

CLI Trace The DB2 CLIODBCJDBC trace utility provides very detailed information about the data streams exchanged between DB2 Connect and target database server Refer to the DB2 Information Center for more information on how to set up and analyze the CLI traces httppublibboulderibmcominfocenterdb2v8luwindexjsptopic=comibmdb2udbdocadc000 7959htm

43

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Trademarks

IBM eServer iSeries AIX AIX 5L i5OS WebSphere DB2 DB2 Universal Database DB2 Connect OS400 zOS OS390 Distributed Relational Database Architecture DRDA and DB2 Information Integration are trademarks or registered trademarks of International Business Machines Corporation in the United States and other countries

Java and all Java-based trademarks are trademarks of Sun Microsystems Inc in the United States other countries or both

Linux is a registered trademark of Linus Torvalds in the United States other countries or both

UNIX is a registered trademark of The Open Group in the United States and other countries

Microsoft and Windows are registered trademarks of Microsoft Corporation in the United States andor other countries

All other registered trademarks and trademarks are properties of their respective owners

IBM makes no commitment to make available any products referred to herein

References in this publication to IBM products or services do not imply that IBM intends to make them available in every country in which IBM operates

Additional Information ITSO offers a Redbook that can be helpful to those who want to learn more about i5OS AIX integration

bull AIX Integration with I5OS on the IBM eServer iSeries Server (SG24-6551)

Jarek Miszczyk is the Senior Software Engineer IBM eServer Solutions Enablement IBM Rochester

[Portions of this white paper reprinted with permission from MC Mag Online published by MC Press LLP httpwwwmcpressonlinecom]

Acknowledgments The author would like to thank the following people for their advice contributions and support on this paper

Bob Bittner IBM Rochester Jon Rush IBM Rochester Prasad Vallurupalli IBM Rochester Neil Willis IBM Rochester

44

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix A Source Listing of TestJDBCjava

package comibmiseriespwdimport javasqlimport javaxnamingimport javautilHashtableimport javautilimport javaxsqlimport comibmas400access

public class TestJDBC public static void main(javalangString[] args)

throws Exception

int numOfLoops = 5000int outerNumOfLoops = 5boolean firstExec = trueConnection conStatement sPreparedStatement psPreparedStatement pstmtdelCallableStatement cstmPreparedStatement pstmtHashtable env = new Hashtable()

envput(ContextINITIAL_CONTEXT_FACTORYcomsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env)Systemoutprintln(Deploying connection pooling data source)deployDataSource() Do the work with connection pooling onlyAS400JDBCConnectionPoolDataSource tkcpds =

(AS400JDBCConnectionPoolDataSource)ctxlookup(jdbcToolkitDataSource) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPool pool = new AS400JDBCConnectionPool(tkcpds) Adds 1 connection to the pool that can be used by theapplication (creates the physical database connections based onthe data source)poolfill(1)Systemoutprintln(nStart timing Toolkit connection pooling)long startTime = SystemcurrentTimeMillis()

for (int i = 0 i lt outerNumOfLoops i++) con = poolgetConnection()consetAutoCommit(false) deleteif ( i == 0)

long startDelete = SystemcurrentTimeMillis()cstm = cstm = conprepareCall(

CALL qsysqcmdexc(CLRPFM FILE(DB2USERCOFFEES) + 000000002800000))

cstmexecuteUpdate()cstmclose()long endDelete = SystemcurrentTimeMillis()Systemoutprintln(Delete all records +

(endDelete - startDelete) + ms elapsed)

45

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

String sqlinstrlong startInsert = SystemcurrentTimeMillis() insert

pstmt =conprepareStatement(INSERT INTO COFFEES VALUES( ))for (int j = 0 j lt numOfLoops j++) pstmtsetString(1 Kona_ + IntegertoString(i))pstmtsetInt(2 150)pstmtsetFloat(3 999f)pstmtsetInt(4 0)pstmtsetInt(5 0)pstmtaddBatch()int [] updateCounts = pstmtexecuteBatch()concommit()pstmtclose()long endInsert = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for + numOfLoops + inserts

+ (endInsert - startInsert)) selectlong startSelect = SystemcurrentTimeMillis()ps = conprepareStatement(SELECT FROM COFFEES)ResultSet rs = psexecuteQuery()rsnext()rsclose()concommit()psclose()long endSelect = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for select +

(endSelect - startSelect))consetAutoCommit(true)conclose()long endTime = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for + outerNumOfLoops +

loops + (endTime - startTime))Systemexit(0)

private static void deployDataSource()throws ExceptionString serverName = teraplex String databaseName = TERAPLEX String userName = db2user String password = db2pwd

Establish a JNDI context and bind the connection pool data sourceHashtable env = new Hashtable()envput(ContextINITIAL_CONTEXT_FACTORY

comsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPoolDataSource tkcpds = new

AS400JDBCConnectionPoolDataSource()tkcpdssetServerName(serverName) tkcpdssetDatabaseName(databaseName) tkcpdssetUser(userName) tkcpdssetPassword(password) tkcpdssetDescription(Toolkit Connection Pooling DataSource)tkcpdssetSavePasswordWhenSerialized(true)tkcpdssetExtendedDynamic(true)

46

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

tkcpdssetPackage(JDBCDS)tkcpdssetPackageCache(true)tkcpdssetPackageCriteria(select)enable the following properties as requiredcpdssetTrace(true)tkcpdssetServerTraceCategories( AS400JDBCDataSourceSERVER_TRACE_DEBUG_SERVER_JOB)

ctxrebind(jdbcToolkitDataSource tkcpds)

47

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix B mdash Source Listing of cursorsjsqc

Source File Name = cursorsjsqc Licensed Materials - Property of IBM (C) COPYRIGHT International Business Machines Corp 1995 2000 2004 All Rights Reserved US Government Users Restricted Rights - Use duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp PURPOSE This sample program demonstrates the use of a CURSOR The CURSOR is processed using static SQL EXTERNAL DEPENDENCIES - Ensure existence of database for precompile purposes - Precompile with the SQL precompiler (PREP in DB2) - Bind to a database (BIND in DB2) - Compile and link with the IBM Cset++ compiler (AIX and OS2) or the Microsoft Visual C++ compiler (Windows) or the compiler supported on your platform For more information about these samples see the README file For more information on programming in C see the - Programming in C and C++ section of the Application Development Guide For more information on building C applications see the - Building C Applications section of the Application Building Guide For more information on the SQL language see the SQL Reference

include ltstdiohgt include ltstdlibhgt include ltstringhgtinclude ltsqlhgtinclude ltsqlenvhgtinclude ltsqldahgtinclude ltsqlcahgt

int SqlInfoPrint( char struct sqlca int char )void TransRollback( void)

define EMB_SQL_CHECK( MSG_STR ) rc = SqlInfoPrint( MSG_STR ampsqlca __LINE__ __FILE__) if ( rc = 0 ) TransRollback( )

return 1

EXEC SQL INCLUDE SQLCA

int main(int argc char argv[])

EXEC SQL BEGIN DECLARE SECTIONchar dname[15]

48

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

char pname[10]double compchar userid[9]char passwd[19]

EXEC SQL END DECLARE SECTION

int rc = 0printf( Sample C program CURSORSJ n )if (argc == 1)

EXEC SQL CONNECT TO TPLXEMB_SQL_CHECK(CONNECT TO TPLX)

else if (argc == 3)

strcpy (userid argv[1])strcpy (passwd argv[2])EXEC SQL CONNECT TO TPLX USER userid USING passwdEMB_SQL_CHECK(CONNECT TO TPLX)

else

printf (nUSAGE cursor [userid passwd]nn)return 1

endif

EXEC SQL DECLARE c1 CURSOR FORselect deptname name salary + ifnull(comm0) as compensationfrom org o staff swhere odeptnumb = sdeptorder by deptname compensation desc

EXEC SQL OPEN c1EMB_SQL_CHECK(OPEN CURSOR)

printf(DEPARTMENT NAME COMPENSn)printf(-----------------------------------n)do

EXEC SQL FETCH c1 INTO dname pname compif (SQLCODE = 0) breakprintf( -1515s -1010s 72fn dname pname comp )

while ( 1 )

EXEC SQL CLOSE c1EMB_SQL_CHECK(CLOSE CURSOR)

EXEC SQL CONNECT RESETEMB_SQL_CHECK(CONNECT RESET)

exit(0)

end of program CURSORSJSQC

int SqlInfoPrint( char appMsgstruct sqlca pSqlcaint linechar file )

int rc = 0char sqlInfo[1024]char sqlInfoToken[1024]char sqlstateMsg[1024]char errorMsg[1024]

if (pSqlca-gtsqlcode = 0 ampamp pSqlca-gtsqlcode = 100)

49

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

strcpy(sqlInfo )if( pSqlca-gtsqlcode lt 0) sprintf( sqlInfoToken n---- error report ----n)

strcat( sqlInfo sqlInfoToken)else sprintf( sqlInfoToken n---- warning report ----n)

strcat( sqlInfo sqlInfoToken) endif

sprintf( sqlInfoToken app message = sn appMsg)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken line = dn line)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken file = sn file)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken SQLCODE = ldn pSqlca-gtsqlcode)strcat( sqlInfo sqlInfoToken)

get error message rc = sqlaintp( errorMsg 1024 80 pSqlca) return code is the length of the errorMsg string if( rc gt 0) sprintf( sqlInfoToken sn errorMsg)

strcat( sqlInfo sqlInfoToken)

get SQLSTATE message rc = sqlogstt( sqlstateMsg 1024 80 pSqlca-gtsqlstate)if (rc == 0) sprintf( sqlInfoToken sn sqlstateMsg)

strcat( sqlInfo sqlInfoToken)

if( pSqlca-gtsqlcode lt 0) sprintf( sqlInfoToken --- end error report ---n)

strcat( sqlInfo sqlInfoToken)printf(s sqlInfo)return 1

else sprintf( sqlInfoToken --- end warning report ---n)

strcat( sqlInfo sqlInfoToken)printf(s sqlInfo)return 0

endif endif

return 0

void TransRollback( ) struct sqlca sqlca

int rc = 0 rollback the transaction printf( nRolling back the transaction n)

EXEC SQL ROLLBACKrc = SqlInfoPrint( ROLLBACK ampsqlca __LINE__ __FILE__)if( rc == 0) printf( The transaction was rolled backn)

50

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

51

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix C mdash Source Listing of testclicpp

Include The Appropriate Header Filesinclude ltsqlclihgtinclude ltsqlcli1hgtinclude ltsqlutilhgtinclude ltsqlenvhgtinclude ltstdiohgt include ltiostreamgt include ltlocalehgt include ltstringhgtdefine SQL_SQLSTATE_SIZE 5define LOOPS 8

using namespace std

Define The CLI_Class Classclass CLI_Class

Attributespublic

SQLHANDLE EnvHandleSQLHANDLE ConHandleSQLHANDLE StmtHandleSQLRETURN rcSQLCHAR Job[6]SQLCHAR Name[10]SQLDOUBLE Comp

Operationspublic

CLI_Class()~CLI_Class()SQLRETURN ShowResults()

Constructor Destructor

SQLRETURN printError( SQLHDBC SQLHSTMT)

Define The Class ConstructorCLI_ClassCLI_Class()

setlocale( LC_ALL )

Initialize The Return Code Variablerc = SQL_SUCCESS

Allocate An Environment Handlerc = SQLAllocHandle(SQL_HANDLE_ENV SQL_NULL_HANDLE ampEnvHandle)

Allocate A Connection Handleif (rc == SQL_SUCCESS)

rc = SQLAllocHandle(SQL_HANDLE_DBC EnvHandle ampConHandle)

Define The Class DestructorCLI_Class~CLI_Class()

Free The Connection Handleif (ConHandle = NULL)

SQLFreeHandle(SQL_HANDLE_DBC ConHandle)

Free The Environment Handle

52

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

if (EnvHandle = NULL)SQLFreeHandle(SQL_HANDLE_ENV EnvHandle)

Define The ShowResults() Member FunctionSQLRETURN CLI_ClassShowResults(void)

While There Are Records In The Result Data Set Generated Retrieve And Display Themcout ltlt Name Job Compensation ltlt endlcout ltlt --------- ------ ------------ ltlt endlcoutsetf(iosleft)coutprecision(2)coutsetf(iosfixed)while (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)

rc = SQLFetch(StmtHandle)if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)

coutwidth(15)cout ltlt Name

coutwidth(10)cout ltlt Job

coutwidth(7)cout ltlt Comp ltltendl

if(rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO ampamp rc = SQL_NO_DATA)printError(ConHandle StmtHandle)

else

rc = 0SQLCloseCursor(StmtHandle)

Return The ODBC API Return Code To The Calling Functionreturn(rc)

SQLRETURN CLI_ClassprintError (SQLHDBC hdbc

SQLHSTMT hstmt)

SQLCHAR buffer[SQL_MAX_MESSAGE_LENGTH + 1]SQLCHAR sqlstate[SQL_SQLSTATE_SIZE + 1]SQLINTEGER sqlcodeSQLSMALLINT lengthSQLRETURN rcwhile ((rc = SQLError(SQL_NULL_HENV hdbc hstmt

sqlstateampsqlcodebufferSQL_MAX_MESSAGE_LENGTH + 1amplength)) == SQL_SUCCESS || rc ==

SQL_SUCCESS_WITH_INFO)

cout ltlt SQLSTATE ltlt sqlstate ltlt endlcout ltlt SQLCODE ltlt sqlcode ltlt endlcout ltlt Error msg ltlt buffer ltlt endl

53

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

cout ltlt----------------------------- ltlt endl ltlt endl

return(SQL_ERROR)

----------------------------------------------------------------- The Main Function -----------------------------------------------------------------int main()

Declare The Local Memory Variables

(SQLCHAR ) db2user SQL_NTS (SQLCHAR ) test26t SQL_NTS)

SQLRETURNSQLCHARSQLCHARSQLCHARchar

SQLCHAR

rc = SQL_SUCCESSDBName[10] = TPLXSQLStmt[255]c[10]ptrcurrentDepartment[8][15] = Head Office

New England Mid Atlantic South Atlantic Great Lakes PlainsPacificMountain

Create An Instance Of The CLI_Class ClassCLI_Class Example

Connect To iSeries Database if (ExampleConHandle = NULL)

rc = SQLConnect(ExampleConHandle DBName SQL_NTS

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)ExampleprintError(ExampleConHandle SQL_NULL_HSTMT)

return(rc)

cout ltlt Successfully connected to ltlt DBName ltlt ltlt endlrc = SQLSetConnectAttr(ExampleConHandle SQL_ATTR_AUTOCOMMIT

(SQLPOINTER) SQL_AUTOCOMMIT_OFF SQL_IS_UINTEGER) Allocate An SQL Statement Handlerc = SQLAllocHandle(SQL_HANDLE_STMT ExampleConHandle

ampExampleStmtHandle)if (rc == SQL_SUCCESS)

Define A SELECT SQL Statement

strcpy((char ) SQLStmt select name job salary + ifnull(comm0) ascompensation )

ptr = strcat( (char ) SQLStmt from org o staff s )ptr = strcat( (char ) SQLStmt where odeptnumb = sdept)ptr = strcat( (char ) SQLStmt and deptname = )ptr = strcat( (char ) SQLStmt order by compensation desc)

Prepare The SQL Statementrc = SQLPrepare(ExampleStmtHandle SQLStmt SQL_NTS)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)ExampleprintError(ExampleConHandle ExampleStmtHandle)

54

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

return(rc)

Bind The Columns In The Result Data Set Returned To Application Variables

rc = SQLBindCol(ExampleStmtHandle 1 SQL_C_CHAR (SQLPOINTER)ExampleName sizeof(ExampleName) NULL)

rc = SQLBindCol(ExampleStmtHandle 2 SQL_C_CHAR (SQLPOINTER)ExampleJob sizeof(ExampleJob) NULL)

rc = SQLBindCol(ExampleStmtHandle 3 SQL_C_DOUBLE (SQLPOINTER)ampExampleComp sizeof(ExampleComp) NULL)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO) ExampleprintError(ExampleConHandle ExampleStmtHandle)

return(rc)

while (true)

for (int i = 0 i lt LOOPS i++)

rc=SQLBindParameter(ExampleStmtHandle1SQL_PARAM_INPUTSQL_C_CHARSQL_CHAR

150(SQLPOINTER) currentDepartment[i8]0NULL)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)

ExampleprintError(ExampleConHandle ExampleStmtHandle)return(rc)

rc = SQLExecute(ExampleStmtHandle)if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)

ExampleprintError(ExampleConHandle ExampleStmtHandle)return(rc)

cout ltlt endl ltlt Current Dept ltlt currentDepartment[i8] ltlt

endl Display The Results Of The SQL QueryExampleShowResults()if(rc = 0)break

if ( i500 == 0 ampamp i gt 0 )cout ltlt Loops ltlt i ltlt ltlt endl

cout ltlt AFTER ltlt LOOPS ltlt loops Press X to exit ltlt endlcin gtgt cif (c[0] == x || c[0] == X)

break

Free The SQL Statement Handleif (ExampleStmtHandle = NULL )

SQLFreeHandle(SQL_HANDLE_STMT ExampleStmtHandle) Disconnect From The Northwind Sample Databaserc = SQLDisconnect(ExampleConHandle)

Return To The Operating Systemreturn(rc)

55

Table of Contents Introduction 1DB2 UDB for iSeries runtime 1

DB2 SQL Runtime Interfaces 2Static SQL 2Dynamic SQL 3Extended Dynamic SQL 3

JDBC Data Access 4Initial Configuration Considerations 4

Virtual Versus Physical LAN 5Tuning DB2 UDB for iSeries Access with IBM Toolbox for Java and JTOpen Driver 6

Connection Pooling 7Extended Dynamic SQL and Statement Caching 9Reusable Open Data Paths (ODPs) 9Block Inserts 10

WebSphere Considerations 12Connection Pooling and Statement Caching 12Extended Dynamic SQL 12Changing the WebSphere Application Server default isolation level 13

Troubleshooting 16Job Log Messages 16JDBC Trace Utility 17Database Monitor 19

IBM DB2 JDBC Universal Driver 19Obtaining a Connection to DB2 UDB for iSeries 20Considerations 21

DB2 Connect data access 22DB2 Connect in a nutshell 23Prerequisites 24DB2 Connect configuration 24

Configuration steps in the iSeries partition 24ADDRDBDIRE RDB(TPLX) RMTLOCNAME(LOCAL) 24

Configuration steps in the AIX partition 26Accessing DB2 UDB for iSeries from C embedded SQL 34

Prerequisites 34Static SQL and SQL packages 34Simple embedded SQL application 34

Distributed Join 35Distributed Join Example 36

Connection Pooling and Connection Concentrator 38Troubleshooting 38Job Log Messages 39DB2 DRDA trace utility 40

Accessing DB2 for iSeries from CLI 40Prerequisites 40

Dynamic SQL and Access Plan Caching 40Simple DB2 CLI C++ Application 40

Reusable Open Data Paths (ODPs) 41Techniques to Further Improve DB2 CLI Performance 42

Connection Pooling 42Blocking 43Troubleshooting 43Job Log Messages 43CLI Trace 43

Trademarks 44

Additional Information 44Acknowledgments 44Appendix A Source Listing of TestJDBCjava 45Appendix B mdash Source Listing of cursorsjsqc 48Appendix C mdash Source Listing of testclicpp 52

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Introduction AIX 5Ltrade is quickly becoming the preferred commercial implementation of UNIX operating system The recently announced IBMreg eServertrade i5 servers can run AIX 5L in as many as 160 separate logical partitions (LPARs) This gives iSeriestrade customers a very rich portfolio of business applications that are currently available on AIXreg Traditionally many organizations use the iSeries server as a reliable and highly scalable database server The iSeries database DB2reg UDB for iSeries is fully integrated in i5OSreg and OS400reg and exploits its robust features such as single-level storage tight security and object-based architecture For these reasons IBM believes that DB2 UDB for iSeries will remain the database of choice for most iSeries shops

Generally AIX applications can use several programming environments to access the iSeries database JDBC ODBC DB2 CLI and embedded SQL However depending on the protocol and specific driver implementation an AIX application can directly communicate with a back-end database server job on an iSeries server or it may require DB2 Connecttrade Gateway services Currently only IBM Toolbox for Java JDBC driver supports a direct native connection to iSeries servers All other interfaces require DB2 Connect This paper provides connectivity options implementation tips and a number of coding examples that illustrate how to optimize the access to a DB2 UDB for iSeries database from an AIX partition for each of these programming interfaces

Disclaimer The performance information in this document is for guidance only System performance depends on many factors including system hardware system and user software and user application characteristics Customer applications must be carefully evaluated before estimating performance IBM does not warrant or represent that a user can or will achieve similar performance No warranty on system performance or price performance is expressed or implied in this document

DB2 UDB for iSeries runtime As mentioned the DB2 UDB for iSeries engine is integrated into i5OS It uses and depends on the operating system to provide many services such as locking security archivebackup buffer management and transaction services The operating system in turn uses and relies on the database engine to provide certain services From the DB2 point-of-view an AIX application running in a partition on an eServer i5 server is just a regular remote database client that uses the back-end database server jobs to submit SQL requests to SQL runtime The DB2 SQL runtime supports several interfaces that can be used to submit SQL statements The interface that is used by a particular client depends on the type of database driver used by the client to connect to DB2 For example JTOpen JDBC driver supports both dynamic and extended dynamic SQL while DB2 Universal JDBC driver supports just the dynamic SQL interface This topic will be discussed in details throughout this paper The typical data flow between an AIX client back-end database server job and DB2 SQL runtime is illustrated in Figure 1

1

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 1 - DB2 UDB for iSeries SQL runtime

DB2 SQL Runtime Interfaces Letrsquos briefly discuss the DB2 SQL runtime interfaces

Static SQL

The SQL statements are embedded in the source code of a host application program For example a stored procedure can be written in C++ and contains a number of embedded SQL statements In this case the stored procedure source code has to be processed by an SQL preshycompiler prior to compiling the host application program itself At that time the embedded SQL statements are parsed validated and optimized As a result of this process an access plan gets created for each statement The access plan is a control structure that contains information on the actions necessary to satisfy an SQL request Typically it contains

bull An access method that the optimizer selected for a given statement (for example table scan)

bull Information on associated tables and indexes that is used at runtime to determine if an access plan needs to be rebuilt due to table changes or index changes

bull Any applicable environment information such as jobrsquos code page

The access plan is then permanently stored in the program object and can be reused when the program is executed

In another scenario an embedded SQL application may be executed on a client for example in an AIX partition and access the DB2 UDB for iSeries through DB2 Connect In this case a client-side DB2 SQL precompiler stores the static SQL statements in a bind file The bind file is then

2

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

bound to the back-end database server The bind process creates an SQL package on the DB2 UDB for iSeries The package contains the access plans and other control structures that can be reused when the client program executes

Static SQL is the most efficient way to process SQL requests on an iSeries server

Dynamic SQL Dynamic SQL statements are parsed validated and optimized at the time an SQL application is executed The SQL statements are passed to the database manager in the form of a character string using the SQL statements PREPARE or EXECUTE IMMEDIATE The IBM Toolbox for JavaJTOpen JDBC driver uses this method if Extended Dynamic SQL support is not enabled The Dynamic SQL is also used by the dynamic SQL interfaces such as DB2 Call Level Interface (DB2 CLI) ODBC and JDBC when a client application connects to DB2 UDB for iSeries through DB2 Connect gateway Refer to DB2 Connect data access on page 22 of this paper for more details

Extended Dynamic SQL In Extended Dynamic SQL the SQL statements are dynamic However SQL packages are used to make the implementation of the dynamic SQL statements similar to that of static SQL The SQL statements are parsed validated and optimized and the resulting access plan is permanently stored in a SQL package Note that this process is dynamic and new statements can be added to the SQL package at the run time The IBM Toolbox for JavaJTOpen JDBC driver can take advantage of the Extended Dynamic SQL support

3

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

JDBC Data Access This section provides implementation tips and coding examples that illustrate how to optimize the access to your DB2 UDB for iSeries database from a AIX partition by using various JDBC drivers Currently IBM offers several AIX-enabled JDBC drivers that support DB2 UDB for iSeries

bull Type 4 drivers mdash IBM Toolbox for Java JTOpen and DB2 Universal JDBC Driver bull Type 2 driver mdash DB2 JDBC Type 2 Driver

The IBM Toolbox for Java iSeries driver has been implemented in pure Javatrade and optimized for accessing DB2 UDB for iSeries data It uses native iSeries protocol to communicate with the back-end database server job JTOpen is the open-source version of the IBM Toolbox for Java Licensed Program Product (LPP)

The DB2 Universal JDBC Driver is also a pure Java implementation It is a part of the DB2 UDB for AIX Version 8 product and it uses the Distributed Relational Database Architecture (DRDA) protocol for clientserver communications The driver is compatible with various DB2 UDB server platforms with appropriate DRDA Application Server (AS) level support and prerequisite stored procedures It also supports Type 2 connectivity when accessing DB2 UDB for Linuxreg UNIX and Windowsreg (DB2 UDB for LUW) databases

The traditional DB2 JDBC Type 2 Driver is built on top of DB2 Call Level Interface (CLI) It requires DB2 Connect functionality to access DB2 UDB for iSeries This is a legacy driver and IBM currently recommends that the DB2 Universal JDBC driver is used instead

Initial Configuration Considerations Practical experience shows that the JDBC application performance greatly depends on the programming techniques and the SQL access tuning However significant performance gains can be achieved by simply tweaking the AIX partition environment For example a virtual LAN connection to the back-end database can significantly streamline the data flow

4

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Virtual Versus Physical LAN One of the most significant benefits of installing AIX in an iSeries partition is the ability to utilize virtual LAN and virtual DASD This usually results in reduced hardware costs through improvements in data transfer performance and enhanced disk protection The performance tests conducted by the IBM eServer Solutions Enablement team showed that the Virtual 1Gb LAN delivered a data throughput similar to dedicated 1Gb Ethernet adapters (model 5706) connected via a dedicated Ethernet segment An example configuration is illustrated in Figure 2

Figure 2 VLAN vs 1 Gb Ethernet IOA configuration

Although similar performance can be expected for VLAN and 1Gb Ethernet the VLAN configuration has two advantages over the physical LAN connection

bull No additional communications gear is required bull It is a dedicated point-to-point connection so there is no interference from other devices on

the same network segment

On the other hand certain application scenarios may benefit from a physical LAN adapter dedicated to an AIX partition For instance in a three-tier application architecture clients connect to an application server running in a AIX partition The application server in turn connects to DB2 UDB for iSeries where data is stored and retrieved In this case configuring a separate physical LAN connection in a AIX partition has the following advantages

bull An unnecessary additional hop is eliminated from the network route bull Client-application server traffic does not unnecessarily saturate i5OS communications gear

5

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Tuning DB2 UDB for iSeries Access with IBM Toolbox for Java and JTOpen Driver This section covers JDBC implementation details for a sample Java program called TestJDBC (the source is provided at the end of this paper in Appendix A) The application uses the Java Naming and Directory Interface (JNDI) to obtain a database connection deletes 5000 records generates and inserts 5000 records and finally retrieves the newly inserted records from an SQL table called COFFEES The application executes in an AIX partition and accesses the DB2 UDB for iSeries through the JTOpen (or IBM Toolbox for Java) driver Figure 3 shows the software components involved in the execution of this simple application

Figure 3 JDBC client accessing DB2 UDB for iSeries

Apart from the JTOpen driver which can be downloaded from the IBM Toolbox for Java Web site you need three other JAR files to successfully compile and execute the JDBCTest application in a AIX partition

bull providerutiljar and fscontextjar mdashDownload a simple file system JNDI provider from Sun Microsystems JNDI Web site httpjavasuncomproductsjndidownloadsindexhtml

bull jdbc2_0-stdextjar mdash Copy the javaxsql package from the QIBMUserDataJava400ext IFS directory on the iSeries server

The location of the JAR files needs to be added to the CLASSPATH environment variable For instance the following entry could be added to the AIX profile script

6

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

CLASSPATH=homecodeJTOpenjt400jarCLASSPATH=$CLASSPATHhomecodefscontextproviderutiljarCLASSPATH=$CLASSPATHhomecodefscontextfscontextjarCLASSPATH=$CLASSPATHhomecodeJTOpenjdbc2_0-stdextjarexport CLASSPATH

To compile the source use the following command in the AIX partition

javac TestJDBCjava

Although the TestJDBC application is fairly simple it illustrates several important aspects of efficient JDBC programming for DB2 UDB for iSeries

Connection PoolingA JDBC connection can be obtained through either the DataSource or DriverManager object Either method involves significant overhead A fairly large amount of system resources is required to create and maintain the connection and then release it when it is no longer needed JTOpen allows a developer to establish a pool of database connections that can be shared by multiple client applications Connection pooling can improve the response time because the connection pool manager can locate and use an existing connection When the database request is completed the connection returns to the connection pool for reuse

In the JDBCTest sample JNDI was first used to register a connection pool-capable data source Heres an excerpt from the deployDataSource method of the sample application

Hashtable env = new Hashtable()envput(ContextINITIAL_CONTEXT_FACTORY

comsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env) [1]

Register an AS400JDBCConnectionPoolDataSource objectAS400JDBCConnectionPoolDataSource tkcpds = newAS400JDBCConnectionPoolDataSource() [2]tkcpdssetServerName(serverName) tkcpdssetDatabaseName(databaseName) tkcpdssetUser(userName) tkcpdssetPassword(password) tkcpdssetDescription(Toolkit Connection Pooling DataSourceobject) hellip ctxrebind(jdbcToolkitDataSource tkcpds) [3]

At [1] the initial JNDI context is created

Then at [2] an AS400JDBCConnectionPoolDataSource object is instantiated This is the JTOpen implementation of the javaxsqlConnectionPoolDataSource interface An AS400JDBCConnectionPoolDataSource object supports a number of methods that can be used to set iSeries-specific properties of the underlying DataSource object Some of these properties will be discussed in greater detail in the following sections of this paper

At [3] the data source object is bound to an arbitrary name that will be used in the main application Note that the deployDataSource method needs to be executed just once unless some of the data source properties need to be changed In that case the developer would need to rebind

7

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

The JNDI registered data source is then used in the main application to initialize the connection pool

AS400JDBCConnectionPoolDataSource tkcpds = [1](AS400JDBCConnectionPoolDataSource)ctxlookup(jdbcToolkitDataSource) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPool pool = newAS400JDBCConnectionPool(tkcpds)[2] Adds 1 connection to the pool that can be used by the application(creates the physical database connections based on the datasource)poolfill(1) [3] hellip con = poolgetConnection()[4]

At [1] the JNDI service is used to instantiate the AS400JDBCConnectionPoolDataSource

Then at [2] an AS400JDBCConnectionPool object is created This object is responsible for managing the connection pool

At [3] the connection pool is initialized with one connection

The pool object is used at [4] to obtain a database connection There are several additional things the developer should know about this code snippet

bull The advantage of using JNDI to register the data source object as opposed to just instantiating it in the main method is that in a more realistic scenario the data source would be registered just once at application deployment time Additionally the data source properties do not have to be hard-coded in the main method and can be changed at any time and then rebound without affecting the application

bull The AS400JDBCConnectionPool is a proprietary JTOpen implementation of a connection pool Specifically it does not implement the Referenceable interface and thus cannot be bound through JNDI services

bull The JTOpen AS400JDBCConnectionPoolDataSource does not support statement caching as described in the JDBC 30 specification Statement caching is implemented through SQL packages This feature is covered in the following section

Note The native iSeries JDBC driver supports both connection pooling and statement caching in a JDBC 30 compliant manner

8

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Extended Dynamic SQL and Statement Caching As mentioned the JTOpen data source object supports a number of properties that can be used to fine-tune the database performance In this section properties used to enable extended dynamic SQL support (see DB2 SQL Runtime Interfaces section above) and local statement caching will be discussed

Here is a relevant code excerpt from the deployDataSource method

AS400JDBCConnectionPoolDataSource tkcpds = new AS400JDBCConnectionPoolDataSource() hellip tkcpdssetExtendedDynamic(true)[1]tkcpdssetPackage(JDBCDS) [2]tkcpdssetPackageCache(true) [3]tkcpdssetPackageCriteria(select) [4]

At [1] the extended dynamic SQL support is enabled Note that the default is disabled for JTOpen The extended dynamic SQL functionality is often referred to as SQL package support The SQL packages are server-side repositories for SQL statements Packages contain the internal structures such as parse trees and access plans which are needed to execute SQL statements Because SQL packages are a shared resource the information built when a statement is prepared is available to all the users of the package This saves processing time especially in an environment where many users are using the same or similar statements Also because SQL packages are permanent this information is saved across job initiationtermination and IPLs In fact SQL packages can be saved and restored on other servers

At [2] the SQL package is named Note that the actual package name on the iSeries server is JDBCDSBAA The package name is generated by taking the name specified on the client and appending three letters that are an encoded set of the package configuration attributes By default an SQL package does not contain unparameterized select statements This behavior is overridden at [4] by setting the PackageCriteria property to select

At [3] the local statement cache is enabled A copy of the SQL package is cached on the AIX client This may improve application performance in a way similar to JDBC 30 statement caching Note however that local statement caching is not recommended for large SQL packages The copy of an SQL package is cached when the database connection is obtained This may cause increased network traffic as well as slow down the connection setup time

Reusable Open Data Paths (ODPs)An Open Data Path (ODP) definition is an internal i5OS object that is created when certain SQL statements (such as OPEN INSERT UPDATE and DELETE) are executed for the first time in a given job (or connection) The ODP can be thought of as a runtime implementation of an access plan The access plan created at the optimization time provides a recipe or in other words a sequence of steps necessary to execute the statement The ODP on the other hand provides the executable code for all requested IO operations The process of creating new ODP objects is fairly CPU- and IO-intensive so whenever possible the iSeries DB2 runtime tries to reuse existing ODPs For instance a ResultSetclose() call may close the SQL cursor but leave the ODP available to be used the next time the cursor is opened This can significantly reduce the response time in running SQL statements A reusable OPD usually requires 10 to 20 times less CPU resources than a newly created ODP Therefore it is important that the applications employ programming techniques that allow the DB2 runtime to reuse ODPs

With dynamic programming interfaces such as JDBC the most efficient way to avoid full opens is to employ the so-called prepare once execute many programming paradigm Ideally an SQL statement that is executed more than once should be prepared just once mdashfor example in the class constructor mdash and then reused for the consecutive executions At the prepare time the

9

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 engine stores the prepared statement along with the associated statement name in the QZDASOINIT jobs statement cache On the first execution the ODP created for a given statement is associated with the appropriate entry in the statement cache On consecutive executions the prepared statement and the corresponding ODP can be quickly located in the statement cache and reused The code snippet below illustrates the prepare once execute many programming technique

PreparedStatement pstmt = conprepareStatement(INSERT INTO COFFEES VALUES( ))[1] hellip for (int i = 0 i lt outerNumOfLoops i++)

insertfor (int j = 0 j lt numOfLoops j++)

pstmtsetString(1 Lavaza_ + IntegertoString(j)) hellip pstmtaddBatch()

int [] updateCounts = pstmtexecuteBatch()[2]concommit()

At [1] a PreparedStatement pstmt object is instantiated for a parameterized INSERT statement The statement is prepared just once The PreparedStatement object is then repeatedly used at [2] to perform blocked insert

Block Inserts Occasionally the developer may need to initially populate a table or insert a modified result set into a temporary table The efficiency of the insert operation for a large set of records can be dramatically improved by using the executeBatch method rather than the executeUpdate method The JTOpen driver converts parameterized insert statements in an executeBatch method to a block insert statement This significantly reduces the data flow and system resources required to perform the insert The following code snippet shows how to take advantage of the executeBatch method

10

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

PreparedStatement pstmt =conprepareStatement(INSERT INTO COFFEES VALUES( ))[1]for (int j = 0 j lt numOfLoops j++) pstmtsetString(1 Lavaza_ + IntegertoString(j))pstmtsetInt(2 i)pstmtsetFloat(3 499f)pstmtsetInt(4 0)pstmtsetInt(5 0)pstmtaddBatch() [2]

int [] updateCounts = pstmtexecuteBatch() [3]

At [1] a parameterized insert statement is prepared Note that all columns must be parameterized Otherwise the executeBatch method may throw the SQL0221 Number of rows 1 not valid exception In other words the developer should not mix parameter markers with literals or special registers in the VALUE clause

At [2] the addBatch method is used to add a new record to the client record buffer

At [3] all locally buffered data is sent to the server which in turn performs a block insert

Figure 4 shows the performance data for the executeBatch and executeUpdate methods

Figure 4 executeBatch() versus executeUpdate() performance comparison

11

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

WebSphere Considerations In certain situations an application provider may decide to deploy WebSphere Application Server in an AIX partition rather than natively in i5OS At the same time the application uses DB2 UDB for iSeries as an back-end database server Typically the WebSphere Application Server running in the AIX partition uses the virtual LAN to communicate with DB2 UDB for iSeries The WebSphere applications will access the database through a remote JDBC connection For performance and functionality reasons IBM recommends to utilize in such environments the IBM Toolbox for Java JTOpen driver Most of the tips and techniques described so far in this document hold true for WebSphere applications accessing DB2 UDB for iSeries There are however certain JDBC access aspects that are specific to this multi-tier architecture Letrsquos have a closer look at some of these considerations

Connection Pooling and Statement Caching

WebSphere Application Server provides its own connection pooling and statement caching mechanism that is by default enabled so that WebSphere applications automatically enjoy the performance benefits of these two critical programming techniques See the following link to learn more about the optimal connection pool setting in WebSphere

httppublibboulderibmcomwas40051englishinforzaiz51adminhelpudat_conpoolsethtml

Extended Dynamic SQL

For non-JTA connections WebSphere Application Server uses the comibmas400accessAS400JDBCConnectionPoolDataSource class as the iSeries JDBC provider implementation This is the DataSource implementation that has been used in all previous coding examples As mentioned the class supports a range of iSeries specific properties that can be used to fine tune JDBC performance These properties can be set through the WebSphere Application Server admin console For example herersquos the procedure to enable the extended dynamic SQL support In the WebSphere Application Server admin console navigate to the Data Source configuration dialog by selecting JDBC Providers -gt iSeriesToolbox -gt Data Sources then scroll down to the Additional Properties section Select Custom Properties link The Custom Properties dialog opens Scroll down to find the Extended Dynamic property and select it Change the default value false to true save the new configuration by clicking Apply button This is illustrated in Figure 5

12

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 5 Enabling the extended dynamic SQL through WebSphere Application Server console

The WebSphere Application Server needs to be restarted for the change to take effect The similar procedure can be followed to set other iSeries Data Source properties

Changing the WebSphere Application Server default isolation level

WebSphere Application Server V5 uses the REPEATABLE_READ (RR) isolation level for all implicit (WebSphere Application Server managed) transactions With the RR isolation level the rows selected updated deleted and inserted are locked until the end of the transaction Under certain circumstances this fairly extensive locking policy may cause locking contention especially when a WebSphere application competes for database resources with other applications that run on iSeries server For example a legacy order entry application may share data with the e-business customer care application running in WebSphere The locking contention may sometimes be eliminated by lowering the isolation level used by WebSphere Although the iSeries Data Source supports the custom transactionIsolation property resetting this property on the Data Source object will not change the default isolation level used by WebSphere for the connection objects produced by that Data Source In other words WebSphere will override the Data Source isolation level setting at the time the connection is obtained by a WebSphere application object such as servlet or Enterprise Java Bean (EJB) In order to change the default WebSphere behavior one must use the resource referencing Resource referencing allows a programmer to lookup DataSource or EJB objects using alias names rather than JNDI names Additionally by creating a resource reference a programmer can change certain properties of the underlying object Specifically a DataSource reference can be used to set a different isolation level for the connections produced by this database resource Typically resource references are defined by a programmer in a application development tool such as WebSphere Studio Application Developer The method to specify a DataSource reference differs depending on whether a programmer plans to use the reference in a servlet or in an EJB Letrsquos start with outlining the configuration process for a servlet In WebSphere Studio Application Developer open the deployment descriptor editor for the web project that contains the servlet To do so double click on the webxml file under WEB-INF directory in the web project In the deployment editor dialog select the References tab and then select Resource tab located in the top of the dialog that appears Under Resource References section select the Add button Herersquos an example of a DataSource reference created for iSeries DataSource named TestJDBCDS Note that the reference changes the default isolation level to READ_COMMITTED

13

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 6 Defining a resource reference for a servlet

Once the resource reference has been defined and saved the servlet source code needs to be changed to reflect the fact that a resource reference is used to obtain a DataSource from the JNDI service Herersquos the relevant code snippet try

ctx = new InitialContext() ds = (DataSource)ctxlookup(javacompenvTestJDBCJ2C)

catch (Exception e) eprintStackTrace(out)

Now the ds DataSource object will produce connections that by default run with the isolation level of READ_COMMITTED (RC)

As mentioned the process of defining a resource reference for an EJB differs from the process that is used in the case of a servlet In WebSphere Studio Application Developer open the deployment descriptor editor for the EJB project that contains the EJB To do so double click on the ejb-jarxml file under WEB-INF directory in the project In the deployment editor dialog select the References tab In the references section on the left locate and select the EJB for which the developer wants to change the default isolation level Click the Add button The Add Reference dialog opens Click the Resource Reference radio button and then Next Define the reference following the example shown in Figure 7

14

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 7 Adding a resource reference for an EJB

When you click ldquoFinishrdquo the reference definition is added to the EJB descriptor The new definition needs to be further modified To do so click on the (+) sign next to the EJB in the References list Click the new reference TestJDBCJ2C in this example to open the properties for the reference Change WebSphere Bindings and WebSphere Extensions sections as illustrated in Figure 8

15

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 8 Defining a resource reference for an EJB

Save the modified definition and then change the EJB source code to use the reference rather than directly DataSource

TroubleshootingTroubleshooting a multi-tier application may be a bit tricky because the developer needs to deal with software components that reside in separate partitions Three tools are particularly useful for pinning down the potential problem areas bull Joblog messages for a database server job mdash Provides enough details to isolate DB2 UDB for

iSeries runtime issues bull JDBC trace utility mdash Provides granular information about the data flow between the AIX

application and the iSeries server job bull Database Monitor ndash Provides detailed SQL runtime trace

Job Log MessagesAs mentioned a DB2 client communicates with a corresponding iSeries server job This server job runs the SQL requests on behalf of the client The iSeries database server jobs are called QZDASOINIT and they run in the QUSRWRK subsystem At any given time a large number of database server jobs may be active on the server so the first step is to identify the job that serves the particular client connection The easiest method to accomplish this task is to run the following CL command from the i5OS prompt

WRKOBJLCK OBJ(DB2USER) OBJTYPE(USRPRF)

Here DB2USER is the user profile that is used to connect to the iSeries server Note that a QZDASONIT job is assigned to a client after the connection has been established so the developer needs to set a breakpoint in the client application after the database connection has been established

Once the Work with Object Locks appears key in 5 (Work with Job) next to the only QZDASOINIT job that should be listed This shows the Work with Job dialog Select option 10 to

16

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

display the job log for the database server job Now the job log can be searched for any error messages generated by the DB2 runtime

Sometimes it is also useful to include debug messages in the job log The debug messages are informational messages written to the job log about the implementation of a query They describe query implementation methods such as the use of indexes join order ODP implementation (reusable versus non-reusable) and so on The easiest way to instruct an iSeries server to include the debug messages is to set the ServerTraceCategories property on the data source object

tkcpdssetServerTraceCategories(AS400JDBCDataSourceSERVER_TRACE_DEBUG_SERVER_JOB)

A sample of the job log messages with debug messages enabled is shown below

SET TRANSACTION completeSTATEMENT NAME FOUND QZ868F0A458E13AF8C Starting optimizer debug message for query Arrival sequence access was used for file COFFEESODP created ODP not deleted 5000 rows inserted in COFFEES in DB2USER STATEMENT NAME FOUND QZ868F0A4C144BF12EBlocking used for queryCursor CRSR0001 opened606 rows fetched from cursor CRSR0001 ODP not deleted Cursor CRSR0001 closed

So the job log offers fairly detailed information on how the AIX client requests were implemented by the DB2 runtime

JDBC Trace UtilityThe JTOpen driver provides a tracing utility which can be used to collect detailed client-side traces The JDBC tracing is turned off by default It can be enabled by setting the Trace property to true Heres an example of how to switch on tracing using the setTrace method on the data source object

tkcpdssetTrace(true)

The trace can also be enabled when using the DriverManagergetConnection() method for obtaining a connection to DB2 UDB for iSeries In this case the developer could add the trace property to the connection string This approach is illustrated in the following code snippet

ClassforName(comibmas400accessAS400JDBCDriver) [1] hellip con = DriverManagergetConnection(jdbcas400teraplextrace=true

db2userdb2pwd) [2]

At [1] an instance of the JTOpen JDBC Driver is initiated Then at [2] the driver is used to obtain a connection to the iSeries server Note how the trace property has been added to the database URL See the IBM Toolbox for Java JDBC properties documentation on the iSeries Information Center Web site for a complete list of properties supported by the JTOpen driver

Although the level of details provided by the trace utility is sufficient in most troubleshooting scenarios sometimes the developer may need to collect low-level traces scoped to a certain type

17

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

of information In V5R3 the IBM Toolbox for Java (as well as the latest JTOpen) added a comprehensive detailed trace facility The following is the complete list of detailed trace parameters and their purpose

bull None or ldquordquo ndash This setting disables the detailed trace bull datastream - This category is used by Toolbox classes to log dataflow between the local host

and the remote system It is not intended for use by application classes bull diagnostic - This category is used to log object state information bull error - This category is used to log errors that cause an exception bull information - This category is used to track the flow of control through the code bull warning - This category is used to log errors that are recoverable bull conversion - This category is used by Toolbox classes to log character set conversions

between Unicode and native code pages bull proxy - This category is used by Toolbox classes to log data flow between the client and the

proxy server bull pcml - This category is used to determine how PCML interprets the data that is sent to and

from the server bull jdbc - This category is used to track JDBC calls throughout the program bull thread - This category is used to enable tracing of thread information This is useful when

debugging multi-threaded applications bull all - This category will enable all previous categories

The detailed trace can be enabled when using the DriverManagergetConnection() method for obtaining a connection to DB2 UDB for iSeries In this case the developer could add the toolbox trace property to the connection string This is illustrated in the following code sample

String dbUrl = jdbcas400pwd1toolbox trace=diagnostic con = DriverManagergetConnection(dbUrl dbUser dbPassword)

Note that currently the driverrsquos DataSource interfaces do not allow the developer to directly activate the detailed tracing However they could set the server from the command line at the time the java program is launched The example below shows how the detailed trace properties could be enabled at the command line

java -Dcomibmas400accessTracecategory=diagnostic TestJDBC

The -D switch indicates to the java interpreter that the information following it will be a system property

In case of a WebSphere application the trace property can be set through the admin console In the console select Application Servers-gt server1-gt Process Definition -gt Java Virtual Machine Figure 9 shows how to set the Generic JVM Arguments for an application server instance

18

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 9 Setting JVM arguments to enable detailed Toolbox tracing

Database Monitor

The database monitor is the ultimate tool available on DB2 UDB for iSeries to collect low-level SQL traces It is mainly used to pin down the SQL performance problems Refer to the lsquoUsing iSeries Database Monitor to Identify and Tune SQL Queriesrsquo white paper for a detailed discussion on how to collect and analyze the database monitor traces httpibmcomserversenablesiteeducationiborecordhtmldtmon

IBM DB2 JDBC Universal Driver DB2 JDBC Universal Driver is one of the new features delivered with DB2 UDB Version 8 DB2 JDBC Universal Driver has been designed to eliminate the dependency on DB2 CLI runtime modules as well as to enable direct Type 4 connectivity to DB2 UDB for iSeries and DB2 UDB for zOSreg

The pure-Java (Type 4) remote connectivity is based on the DRDA open distributed protocol for cross-platform access to DB2 DRDA defines the rules the protocols and the semantics for accessing distributed data Applications can access data in a distributed relational environment by using SQL statements The iSeries DRDA application server implementation is based on multiple connection-oriented server jobs running in the QSYSWRK subsystem A DRDA listener job (QRWTLSTN) listens for TCP connect requests on port 446 Once an application requester connects to the listener job the listener wakes up one of the QRWTSRVR prestart jobs and assigns it to a given client connection Any further communication occurs directly between the client application and the QRWTSRVR job These concepts are illustrated in Figure 10

19

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 10 Accessing DB2 UDB for iSeries with DB2 Universal Driver

The DB2 Universal Driver can be loaded in an AIX partition by installing one of the DB2 Connect for AIX products (see the Additional Information section for details) It is also a part of a DB2 Enterprise Server Edition for AIX install Specifically the developer needs three JAR files in a AIX partition to successfully connect to an iSeries server db2jccjar db2jcc_license_cisuzjar and db2jcc_license_cujar The iSeries license is contained in db2jcc_license_cisuzjar Note that this file is not a part of DB2 Client In other words a DB2 Connect license is required to use the driver in production environments The location of the JAR files needs to be added to the CLASSPATH environment variable For instance the following entry could be added to the AIX profile script

CLASSPATH=homedb2inst2sqllibjavadb2jccjarCLASSPATH=$CLASSPATHhomedb2inst2sqllibjavadb2jcc_license_cujarCLASSPATH=$CLASSPATHhomedb2inst2sqllibjavadb2jcc_license_cisuzjarexport CLASSPATH

Java Runtime 131 is a prerequisite

Additionally the developer should install the latest database group PTF (SF99503 for i5OS V5R3) on the iSeries server The Informational APAR ii13348 is keeping track of any fixes relevant to DRDA above and beyond the current database group PTF

Obtaining a Connection to DB2 UDB for iSeries When Type 4 connectivity is used the DB2 Universal Driver connects directly to the DB2 on iSeries through TCPIP Note that this is different from the legacy DB2 Type 2 JDBC driver that requires a DB2 node and remote database configurations on the client accessing iSeries The following code snippet illustrates how to use the DB2 JDBC Universal Driver to obtain a connection to DB2 UDB for iSeries

20

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

try ClassforName(comibmdb2jccDB2Driver) [1] catch(javalangClassNotFoundException e) Systemerrprint(ClassNotFoundException )Systemerrprintln(egetMessage())

try DriverManagergetConnection(jdbcdb2teraplex446TERAPLEX[2]

db2userdb2pwd) hellip catch(SQLException ex) Systemerrprintln(

SQLException + exgetMessage())

At [1] an instance of the DB2 JDBC Universal Driver is instantiated Then at [2] the driver is used to obtain a connection to the iSeries server Note the proper form of the database URL required by the driver

Considerations There are several advantages of DB2 JDBC Universal Driver bull Ease of cross-platform development mdash Consistent coding techniques and consistent error

codes and messages bull Ease of deployment mdash Pure Java (no runtime client required) and a single driver for accessing

DB2 on different platforms

The ease of use comes at a price though The iSeries JTOpen driver is optimized for accessing DB2 UDB for iSeries data and it uses native iSeries protocol to communicate with the back-end database server job This usually results in better performance and more-efficient system resources utilization For instance when using the DB2 JDBC Universal Driver to access an iSeries server the executeBatch method results in a single record insert There are also some restrictions when using DB2 Universal JDBC Driver with Type 4 connectivity

bull Support for distributed transactions (JTA) is not enabled bull Driver built-in connection pooling is not supported

Refer to Java application support in DB2 for more details on DB2 JDBC Universal Driver

21

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 Connect data access This section will explore the most important aspects of DB2 Connect ndash iSeries integration - including configuration tips and coding examples

DB2 Connect provides functionality for accessing data stored in DB2 UDB for iSeries as well as DB2 UDB for zOS and DB2 UDB for OS390reg DB2 Connect offers capabilities to access DB2 family members via several SQL interfaces gateway functions such as connection pooling and federated database functionality Many applications supporting the DB2 family of products leverage DB2 Connect as a key middleware component DB2 Connect is offered as separate AIX license products

Enterprise Edition Application Server Edition

In addition to DB2 Connect there are several other DB2 UDB Version 81 products that are supported on AIX

DB2 Universal Database Enterprise Server Edition DB2 Universal Database Workgroup Server Unlimited Edition DB2 Universal Database Workgroup Server Edition DB2 Universal Database Universal Developers Edition All Clients

The DB2 Connect Enterprise Edition functionality is also contained in DB2 Enterprise Server Edition for AIX

22

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 Connect in a nutshell In the scenario described in this paper the DB2 Connect functions contained in DB2 Enterprise Edition for AIX are utilized DB2 Connect Enterprise Edition provides support for both local and remote DB2 clients This is illustrated in Figure 11 Accessing DB2 UDB for iSeries with DB2 Connect

Figure 11 Accessing DB2 UDB for iSeries with DB2 Connect

DB2 Connect implements the Distributed Relational Database Architecturetrade (DRDAreg) to reduce the cost and complexity of accessing data stored in DB2 UDB for iSeries and other DRDA-compliant database servers DRDA defines the rules the protocols and the semantics for accessing distributed data Applications can access data in a distributed relational environment by using SQL statements In a distributed environment the system running the application and sending the SQL requests across the network is called the application requester (AR) A remote database server that executes SQL requests submitted by an application requester is known as the application server (AS) In the example shown in Figure 11 (above) DB2 Connect plays the role of an application requester while DB2 UDB for iSeries is an application server In this case DB2 Connect communicates with the iSeries database through TCPIP The iSeries DRDA application server implementation is based on multiple connection-oriented server jobs running in the QSYSWRK subsystem A DRDA listener job (QRWTLSTN) listens for TCP connect requests on port 446 Once an application requester connects to the listener job the listener wakes up one of the QRWTSRVR prestart jobs and assigns it to a given client connection Any further communication occurs directly between the client application and the QRWTSRVR job

DB2 Connect supports a wide range of programming interfaces that can be used by AIX applications to access the iSeries database Embedded SQL frac34 Both static and dynamic SQL frac34 Various programming languages (Java CC++ Cobol Fortran REXX)

DB2 Call Level Interface (DB2 CLI) ODBC JDBC frac34 DB2 JDBC Type 2 Driver frac34 DB2 JDBC Type 4 Driver (Universal JDBC Driver)

23

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Note that DB2 Connect supports access to DB2 UDB for iSeries through DB2 JDBC Universal driver However for performance and ease of maintenance reasons IBM recommends that Java applications running in AIX use native iSeries Toolbox JDBC driver See the JDBC Data Access section of this paper (above) for more details On the other hand DB2 Connect is a very efficient and robust connectivity option for AIX applications especially in the environments that are not directly supported by the native iSeries JDBC driver Here are several possible scenarios that would require DB2 Connect installed in a AIX partition

Embedded SQL interface is used to access DB2 CLI or ODBC interface is used to access DB2 A single SQL interface is needed to access multiple back end DB2 server Specific DB2 Connect functionality is needed such as distributed join or connection

pooling

Prerequisites One of the DB2 Connect products or DB2 Enterprise Server Edition for AIX V81 is needed Additionally DB2 Application Development Client is required in the AIX partition to compile DB2 applications

For maximum database server stability the developer should install the latest database group PTF (SF99503 for i5OS V5R3) on the iSeries server The Informational APAR ii13348 is keeping track of any fixes relevant to DRDA above and beyond the current database group PTF

DB2 Connect configuration The following example employs i5OS V5R3 and DB2 UDB Enterprise Server Edition for AIX Version 81 FixPak 6

Configuration steps in the iSeries partition The following process lists the necessary steps to be performed on the iSeries server 1) Verify that the TCPIP stack is working correctly It is assumed that the Virtual LAN is used to

communicate with the i5OS partition First obtain the IP address of the iSeries server or its hostname and ping the iSeries server from the AIX partition

2) Create a relational database (RDB) entry for the iSeries database in the i5OS partition If this has already been created it can be displayed by using the DSPRDBDIRE command Make sure that the RDB entry with a location of LOCAL exists on the iSeries server If it does not exist use the ADDRDBDIRE command to add the appropriate RDB entry For example the following command would add an RDB entry named TPLX For simplicity it is recommended that the TCPIP host name and RDB entry remain the same

ADDRDBDIRE RDB(TPLX) RMTLOCNAME(LOCAL)

3) Create a collection called NULLID This is necessary because the utilities shipped with DB2 Connect and DB2 UDB for AIX store their packages in the NULLID collection Since it does not exist by default in the iSeries server you must create it using the following command

CRTLIB LIB(NULLID)

4) Products that support DRDA automatically perform any necessary code page conversions at the receiving system For this to happen both systems need a translation table from their code page to the partner code page The default Coded Character Set Identifier (CCSID) on the iSeries server is 65535 Since DB2 Connect does not have a translation table for this code page the developer needs to change the individual user profiles to contain a CCSID that can be converted properly by DB2 Connect For US English this is 037 For other languages see DB2 Connect Personal Edition Quick Beginning GC09-2967 The following command changes the CCSID for an individual user profile to 037

24

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

CHGUSRPRF userid CCSID(037)

5) Verify that the default port 446 for DRDA service is being used To do this go to the Configure TCPIP menu (CFGTCP) select Configure Related Tables and then select Work with service table entries Verify that the DRDA service is set for port 446

6) The Distributed Data Management (DDM) job must be started for DRDA to work If you want the DDM job to be automatically started whenever TCPIP is started change the attributes of the DDM job using the CHGDDMTCPA command and set the Autostart server parameter to YES

7) If the system administrator chooses not to autostart the server issue the following command to start the DDM server job

STRTCPSVR SERVER(DDM)

8) Make sure that the user profiles that will be used to connect to the iSeries server exist on the server

25

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Configuration steps in the AIX partition The following steps are required for DB2 Connect to be configured in the AIX partition 1) Sign on to the AIX partition as the DB2 administrator 2) Launch Client Configuration Assistant (db2ca from the command prompt) It is assumed that

VNC or an X-Windows server are being used on the workstation so that the db2ca GUI can be properly rendered

3) From the Selected pull-down menu select the Add Database using Wizard option The Select how you want to setup a connection dialog appears Select Manually configure a connection to a database and click Next This is shown in Figure 12

Figure 12 Accessing DB2 UDB for iSeries with DB2 Connect

26

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

4) On the Select a communications protocol choose TCPIP and select The database physical resides on a host or OS400 system Then select the option Connect directly to the server as shown in Figure 13 Click Next

Figure 13 mdash Selecting communications protocol

27

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

5) On the TCPIP tab fill in the host name of the iSeries server The port number should be 446 This is shown in Figure 14 Click Next

Figure 14 mdash Specifying TCPIP communication parameters

28

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

6) On the Database tab fill in the Relational Database name Use the RDB entry name (specified in step 2) in the Configuration steps in the iSeries partition section as shown in Figure 15 Click Next

Figure 15 mdash Specifying the remote database

7) If you plan to use the ODBC applications select Register this database for ODBC as a system data source on the ODBC tab Click Next

29

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

8) On the Specify the node option dialog select OS400 from the Operating System pull-down menu This is shown in Figure 16 Click Finish

Figure 16 mdash Specifying the node options

30

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

9) The Test Connection dialog appears This allows the developer to verify that the connection works Select both CLI and JDBC check boxes You are also prompted for an iSeries user ID and password as shown in Figure 17

Figure 17 mdash Testing the connection

31

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

10) The successful connection to the database server is confirmed by the message box shown in Figure 18

Figure 18 mdash Test Connection results 11) At this time a newly configured database connection should appear in the main DB2

Configuration Assistant window It is recommended that the DB2 utilities are also bound to the iSeries database The bind process creates the necessary SQL packages on the remote database In the main Configuration Assistant window click the TPLX database entry and then select Selected-gtBindhellip

32

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

12) The Bind dialog appears Click Select All and then enter the connection information as shown in Figure 19 Click Bind The Results message box appears This allows the developer to monitor the progress of the binding process Watch for any error and warning messages

Figure 19 mdash Binding the DB2 utilities This concludes the DB2 Connect configuration steps

33

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Accessing DB2 UDB for iSeries from C embedded SQL

As mentioned earlier DB2 Connect allows developers to compile and run embedded SQL applications that access DB2 UDB for iSeries data This section covers implementation details for a C embedded SQL application called cursorsjsqc (see Appendix B for source code)

Prerequisites An embedded SQL application running in an AIX partition will use DB2 Connect services to access DB2 UDB for iSeries therefore the developer needs to make sure that all components listed in section Prerequisites on page 24 are installed The developer also needs to create a remote database connection as described in the DB2 Connect configuration section of this paper on page 24

Static SQL and SQL packages To successfully run against a DB2 UDB for iSeries database an embedded SQL application needs to be first precompiled and bound to the back-end database This process creates an SQL package on the target iSeries server The SQL package contains the access plan information for the SQL statements executed by the application The internal structure of the package as well as the method how its content is used by the SQL runtime to facilitate the access plan reuse is similar to the Extended Dynamic SQL support covered in detail in the Extended Dynamic SQL and Statement Caching section of this paper (on page 9) There are however important differences between the packages created by the extended dynamic SQL support and the packages created for embedded SQL DRDA client applications The extended dynamic SQL packages support dynamic SQL interfaces such as JDBC

that can submit ad hoc SQL statements at the run time The SQL runtime can prepare the dynamic statements and add them to the package On the other hand the DRDA packages are created at the precompile time and contain static SQL In order to add new statements to the package the application needs to be precompiled and rebound again

The extended dynamic SQL package can dynamically grow up to 500MB by allocating new space as required The DRDA packages since they are created at the precompile time have a fix size and do not grow over their life time

Simple embedded SQL application The application is based on a source code provided in the DB2 UDB samples directory typically to be found at homedb2inst1sqllibsamples The cursorsjsqc performs a join between STAFF and ORG tables located in DB2USER schema (library) on the TPLX database server (the source is provided at the end of this paper in Appendix B) The join statement retrieves the DEPTNAME column from ORG NAME column from STAFF and calculates the total compensation for an employee by adding SALARY and COMM columns in STAFF The results are sorted by department name and total compensation Here is the SELECT statement used by the application

SELECT deptname name salary + IFNULL(comm0) as compensationFROM org o staff sWHERE odeptnumb = sdeptORDER BY deptname compensation DESC

The application iterates through the selected records and prints out the data to the standard output device The sample DB2USER schema was created with the following SQL statements

db2 CONNECT TO tplx USER db2user USING mypassworddb2 CALL QSYSCREATE_SQL_SAMPLE(DB2USER)

34

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Make sure that the AIX partition is logged into with the DB2 admin user profile If the defaults were selected at the DB2 installation time this profile name is db2inst1 It is also assumed that DB2USER user exists on the iSeries server and that it has appropriate authority

There are several steps that are required to create an executable for the cursorsjsqc source code First the DB2 PRECOMPILE utility needs to be called The utility creates a bind file that is used to bind the required SQL package to the TPLX database It also converts embedded SQL statements into DB2 run-time API calls and produces a pure C source file that can be processed by an AIX C compiler

db2 CONNECT TO tplx USER db2user USING mypassworddb2 prep cursorsjsqc bindfile

Note that the connect statement is required only if the developer is not already connected to the database on an iSeries server Watch for any error or warning messages returned by the DB2 prep utility The prepare step should produce cursorsjbnd and cursorsjc files in the current directory Now the developer can invoke the bind utility to prepare the statements contained in the bind file and create the package on the target iSeries database server

db2 bind cursorsjbnd

It is assumed that Visual C++ 60 is installed and configured in the AIX partition Refer to the ldquoDeveloping and Porting C and C++ Applications on AIXrdquo redbook for more information on how to use the Visual C++ compiler httpibmcomredbooksabstractssg245674htmlOpen

Use the following commands to compile the C source generated by the precompile utility

xlc -I$INSTHOMEsqllibinclude ndashc cursorsjcxlc ndasho cursorsj cursorsjo -L$INSTHOMEsqlliblib ndashldb2

Run the program from the AIX prompt

cursorsj db2user mypassword

Distributed Join DB2 UDB Version 8 provides core federated server functionality A federated system consists of a DB2 UDB instance that operates as a federated server a database that acts as the federated database one or more data sources and clients (users and applications) that access the database and data sources Federated server permits objects stored in multiple databases to be accessed together in the same query For example a query can refer to a table that resides in DB2 UDB for iSeries and join it to a table stored in DB2 UDB for AIX Such a query would constitute so called distributed join The support for DB2 UDB for iSeries as a federated data source is provided by core federated server functionality directly implemented in DB2 UDB Enterprise Server Edition and DB2 UDB Connect Enterprise Edition All other DB2 UDB family members are also supported directly by core DB2 UDB federated server An additional software product DB2 Information Integratortrade is required to access non-DB2 UDB databases such as Oracle Sybase or Microsoftreg SQL Server Consult the following white papers for a detailed discussion on DB2 federated server support Heterogeneous data access for iSeries applications Version 2 httpibmcomserversenablesiteeducationiborecordhtmlhetdata Fundamentals of IBM DB2 Federated Server and Relational Connect httpwww7bsoftwareibmcomdmddlibrarytecharticle0206purnell0206purnellhtml

35

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Distributed Join Example In this section the steps that are required to configure DB2 UDB for iSeries as a federated data source will be illustrated Then the cursorsjsqc program will be ldquotweakedrdquo so that it executes a distributed join query that accesses data stored on an iSeries server and in the local DB2 UDB for AIX database It is assumed that the developer is familiar with the DB2 federated server concepts

Note Run the following commands from the Command Line Processor prompt Load the utility by executing the db2 command at the AIX prompt 1) First the local DB2 UDB for AIX instance needs to be enabled as a DB2 federated server

This is done by setting the database manager configuration parameter FEDERATED to YES

db2=gt update dbm cfg using FEDERATED YES

The database instance needs to be restarted for the change to take effect

NOTE A federated database is a regular database in a DB2 UDB instance that has the FEDERATED parameter enabled Therefore in this example the SAMPLE database that was created earlier is used as the federated database A new database can also be created using the CREATE DATABASE command

2) Connect to the federated database

db2=gt connect to sample

3) Use the CREATE WRAPPER statement to register a wrapper for the iSeries data source Wrappers are library routines that are used by the federated server to perform operations such as connecting to a data source and retrieving data from it The default wrapper name for DB2 UDB for iSeries is DRDA Here is the command to register the DRDA wrapper

db2=gt create wrapper drda

4) Use the CREATE SERVER statement to register a data source as a server within the federated database The server definition specifies the type and version of the data source and the wrapper used for communications with this data source For the DB2 UDB for iSeries data source the node and the database names are also needed The node and database name parameters have been configured for our TPLX database in the Configuration steps in the AIX partition section (on page 24) Use the following DB2 UDB command to lookup these parameter on the federated server

db2=gt list database directory

In this case the command produced the following output

Database alias = TPLX Database name = DCSE99E1 Node name = NDE9BF76 Database release level = a00 Comment = Directory entry type = Remote Authentication = SERVER Catalog database partition number = -1

36

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Note that the node name is set to NDE9BF76 The name was generated by the Configuration Administrator utility (db2ca)

Here is the command to register the TPLX database as a federated server

db2=gt create server tplx type db2400 version 530 wrapperdrda authorization db2user password mypassword options(nodeNDE9BF76 dbname TPLX)

The command is quite complex so make sure that the syntax is correct

5) Define the user mappings that instructs the federated server what user ID and password should be used when connecting to the iSeries data source

db2=gt create user mapping for user server tplxoptions(remote_authid db2user remote_password mypassword)

Specify the nickname for the iSeries table or view A nickname is an identifier that is used by the federated server to reference an object located at the data source The following command creates a nickname for the STAFF table located in the DB2USER schema on the TPLX database

db2=gt create nickname tplx_staff for tplxdb2userstaff

6) Test the distributed join query

db2=gt SELECT deptname name salary + COALESCE(comm0) ascompensation FROM org o tplx_staff s WHERE odeptnumb =sdept ORDER BY deptname compensation DESC

Note that the native iSeries function IFNULL has been substituted with an equivalent DB2 UDB function COALESCE COALESCE is also supported on iSeries servers For better portability IBM encourages the use of COALESCE rather than IFNULL Note also that the query runs on the federated server rather than on TPLX It accesses the ORG table in the local DB2 UDB for AIX SAMPLE database and the STAFF table that resides in TPLX The federated server performs the necessary distributed join

7) Modify the cursorsjsqc so that it executes a distributed join There are two source code modifications - Change the CONNECT TO statements Now the application needs to connect to the

federated database SAMPLE rather than to TPLX

EXEC SQL CONNECT TO SAMPLEEXEC SQL CONNECT TO SAMPLE USER userid USING passwd

- Modify the select statement so that it performs a distributed join Use the statement (shown in step 6) above Save the new source version as cursordjsqc

- Prepare bind and compile the distributed join version of the program as described in the Simple C embedded SQL application section (on page 34)

db2 prep cursordjsqc bindfiledb2 bind cursordjbndxlc -I$INSTHOMEsqllibinclude ndashc cursordjcxlc ndasho cursordj cursordjo -L$INSTHOMEsqlliblib ndashldb2

37

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

- Run the program from the AIX prompt

cursordj

Connection Pooling and Connection ConcentratorA modern Web-based application typically executes a large number of short-lived transactions Executing a transaction in this environment means establishing a database connection executing a few SQL statements and terminating this connection Creating connections to the database server is a very costly process To reduce the unnecessary workload DB2 Connect implements connection pooling and connection concentrator Connection pooling mechanism allows DB2 Connect to reuse an existing connection infrastructure for subsequent connection requests The connection concentrator is an advanced technology that allows DB2 Connect to serve a potentially very large number of clients with a limited number of database connections This is accomplished by decoupling clients from a particular database connection

Note that currently neither connection pooling nor connection concentrator support DB2 UDB for iSeries Therefore for performance reasons the author strongly recommends that the application server that obtains and drops connections very frequently implements its own database connection pooling mechanism that would assign an existing pooled database connection to a new AIX process or thread

TroubleshootingTroubleshooting a multi-tier application may be a bit tricky because the developer needs to deal with software components that reside in separate partitions The authorrsquos experience shows that two tools are particularly useful for pinning down the potential problem areas The joblog messages for a database server job usually provide enough details to isolate DB2

UDB for iSeries runtime issues The DRDA trace utility provides granular information about the data flow between the AIX

application and the iSeries server job

38

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Job Log MessagesAs mentioned earlier a DB2 client communicates with a corresponding iSeries server job This server job runs the SQL requests on behalf of the client More precisely when a DB2 client submits an SQL statement the statement is passed to a server job that in turn calls the DB2 runtime to execute the statement The results are then reformatted and marshaled to the client The iSeries DRDA server jobs are called QRWTSRVR and they run in the QUSRWRK subsystem At any given time there may be a large number of DRDA server jobs active on the system so the first step is to identify the job that serves the particular client connection The easiest method to accomplish this task is to run the following CL command from the i5OS prompt

WRKOBJLCK OBJ(DB2USER) OBJTYPE(USRPRF)

Here DB2USER is the user profile that is used to connect to the iSeries server Note that a QRWTSRVR job is assigned to a client after the connection has been established so the developer needs to set a breakpoint in the client application below the CONNECT TO statement

Once the Work with Object Locks appears key in 5 (Work with Job) next to the only QRWTSRVR job that should be listed This shows the Work with Job dialog Select option 10 to display the job log for the database server job Now the developer can search the job log for any error messages generated by the DB2 runtime

Sometimes it is also useful to include debug messages in the job log The debug messages are informational messages written to the job log about the implementation of a query They describe query implementation methods such as use of indexes join order ODP implementation (reusable versus non-reusable) and so on The easiest way to instruct the iSeries server to include the debug messages is to call the following stored procedure just after the connection to the iSeries server is established

EXEC SQL call qsysqcmdexc(STRDBGUPDPROD(YES)000000002000000)

A sample of the job log messages with debug messages enabled is shown below in Figure 20

Arrival sequence access was used for file STAFFAccess path suggestion for file STAFFQuery options used to build the OS400 query access plan Ending debug message for query ODP created Blocking used for queryCursor SQLCUR201 opened1 rows fetched from cursor SQLCUR201Row not found for SQLCUR201ODP deleted Cursor SQLCUR201 closedDESCRIBE of prepared statement STMT0201 completed

Figure 20 mdash Joblog with debug messages enabled

So the job log offers fairly detailed information on how the AIX client requests were implemented by the DB2 runtime

39

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 DRDA trace utilityThe DB2 DRDA trace utility (db2drdat) provides detailed information about the data streams exchanged between DB2 Connect and target database server The output file produced by the utility contains send and receive communications buffers TCPIP error messages and SQL Communications Area (SQLCA) information Please refer to lsquoDB2 Connect Userrsquos Guidersquo manual for in-depth discussion of the DRDA trace utility

Accessing DB2 UDB for iSeries from CLI DB2 Call Level Interface (CLI ) is based on the Microsoft Open Database Connectivity (ODBC) specification and the ISO CLI standard The DB2 CLI interface gained popularity among DB2 application providers because the developer can build an ODBC application by simply linking the application with libdb2 library on a UNIX server In other words the developer directly utilizes the DB2 ODBC driver services without a need for an ODBC driver manager Additionally in contrast to embedded SQL the developer does not need to precompile or bind DB2 CLI applications because they use packages provided with DB2 UDB The developer simply compiles and links the application

Prerequisites A DB2 CLI application running in an AIX partition will use DB2 Connect services to access DB2 UDB for iSeries therefore make sure that all components listed in Prerequisites section of this paper on page 24 are installed The developer also needs to create a remote database connection as described in the DB2 Connect configuration section of this paper on page 24

Dynamic SQL and Access Plan Caching A DB2 CLI client application uses the dynamic SQL interface and does not have the capability to utilize the extended dynamic SQL support Therefore it runs lsquopurersquo dynamic SQL statements That does not mean however that the process of parsing validating and optimizing will be repeated for every execution of a given dynamic SQL statement

The DB2 UDB for iSeries database implements an internal object called System-Wide SQL Statement Cache (SWSC) The SWSC can improve the performance of programs using dynamic SQL statements by caching the access plans in a system-wide cache When a dynamic SQL statement is submitted the SQL runtime searches the SWSC to see if this statement has been previously executed If so then DB2 retrieves and reuses the key information associated with the cached statement and thereby the processing time and the resources utilization can be significantly reduced

Simple DB2 CLI C++ ApplicationThis section covers DB2 CLI implementation details for a sample C++ program called testclicpp (the source is provided at the end of this paper in Appendix C) To compile the source with Visual C++ complier use the following command in the AIX partition

xlC ndashI$INSTHOMEsqllibinclude ndashc testclicppxlC ndasho testcli testclio ndashL$INSTHOMEsqlliblib ndashldb2

The application performs a join between STAFF and ORG tables located in DB2USER schema (library) The join statement retrieves the DEPTNAME column from ORG NAME and JOB columns from STAFF and calculates the total compensation for an employee by adding SALARY and COMM columns in STAFF The results are sorted by total compensation The selection criterion is based on the current value of the department name parameter Here is the SELECT statement used by testcli

40

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

select name job salary + coalesce(comm0) as compensationfrom org o staff swhere odeptnumb = sdeptand deptname = order by compensation desc

Figure 21 shows the software components involved in the execution of this sample application

Figure 21 How a DB2 CLI client accesses DB2 UDB on an iSeries server

Although the testcli application is fairly simple it covers some important aspects of efficient CLI programming for DB2 UDB for iSeries

Reusable Open Data Paths (ODPs)An Open Data Path (ODP) definition is an internal i5OS object that is created when certain SQL statements (such as OPEN INSERT UPDATE and DELETE) are executed for the first time in a given job (or connection) The ODP can be thought of as a runtime implementation of an access plan The access plan created at the optimization time provides a recipe or in other words a sequence of steps necessary to execute the statement The ODP on the other hand provides the executable code for all requested IO operations The process of creating new ODP objects is fairly CPU- and IO-intensive so whenever possible the iSeries DB2 runtime tries to reuse existing ODPs For instance a SQLCloseCursor() API call may close the SQL cursor but leave the ODP available to be used the next time the cursor is opened This can significantly reduce the processing and response time in running SQL statements A reusable OPD usually requires 10 to 20 times less CPU resources than a newly created ODP Therefore it is important that the applications employ programming techniques that allow the DB2 runtime to reuse ODPs

With dynamic interfaces such as CLI full opens are avoided by using a prepare once execute many programming paradigm It means that when an SQL statement is going to be executed more than once you should prepare the statement just once and then reuse the prepared

41

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

statements for consecutive executions Although DB2 UDB does try to convert literals to parameter markers so that similar statements can be reused it is a better programming practice to explicitly implement parameter markers That way the chances for reusable ODPs are quite significantly improved The code snippet in Figure 22 illustrates how to implement the prepare once execute many programming technique

Define A SELECT SQL Statementstrcpy((char ) SQLStmt select name job salary + ifnull(comm0) ascompensation )ptr = strcat( (char ) SQLStmt from org o staff s )ptr = strcat( (char ) SQLStmt where odeptnumb = sdept)ptr = strcat( (char ) SQLStmt and deptname = )ptr = strcat( (char ) SQLStmt order by compensation desc) [1]

Prepare The SQL Statementrc = SQLPrepare(ExampleStmtHandle SQLStmt SQL_NTS) [2]

Bind The Columns In The Result Data Set Returned To Application Variablesrc = SQLBindCol(ExampleStmtHandle 1 SQL_C_CHAR (SQLPOINTER)

ExampleName sizeof(ExampleName) NULL)rc = SQLBindCol(ExampleStmtHandle 2 SQL_C_CHAR (SQLPOINTER)

ExampleJob sizeof(ExampleJob) NULL)rc = SQLBindCol(ExampleStmtHandle 3 SQL_C_DOUBLE (SQLPOINTER)

ampExampleComp sizeof(ExampleComp) NULL)

for (int i = 0 i lt LOOPS i++)rc=SQLBindParameter(ExampleStmtHandle

1SQL_PARAM_INPUTSQL_C_CHARSQL_CHAR10(SQLPOINTER) currentDepartment[i8]0NULL) [3]

rc = SQLExecute(ExampleStmtHandle) [4]cout ltlt endl ltlt Current Dept ltlt currentDepartment[i8] ltlt endl Display The Results Of The SQL QueryExampleShowResults()

Figure 22 Use the prepare once execute many programming technique

The error-handling code has been removed for clarity At [1] the statement text is assigned to a variable Note that a parameter marker is used in the WHERE clause The statement is then prepared just once at [2] The current value of the parameter is bound to the prepared statement at [3] The prepared statement is executed at [4] Steps [3] and [4] are repeatedly executed in a for loop

Techniques to Further Improve DB2 CLI Performance Thus far this paper has discussed the techniques used by a sample application to tune the CLI performance However depending on the application architecture other methods of improving CLI performance may be considered

Connection PoolingCurrently the CLI application connecting through DB2 Connect to DB2 UDB for iSeries does not take advantage of the connection pooling mechanism implemented by DB2 Connect Therefore for performance reasons the author strongly recommends that the application server that obtains and drops connections very frequently implements its own database connection pooling mechanism that would assign an existing pooled database connection to a new AIX process or thread

42

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Blocking

For queries which result in returning large data blocks from the iSeries server (usually 32K of data and above) ensure that the database manager configuration parameter RQRIOBLK is set to 32767 This can be done using the Command Line Processor (CLP) as follows

db2 update database manager configuration using RQRIOBLK 32767

TroubleshootingThe experience of the author shows that two tools are particularly useful for pinning down the potential problem areas bull Joblog messages for a database server job usually provides enough details to isolate DB2

runtime issues bull CLI trace utility provides granular information about the data flow between the AIX application

and the database server job

Job Log MessagesThe process of finding and analyzing the job log for a DB2 CLI connection is identical to the process outlined for an embedded SQL application in the Job Log Message section of this paper on page 39

CLI Trace The DB2 CLIODBCJDBC trace utility provides very detailed information about the data streams exchanged between DB2 Connect and target database server Refer to the DB2 Information Center for more information on how to set up and analyze the CLI traces httppublibboulderibmcominfocenterdb2v8luwindexjsptopic=comibmdb2udbdocadc000 7959htm

43

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Trademarks

IBM eServer iSeries AIX AIX 5L i5OS WebSphere DB2 DB2 Universal Database DB2 Connect OS400 zOS OS390 Distributed Relational Database Architecture DRDA and DB2 Information Integration are trademarks or registered trademarks of International Business Machines Corporation in the United States and other countries

Java and all Java-based trademarks are trademarks of Sun Microsystems Inc in the United States other countries or both

Linux is a registered trademark of Linus Torvalds in the United States other countries or both

UNIX is a registered trademark of The Open Group in the United States and other countries

Microsoft and Windows are registered trademarks of Microsoft Corporation in the United States andor other countries

All other registered trademarks and trademarks are properties of their respective owners

IBM makes no commitment to make available any products referred to herein

References in this publication to IBM products or services do not imply that IBM intends to make them available in every country in which IBM operates

Additional Information ITSO offers a Redbook that can be helpful to those who want to learn more about i5OS AIX integration

bull AIX Integration with I5OS on the IBM eServer iSeries Server (SG24-6551)

Jarek Miszczyk is the Senior Software Engineer IBM eServer Solutions Enablement IBM Rochester

[Portions of this white paper reprinted with permission from MC Mag Online published by MC Press LLP httpwwwmcpressonlinecom]

Acknowledgments The author would like to thank the following people for their advice contributions and support on this paper

Bob Bittner IBM Rochester Jon Rush IBM Rochester Prasad Vallurupalli IBM Rochester Neil Willis IBM Rochester

44

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix A Source Listing of TestJDBCjava

package comibmiseriespwdimport javasqlimport javaxnamingimport javautilHashtableimport javautilimport javaxsqlimport comibmas400access

public class TestJDBC public static void main(javalangString[] args)

throws Exception

int numOfLoops = 5000int outerNumOfLoops = 5boolean firstExec = trueConnection conStatement sPreparedStatement psPreparedStatement pstmtdelCallableStatement cstmPreparedStatement pstmtHashtable env = new Hashtable()

envput(ContextINITIAL_CONTEXT_FACTORYcomsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env)Systemoutprintln(Deploying connection pooling data source)deployDataSource() Do the work with connection pooling onlyAS400JDBCConnectionPoolDataSource tkcpds =

(AS400JDBCConnectionPoolDataSource)ctxlookup(jdbcToolkitDataSource) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPool pool = new AS400JDBCConnectionPool(tkcpds) Adds 1 connection to the pool that can be used by theapplication (creates the physical database connections based onthe data source)poolfill(1)Systemoutprintln(nStart timing Toolkit connection pooling)long startTime = SystemcurrentTimeMillis()

for (int i = 0 i lt outerNumOfLoops i++) con = poolgetConnection()consetAutoCommit(false) deleteif ( i == 0)

long startDelete = SystemcurrentTimeMillis()cstm = cstm = conprepareCall(

CALL qsysqcmdexc(CLRPFM FILE(DB2USERCOFFEES) + 000000002800000))

cstmexecuteUpdate()cstmclose()long endDelete = SystemcurrentTimeMillis()Systemoutprintln(Delete all records +

(endDelete - startDelete) + ms elapsed)

45

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

String sqlinstrlong startInsert = SystemcurrentTimeMillis() insert

pstmt =conprepareStatement(INSERT INTO COFFEES VALUES( ))for (int j = 0 j lt numOfLoops j++) pstmtsetString(1 Kona_ + IntegertoString(i))pstmtsetInt(2 150)pstmtsetFloat(3 999f)pstmtsetInt(4 0)pstmtsetInt(5 0)pstmtaddBatch()int [] updateCounts = pstmtexecuteBatch()concommit()pstmtclose()long endInsert = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for + numOfLoops + inserts

+ (endInsert - startInsert)) selectlong startSelect = SystemcurrentTimeMillis()ps = conprepareStatement(SELECT FROM COFFEES)ResultSet rs = psexecuteQuery()rsnext()rsclose()concommit()psclose()long endSelect = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for select +

(endSelect - startSelect))consetAutoCommit(true)conclose()long endTime = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for + outerNumOfLoops +

loops + (endTime - startTime))Systemexit(0)

private static void deployDataSource()throws ExceptionString serverName = teraplex String databaseName = TERAPLEX String userName = db2user String password = db2pwd

Establish a JNDI context and bind the connection pool data sourceHashtable env = new Hashtable()envput(ContextINITIAL_CONTEXT_FACTORY

comsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPoolDataSource tkcpds = new

AS400JDBCConnectionPoolDataSource()tkcpdssetServerName(serverName) tkcpdssetDatabaseName(databaseName) tkcpdssetUser(userName) tkcpdssetPassword(password) tkcpdssetDescription(Toolkit Connection Pooling DataSource)tkcpdssetSavePasswordWhenSerialized(true)tkcpdssetExtendedDynamic(true)

46

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

tkcpdssetPackage(JDBCDS)tkcpdssetPackageCache(true)tkcpdssetPackageCriteria(select)enable the following properties as requiredcpdssetTrace(true)tkcpdssetServerTraceCategories( AS400JDBCDataSourceSERVER_TRACE_DEBUG_SERVER_JOB)

ctxrebind(jdbcToolkitDataSource tkcpds)

47

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix B mdash Source Listing of cursorsjsqc

Source File Name = cursorsjsqc Licensed Materials - Property of IBM (C) COPYRIGHT International Business Machines Corp 1995 2000 2004 All Rights Reserved US Government Users Restricted Rights - Use duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp PURPOSE This sample program demonstrates the use of a CURSOR The CURSOR is processed using static SQL EXTERNAL DEPENDENCIES - Ensure existence of database for precompile purposes - Precompile with the SQL precompiler (PREP in DB2) - Bind to a database (BIND in DB2) - Compile and link with the IBM Cset++ compiler (AIX and OS2) or the Microsoft Visual C++ compiler (Windows) or the compiler supported on your platform For more information about these samples see the README file For more information on programming in C see the - Programming in C and C++ section of the Application Development Guide For more information on building C applications see the - Building C Applications section of the Application Building Guide For more information on the SQL language see the SQL Reference

include ltstdiohgt include ltstdlibhgt include ltstringhgtinclude ltsqlhgtinclude ltsqlenvhgtinclude ltsqldahgtinclude ltsqlcahgt

int SqlInfoPrint( char struct sqlca int char )void TransRollback( void)

define EMB_SQL_CHECK( MSG_STR ) rc = SqlInfoPrint( MSG_STR ampsqlca __LINE__ __FILE__) if ( rc = 0 ) TransRollback( )

return 1

EXEC SQL INCLUDE SQLCA

int main(int argc char argv[])

EXEC SQL BEGIN DECLARE SECTIONchar dname[15]

48

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

char pname[10]double compchar userid[9]char passwd[19]

EXEC SQL END DECLARE SECTION

int rc = 0printf( Sample C program CURSORSJ n )if (argc == 1)

EXEC SQL CONNECT TO TPLXEMB_SQL_CHECK(CONNECT TO TPLX)

else if (argc == 3)

strcpy (userid argv[1])strcpy (passwd argv[2])EXEC SQL CONNECT TO TPLX USER userid USING passwdEMB_SQL_CHECK(CONNECT TO TPLX)

else

printf (nUSAGE cursor [userid passwd]nn)return 1

endif

EXEC SQL DECLARE c1 CURSOR FORselect deptname name salary + ifnull(comm0) as compensationfrom org o staff swhere odeptnumb = sdeptorder by deptname compensation desc

EXEC SQL OPEN c1EMB_SQL_CHECK(OPEN CURSOR)

printf(DEPARTMENT NAME COMPENSn)printf(-----------------------------------n)do

EXEC SQL FETCH c1 INTO dname pname compif (SQLCODE = 0) breakprintf( -1515s -1010s 72fn dname pname comp )

while ( 1 )

EXEC SQL CLOSE c1EMB_SQL_CHECK(CLOSE CURSOR)

EXEC SQL CONNECT RESETEMB_SQL_CHECK(CONNECT RESET)

exit(0)

end of program CURSORSJSQC

int SqlInfoPrint( char appMsgstruct sqlca pSqlcaint linechar file )

int rc = 0char sqlInfo[1024]char sqlInfoToken[1024]char sqlstateMsg[1024]char errorMsg[1024]

if (pSqlca-gtsqlcode = 0 ampamp pSqlca-gtsqlcode = 100)

49

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

strcpy(sqlInfo )if( pSqlca-gtsqlcode lt 0) sprintf( sqlInfoToken n---- error report ----n)

strcat( sqlInfo sqlInfoToken)else sprintf( sqlInfoToken n---- warning report ----n)

strcat( sqlInfo sqlInfoToken) endif

sprintf( sqlInfoToken app message = sn appMsg)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken line = dn line)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken file = sn file)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken SQLCODE = ldn pSqlca-gtsqlcode)strcat( sqlInfo sqlInfoToken)

get error message rc = sqlaintp( errorMsg 1024 80 pSqlca) return code is the length of the errorMsg string if( rc gt 0) sprintf( sqlInfoToken sn errorMsg)

strcat( sqlInfo sqlInfoToken)

get SQLSTATE message rc = sqlogstt( sqlstateMsg 1024 80 pSqlca-gtsqlstate)if (rc == 0) sprintf( sqlInfoToken sn sqlstateMsg)

strcat( sqlInfo sqlInfoToken)

if( pSqlca-gtsqlcode lt 0) sprintf( sqlInfoToken --- end error report ---n)

strcat( sqlInfo sqlInfoToken)printf(s sqlInfo)return 1

else sprintf( sqlInfoToken --- end warning report ---n)

strcat( sqlInfo sqlInfoToken)printf(s sqlInfo)return 0

endif endif

return 0

void TransRollback( ) struct sqlca sqlca

int rc = 0 rollback the transaction printf( nRolling back the transaction n)

EXEC SQL ROLLBACKrc = SqlInfoPrint( ROLLBACK ampsqlca __LINE__ __FILE__)if( rc == 0) printf( The transaction was rolled backn)

50

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

51

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix C mdash Source Listing of testclicpp

Include The Appropriate Header Filesinclude ltsqlclihgtinclude ltsqlcli1hgtinclude ltsqlutilhgtinclude ltsqlenvhgtinclude ltstdiohgt include ltiostreamgt include ltlocalehgt include ltstringhgtdefine SQL_SQLSTATE_SIZE 5define LOOPS 8

using namespace std

Define The CLI_Class Classclass CLI_Class

Attributespublic

SQLHANDLE EnvHandleSQLHANDLE ConHandleSQLHANDLE StmtHandleSQLRETURN rcSQLCHAR Job[6]SQLCHAR Name[10]SQLDOUBLE Comp

Operationspublic

CLI_Class()~CLI_Class()SQLRETURN ShowResults()

Constructor Destructor

SQLRETURN printError( SQLHDBC SQLHSTMT)

Define The Class ConstructorCLI_ClassCLI_Class()

setlocale( LC_ALL )

Initialize The Return Code Variablerc = SQL_SUCCESS

Allocate An Environment Handlerc = SQLAllocHandle(SQL_HANDLE_ENV SQL_NULL_HANDLE ampEnvHandle)

Allocate A Connection Handleif (rc == SQL_SUCCESS)

rc = SQLAllocHandle(SQL_HANDLE_DBC EnvHandle ampConHandle)

Define The Class DestructorCLI_Class~CLI_Class()

Free The Connection Handleif (ConHandle = NULL)

SQLFreeHandle(SQL_HANDLE_DBC ConHandle)

Free The Environment Handle

52

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

if (EnvHandle = NULL)SQLFreeHandle(SQL_HANDLE_ENV EnvHandle)

Define The ShowResults() Member FunctionSQLRETURN CLI_ClassShowResults(void)

While There Are Records In The Result Data Set Generated Retrieve And Display Themcout ltlt Name Job Compensation ltlt endlcout ltlt --------- ------ ------------ ltlt endlcoutsetf(iosleft)coutprecision(2)coutsetf(iosfixed)while (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)

rc = SQLFetch(StmtHandle)if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)

coutwidth(15)cout ltlt Name

coutwidth(10)cout ltlt Job

coutwidth(7)cout ltlt Comp ltltendl

if(rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO ampamp rc = SQL_NO_DATA)printError(ConHandle StmtHandle)

else

rc = 0SQLCloseCursor(StmtHandle)

Return The ODBC API Return Code To The Calling Functionreturn(rc)

SQLRETURN CLI_ClassprintError (SQLHDBC hdbc

SQLHSTMT hstmt)

SQLCHAR buffer[SQL_MAX_MESSAGE_LENGTH + 1]SQLCHAR sqlstate[SQL_SQLSTATE_SIZE + 1]SQLINTEGER sqlcodeSQLSMALLINT lengthSQLRETURN rcwhile ((rc = SQLError(SQL_NULL_HENV hdbc hstmt

sqlstateampsqlcodebufferSQL_MAX_MESSAGE_LENGTH + 1amplength)) == SQL_SUCCESS || rc ==

SQL_SUCCESS_WITH_INFO)

cout ltlt SQLSTATE ltlt sqlstate ltlt endlcout ltlt SQLCODE ltlt sqlcode ltlt endlcout ltlt Error msg ltlt buffer ltlt endl

53

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

cout ltlt----------------------------- ltlt endl ltlt endl

return(SQL_ERROR)

----------------------------------------------------------------- The Main Function -----------------------------------------------------------------int main()

Declare The Local Memory Variables

(SQLCHAR ) db2user SQL_NTS (SQLCHAR ) test26t SQL_NTS)

SQLRETURNSQLCHARSQLCHARSQLCHARchar

SQLCHAR

rc = SQL_SUCCESSDBName[10] = TPLXSQLStmt[255]c[10]ptrcurrentDepartment[8][15] = Head Office

New England Mid Atlantic South Atlantic Great Lakes PlainsPacificMountain

Create An Instance Of The CLI_Class ClassCLI_Class Example

Connect To iSeries Database if (ExampleConHandle = NULL)

rc = SQLConnect(ExampleConHandle DBName SQL_NTS

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)ExampleprintError(ExampleConHandle SQL_NULL_HSTMT)

return(rc)

cout ltlt Successfully connected to ltlt DBName ltlt ltlt endlrc = SQLSetConnectAttr(ExampleConHandle SQL_ATTR_AUTOCOMMIT

(SQLPOINTER) SQL_AUTOCOMMIT_OFF SQL_IS_UINTEGER) Allocate An SQL Statement Handlerc = SQLAllocHandle(SQL_HANDLE_STMT ExampleConHandle

ampExampleStmtHandle)if (rc == SQL_SUCCESS)

Define A SELECT SQL Statement

strcpy((char ) SQLStmt select name job salary + ifnull(comm0) ascompensation )

ptr = strcat( (char ) SQLStmt from org o staff s )ptr = strcat( (char ) SQLStmt where odeptnumb = sdept)ptr = strcat( (char ) SQLStmt and deptname = )ptr = strcat( (char ) SQLStmt order by compensation desc)

Prepare The SQL Statementrc = SQLPrepare(ExampleStmtHandle SQLStmt SQL_NTS)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)ExampleprintError(ExampleConHandle ExampleStmtHandle)

54

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

return(rc)

Bind The Columns In The Result Data Set Returned To Application Variables

rc = SQLBindCol(ExampleStmtHandle 1 SQL_C_CHAR (SQLPOINTER)ExampleName sizeof(ExampleName) NULL)

rc = SQLBindCol(ExampleStmtHandle 2 SQL_C_CHAR (SQLPOINTER)ExampleJob sizeof(ExampleJob) NULL)

rc = SQLBindCol(ExampleStmtHandle 3 SQL_C_DOUBLE (SQLPOINTER)ampExampleComp sizeof(ExampleComp) NULL)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO) ExampleprintError(ExampleConHandle ExampleStmtHandle)

return(rc)

while (true)

for (int i = 0 i lt LOOPS i++)

rc=SQLBindParameter(ExampleStmtHandle1SQL_PARAM_INPUTSQL_C_CHARSQL_CHAR

150(SQLPOINTER) currentDepartment[i8]0NULL)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)

ExampleprintError(ExampleConHandle ExampleStmtHandle)return(rc)

rc = SQLExecute(ExampleStmtHandle)if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)

ExampleprintError(ExampleConHandle ExampleStmtHandle)return(rc)

cout ltlt endl ltlt Current Dept ltlt currentDepartment[i8] ltlt

endl Display The Results Of The SQL QueryExampleShowResults()if(rc = 0)break

if ( i500 == 0 ampamp i gt 0 )cout ltlt Loops ltlt i ltlt ltlt endl

cout ltlt AFTER ltlt LOOPS ltlt loops Press X to exit ltlt endlcin gtgt cif (c[0] == x || c[0] == X)

break

Free The SQL Statement Handleif (ExampleStmtHandle = NULL )

SQLFreeHandle(SQL_HANDLE_STMT ExampleStmtHandle) Disconnect From The Northwind Sample Databaserc = SQLDisconnect(ExampleConHandle)

Return To The Operating Systemreturn(rc)

55

Additional Information 44Acknowledgments 44Appendix A Source Listing of TestJDBCjava 45Appendix B mdash Source Listing of cursorsjsqc 48Appendix C mdash Source Listing of testclicpp 52

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Introduction AIX 5Ltrade is quickly becoming the preferred commercial implementation of UNIX operating system The recently announced IBMreg eServertrade i5 servers can run AIX 5L in as many as 160 separate logical partitions (LPARs) This gives iSeriestrade customers a very rich portfolio of business applications that are currently available on AIXreg Traditionally many organizations use the iSeries server as a reliable and highly scalable database server The iSeries database DB2reg UDB for iSeries is fully integrated in i5OSreg and OS400reg and exploits its robust features such as single-level storage tight security and object-based architecture For these reasons IBM believes that DB2 UDB for iSeries will remain the database of choice for most iSeries shops

Generally AIX applications can use several programming environments to access the iSeries database JDBC ODBC DB2 CLI and embedded SQL However depending on the protocol and specific driver implementation an AIX application can directly communicate with a back-end database server job on an iSeries server or it may require DB2 Connecttrade Gateway services Currently only IBM Toolbox for Java JDBC driver supports a direct native connection to iSeries servers All other interfaces require DB2 Connect This paper provides connectivity options implementation tips and a number of coding examples that illustrate how to optimize the access to a DB2 UDB for iSeries database from an AIX partition for each of these programming interfaces

Disclaimer The performance information in this document is for guidance only System performance depends on many factors including system hardware system and user software and user application characteristics Customer applications must be carefully evaluated before estimating performance IBM does not warrant or represent that a user can or will achieve similar performance No warranty on system performance or price performance is expressed or implied in this document

DB2 UDB for iSeries runtime As mentioned the DB2 UDB for iSeries engine is integrated into i5OS It uses and depends on the operating system to provide many services such as locking security archivebackup buffer management and transaction services The operating system in turn uses and relies on the database engine to provide certain services From the DB2 point-of-view an AIX application running in a partition on an eServer i5 server is just a regular remote database client that uses the back-end database server jobs to submit SQL requests to SQL runtime The DB2 SQL runtime supports several interfaces that can be used to submit SQL statements The interface that is used by a particular client depends on the type of database driver used by the client to connect to DB2 For example JTOpen JDBC driver supports both dynamic and extended dynamic SQL while DB2 Universal JDBC driver supports just the dynamic SQL interface This topic will be discussed in details throughout this paper The typical data flow between an AIX client back-end database server job and DB2 SQL runtime is illustrated in Figure 1

1

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 1 - DB2 UDB for iSeries SQL runtime

DB2 SQL Runtime Interfaces Letrsquos briefly discuss the DB2 SQL runtime interfaces

Static SQL

The SQL statements are embedded in the source code of a host application program For example a stored procedure can be written in C++ and contains a number of embedded SQL statements In this case the stored procedure source code has to be processed by an SQL preshycompiler prior to compiling the host application program itself At that time the embedded SQL statements are parsed validated and optimized As a result of this process an access plan gets created for each statement The access plan is a control structure that contains information on the actions necessary to satisfy an SQL request Typically it contains

bull An access method that the optimizer selected for a given statement (for example table scan)

bull Information on associated tables and indexes that is used at runtime to determine if an access plan needs to be rebuilt due to table changes or index changes

bull Any applicable environment information such as jobrsquos code page

The access plan is then permanently stored in the program object and can be reused when the program is executed

In another scenario an embedded SQL application may be executed on a client for example in an AIX partition and access the DB2 UDB for iSeries through DB2 Connect In this case a client-side DB2 SQL precompiler stores the static SQL statements in a bind file The bind file is then

2

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

bound to the back-end database server The bind process creates an SQL package on the DB2 UDB for iSeries The package contains the access plans and other control structures that can be reused when the client program executes

Static SQL is the most efficient way to process SQL requests on an iSeries server

Dynamic SQL Dynamic SQL statements are parsed validated and optimized at the time an SQL application is executed The SQL statements are passed to the database manager in the form of a character string using the SQL statements PREPARE or EXECUTE IMMEDIATE The IBM Toolbox for JavaJTOpen JDBC driver uses this method if Extended Dynamic SQL support is not enabled The Dynamic SQL is also used by the dynamic SQL interfaces such as DB2 Call Level Interface (DB2 CLI) ODBC and JDBC when a client application connects to DB2 UDB for iSeries through DB2 Connect gateway Refer to DB2 Connect data access on page 22 of this paper for more details

Extended Dynamic SQL In Extended Dynamic SQL the SQL statements are dynamic However SQL packages are used to make the implementation of the dynamic SQL statements similar to that of static SQL The SQL statements are parsed validated and optimized and the resulting access plan is permanently stored in a SQL package Note that this process is dynamic and new statements can be added to the SQL package at the run time The IBM Toolbox for JavaJTOpen JDBC driver can take advantage of the Extended Dynamic SQL support

3

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

JDBC Data Access This section provides implementation tips and coding examples that illustrate how to optimize the access to your DB2 UDB for iSeries database from a AIX partition by using various JDBC drivers Currently IBM offers several AIX-enabled JDBC drivers that support DB2 UDB for iSeries

bull Type 4 drivers mdash IBM Toolbox for Java JTOpen and DB2 Universal JDBC Driver bull Type 2 driver mdash DB2 JDBC Type 2 Driver

The IBM Toolbox for Java iSeries driver has been implemented in pure Javatrade and optimized for accessing DB2 UDB for iSeries data It uses native iSeries protocol to communicate with the back-end database server job JTOpen is the open-source version of the IBM Toolbox for Java Licensed Program Product (LPP)

The DB2 Universal JDBC Driver is also a pure Java implementation It is a part of the DB2 UDB for AIX Version 8 product and it uses the Distributed Relational Database Architecture (DRDA) protocol for clientserver communications The driver is compatible with various DB2 UDB server platforms with appropriate DRDA Application Server (AS) level support and prerequisite stored procedures It also supports Type 2 connectivity when accessing DB2 UDB for Linuxreg UNIX and Windowsreg (DB2 UDB for LUW) databases

The traditional DB2 JDBC Type 2 Driver is built on top of DB2 Call Level Interface (CLI) It requires DB2 Connect functionality to access DB2 UDB for iSeries This is a legacy driver and IBM currently recommends that the DB2 Universal JDBC driver is used instead

Initial Configuration Considerations Practical experience shows that the JDBC application performance greatly depends on the programming techniques and the SQL access tuning However significant performance gains can be achieved by simply tweaking the AIX partition environment For example a virtual LAN connection to the back-end database can significantly streamline the data flow

4

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Virtual Versus Physical LAN One of the most significant benefits of installing AIX in an iSeries partition is the ability to utilize virtual LAN and virtual DASD This usually results in reduced hardware costs through improvements in data transfer performance and enhanced disk protection The performance tests conducted by the IBM eServer Solutions Enablement team showed that the Virtual 1Gb LAN delivered a data throughput similar to dedicated 1Gb Ethernet adapters (model 5706) connected via a dedicated Ethernet segment An example configuration is illustrated in Figure 2

Figure 2 VLAN vs 1 Gb Ethernet IOA configuration

Although similar performance can be expected for VLAN and 1Gb Ethernet the VLAN configuration has two advantages over the physical LAN connection

bull No additional communications gear is required bull It is a dedicated point-to-point connection so there is no interference from other devices on

the same network segment

On the other hand certain application scenarios may benefit from a physical LAN adapter dedicated to an AIX partition For instance in a three-tier application architecture clients connect to an application server running in a AIX partition The application server in turn connects to DB2 UDB for iSeries where data is stored and retrieved In this case configuring a separate physical LAN connection in a AIX partition has the following advantages

bull An unnecessary additional hop is eliminated from the network route bull Client-application server traffic does not unnecessarily saturate i5OS communications gear

5

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Tuning DB2 UDB for iSeries Access with IBM Toolbox for Java and JTOpen Driver This section covers JDBC implementation details for a sample Java program called TestJDBC (the source is provided at the end of this paper in Appendix A) The application uses the Java Naming and Directory Interface (JNDI) to obtain a database connection deletes 5000 records generates and inserts 5000 records and finally retrieves the newly inserted records from an SQL table called COFFEES The application executes in an AIX partition and accesses the DB2 UDB for iSeries through the JTOpen (or IBM Toolbox for Java) driver Figure 3 shows the software components involved in the execution of this simple application

Figure 3 JDBC client accessing DB2 UDB for iSeries

Apart from the JTOpen driver which can be downloaded from the IBM Toolbox for Java Web site you need three other JAR files to successfully compile and execute the JDBCTest application in a AIX partition

bull providerutiljar and fscontextjar mdashDownload a simple file system JNDI provider from Sun Microsystems JNDI Web site httpjavasuncomproductsjndidownloadsindexhtml

bull jdbc2_0-stdextjar mdash Copy the javaxsql package from the QIBMUserDataJava400ext IFS directory on the iSeries server

The location of the JAR files needs to be added to the CLASSPATH environment variable For instance the following entry could be added to the AIX profile script

6

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

CLASSPATH=homecodeJTOpenjt400jarCLASSPATH=$CLASSPATHhomecodefscontextproviderutiljarCLASSPATH=$CLASSPATHhomecodefscontextfscontextjarCLASSPATH=$CLASSPATHhomecodeJTOpenjdbc2_0-stdextjarexport CLASSPATH

To compile the source use the following command in the AIX partition

javac TestJDBCjava

Although the TestJDBC application is fairly simple it illustrates several important aspects of efficient JDBC programming for DB2 UDB for iSeries

Connection PoolingA JDBC connection can be obtained through either the DataSource or DriverManager object Either method involves significant overhead A fairly large amount of system resources is required to create and maintain the connection and then release it when it is no longer needed JTOpen allows a developer to establish a pool of database connections that can be shared by multiple client applications Connection pooling can improve the response time because the connection pool manager can locate and use an existing connection When the database request is completed the connection returns to the connection pool for reuse

In the JDBCTest sample JNDI was first used to register a connection pool-capable data source Heres an excerpt from the deployDataSource method of the sample application

Hashtable env = new Hashtable()envput(ContextINITIAL_CONTEXT_FACTORY

comsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env) [1]

Register an AS400JDBCConnectionPoolDataSource objectAS400JDBCConnectionPoolDataSource tkcpds = newAS400JDBCConnectionPoolDataSource() [2]tkcpdssetServerName(serverName) tkcpdssetDatabaseName(databaseName) tkcpdssetUser(userName) tkcpdssetPassword(password) tkcpdssetDescription(Toolkit Connection Pooling DataSourceobject) hellip ctxrebind(jdbcToolkitDataSource tkcpds) [3]

At [1] the initial JNDI context is created

Then at [2] an AS400JDBCConnectionPoolDataSource object is instantiated This is the JTOpen implementation of the javaxsqlConnectionPoolDataSource interface An AS400JDBCConnectionPoolDataSource object supports a number of methods that can be used to set iSeries-specific properties of the underlying DataSource object Some of these properties will be discussed in greater detail in the following sections of this paper

At [3] the data source object is bound to an arbitrary name that will be used in the main application Note that the deployDataSource method needs to be executed just once unless some of the data source properties need to be changed In that case the developer would need to rebind

7

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

The JNDI registered data source is then used in the main application to initialize the connection pool

AS400JDBCConnectionPoolDataSource tkcpds = [1](AS400JDBCConnectionPoolDataSource)ctxlookup(jdbcToolkitDataSource) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPool pool = newAS400JDBCConnectionPool(tkcpds)[2] Adds 1 connection to the pool that can be used by the application(creates the physical database connections based on the datasource)poolfill(1) [3] hellip con = poolgetConnection()[4]

At [1] the JNDI service is used to instantiate the AS400JDBCConnectionPoolDataSource

Then at [2] an AS400JDBCConnectionPool object is created This object is responsible for managing the connection pool

At [3] the connection pool is initialized with one connection

The pool object is used at [4] to obtain a database connection There are several additional things the developer should know about this code snippet

bull The advantage of using JNDI to register the data source object as opposed to just instantiating it in the main method is that in a more realistic scenario the data source would be registered just once at application deployment time Additionally the data source properties do not have to be hard-coded in the main method and can be changed at any time and then rebound without affecting the application

bull The AS400JDBCConnectionPool is a proprietary JTOpen implementation of a connection pool Specifically it does not implement the Referenceable interface and thus cannot be bound through JNDI services

bull The JTOpen AS400JDBCConnectionPoolDataSource does not support statement caching as described in the JDBC 30 specification Statement caching is implemented through SQL packages This feature is covered in the following section

Note The native iSeries JDBC driver supports both connection pooling and statement caching in a JDBC 30 compliant manner

8

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Extended Dynamic SQL and Statement Caching As mentioned the JTOpen data source object supports a number of properties that can be used to fine-tune the database performance In this section properties used to enable extended dynamic SQL support (see DB2 SQL Runtime Interfaces section above) and local statement caching will be discussed

Here is a relevant code excerpt from the deployDataSource method

AS400JDBCConnectionPoolDataSource tkcpds = new AS400JDBCConnectionPoolDataSource() hellip tkcpdssetExtendedDynamic(true)[1]tkcpdssetPackage(JDBCDS) [2]tkcpdssetPackageCache(true) [3]tkcpdssetPackageCriteria(select) [4]

At [1] the extended dynamic SQL support is enabled Note that the default is disabled for JTOpen The extended dynamic SQL functionality is often referred to as SQL package support The SQL packages are server-side repositories for SQL statements Packages contain the internal structures such as parse trees and access plans which are needed to execute SQL statements Because SQL packages are a shared resource the information built when a statement is prepared is available to all the users of the package This saves processing time especially in an environment where many users are using the same or similar statements Also because SQL packages are permanent this information is saved across job initiationtermination and IPLs In fact SQL packages can be saved and restored on other servers

At [2] the SQL package is named Note that the actual package name on the iSeries server is JDBCDSBAA The package name is generated by taking the name specified on the client and appending three letters that are an encoded set of the package configuration attributes By default an SQL package does not contain unparameterized select statements This behavior is overridden at [4] by setting the PackageCriteria property to select

At [3] the local statement cache is enabled A copy of the SQL package is cached on the AIX client This may improve application performance in a way similar to JDBC 30 statement caching Note however that local statement caching is not recommended for large SQL packages The copy of an SQL package is cached when the database connection is obtained This may cause increased network traffic as well as slow down the connection setup time

Reusable Open Data Paths (ODPs)An Open Data Path (ODP) definition is an internal i5OS object that is created when certain SQL statements (such as OPEN INSERT UPDATE and DELETE) are executed for the first time in a given job (or connection) The ODP can be thought of as a runtime implementation of an access plan The access plan created at the optimization time provides a recipe or in other words a sequence of steps necessary to execute the statement The ODP on the other hand provides the executable code for all requested IO operations The process of creating new ODP objects is fairly CPU- and IO-intensive so whenever possible the iSeries DB2 runtime tries to reuse existing ODPs For instance a ResultSetclose() call may close the SQL cursor but leave the ODP available to be used the next time the cursor is opened This can significantly reduce the response time in running SQL statements A reusable OPD usually requires 10 to 20 times less CPU resources than a newly created ODP Therefore it is important that the applications employ programming techniques that allow the DB2 runtime to reuse ODPs

With dynamic programming interfaces such as JDBC the most efficient way to avoid full opens is to employ the so-called prepare once execute many programming paradigm Ideally an SQL statement that is executed more than once should be prepared just once mdashfor example in the class constructor mdash and then reused for the consecutive executions At the prepare time the

9

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 engine stores the prepared statement along with the associated statement name in the QZDASOINIT jobs statement cache On the first execution the ODP created for a given statement is associated with the appropriate entry in the statement cache On consecutive executions the prepared statement and the corresponding ODP can be quickly located in the statement cache and reused The code snippet below illustrates the prepare once execute many programming technique

PreparedStatement pstmt = conprepareStatement(INSERT INTO COFFEES VALUES( ))[1] hellip for (int i = 0 i lt outerNumOfLoops i++)

insertfor (int j = 0 j lt numOfLoops j++)

pstmtsetString(1 Lavaza_ + IntegertoString(j)) hellip pstmtaddBatch()

int [] updateCounts = pstmtexecuteBatch()[2]concommit()

At [1] a PreparedStatement pstmt object is instantiated for a parameterized INSERT statement The statement is prepared just once The PreparedStatement object is then repeatedly used at [2] to perform blocked insert

Block Inserts Occasionally the developer may need to initially populate a table or insert a modified result set into a temporary table The efficiency of the insert operation for a large set of records can be dramatically improved by using the executeBatch method rather than the executeUpdate method The JTOpen driver converts parameterized insert statements in an executeBatch method to a block insert statement This significantly reduces the data flow and system resources required to perform the insert The following code snippet shows how to take advantage of the executeBatch method

10

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

PreparedStatement pstmt =conprepareStatement(INSERT INTO COFFEES VALUES( ))[1]for (int j = 0 j lt numOfLoops j++) pstmtsetString(1 Lavaza_ + IntegertoString(j))pstmtsetInt(2 i)pstmtsetFloat(3 499f)pstmtsetInt(4 0)pstmtsetInt(5 0)pstmtaddBatch() [2]

int [] updateCounts = pstmtexecuteBatch() [3]

At [1] a parameterized insert statement is prepared Note that all columns must be parameterized Otherwise the executeBatch method may throw the SQL0221 Number of rows 1 not valid exception In other words the developer should not mix parameter markers with literals or special registers in the VALUE clause

At [2] the addBatch method is used to add a new record to the client record buffer

At [3] all locally buffered data is sent to the server which in turn performs a block insert

Figure 4 shows the performance data for the executeBatch and executeUpdate methods

Figure 4 executeBatch() versus executeUpdate() performance comparison

11

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

WebSphere Considerations In certain situations an application provider may decide to deploy WebSphere Application Server in an AIX partition rather than natively in i5OS At the same time the application uses DB2 UDB for iSeries as an back-end database server Typically the WebSphere Application Server running in the AIX partition uses the virtual LAN to communicate with DB2 UDB for iSeries The WebSphere applications will access the database through a remote JDBC connection For performance and functionality reasons IBM recommends to utilize in such environments the IBM Toolbox for Java JTOpen driver Most of the tips and techniques described so far in this document hold true for WebSphere applications accessing DB2 UDB for iSeries There are however certain JDBC access aspects that are specific to this multi-tier architecture Letrsquos have a closer look at some of these considerations

Connection Pooling and Statement Caching

WebSphere Application Server provides its own connection pooling and statement caching mechanism that is by default enabled so that WebSphere applications automatically enjoy the performance benefits of these two critical programming techniques See the following link to learn more about the optimal connection pool setting in WebSphere

httppublibboulderibmcomwas40051englishinforzaiz51adminhelpudat_conpoolsethtml

Extended Dynamic SQL

For non-JTA connections WebSphere Application Server uses the comibmas400accessAS400JDBCConnectionPoolDataSource class as the iSeries JDBC provider implementation This is the DataSource implementation that has been used in all previous coding examples As mentioned the class supports a range of iSeries specific properties that can be used to fine tune JDBC performance These properties can be set through the WebSphere Application Server admin console For example herersquos the procedure to enable the extended dynamic SQL support In the WebSphere Application Server admin console navigate to the Data Source configuration dialog by selecting JDBC Providers -gt iSeriesToolbox -gt Data Sources then scroll down to the Additional Properties section Select Custom Properties link The Custom Properties dialog opens Scroll down to find the Extended Dynamic property and select it Change the default value false to true save the new configuration by clicking Apply button This is illustrated in Figure 5

12

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 5 Enabling the extended dynamic SQL through WebSphere Application Server console

The WebSphere Application Server needs to be restarted for the change to take effect The similar procedure can be followed to set other iSeries Data Source properties

Changing the WebSphere Application Server default isolation level

WebSphere Application Server V5 uses the REPEATABLE_READ (RR) isolation level for all implicit (WebSphere Application Server managed) transactions With the RR isolation level the rows selected updated deleted and inserted are locked until the end of the transaction Under certain circumstances this fairly extensive locking policy may cause locking contention especially when a WebSphere application competes for database resources with other applications that run on iSeries server For example a legacy order entry application may share data with the e-business customer care application running in WebSphere The locking contention may sometimes be eliminated by lowering the isolation level used by WebSphere Although the iSeries Data Source supports the custom transactionIsolation property resetting this property on the Data Source object will not change the default isolation level used by WebSphere for the connection objects produced by that Data Source In other words WebSphere will override the Data Source isolation level setting at the time the connection is obtained by a WebSphere application object such as servlet or Enterprise Java Bean (EJB) In order to change the default WebSphere behavior one must use the resource referencing Resource referencing allows a programmer to lookup DataSource or EJB objects using alias names rather than JNDI names Additionally by creating a resource reference a programmer can change certain properties of the underlying object Specifically a DataSource reference can be used to set a different isolation level for the connections produced by this database resource Typically resource references are defined by a programmer in a application development tool such as WebSphere Studio Application Developer The method to specify a DataSource reference differs depending on whether a programmer plans to use the reference in a servlet or in an EJB Letrsquos start with outlining the configuration process for a servlet In WebSphere Studio Application Developer open the deployment descriptor editor for the web project that contains the servlet To do so double click on the webxml file under WEB-INF directory in the web project In the deployment editor dialog select the References tab and then select Resource tab located in the top of the dialog that appears Under Resource References section select the Add button Herersquos an example of a DataSource reference created for iSeries DataSource named TestJDBCDS Note that the reference changes the default isolation level to READ_COMMITTED

13

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 6 Defining a resource reference for a servlet

Once the resource reference has been defined and saved the servlet source code needs to be changed to reflect the fact that a resource reference is used to obtain a DataSource from the JNDI service Herersquos the relevant code snippet try

ctx = new InitialContext() ds = (DataSource)ctxlookup(javacompenvTestJDBCJ2C)

catch (Exception e) eprintStackTrace(out)

Now the ds DataSource object will produce connections that by default run with the isolation level of READ_COMMITTED (RC)

As mentioned the process of defining a resource reference for an EJB differs from the process that is used in the case of a servlet In WebSphere Studio Application Developer open the deployment descriptor editor for the EJB project that contains the EJB To do so double click on the ejb-jarxml file under WEB-INF directory in the project In the deployment editor dialog select the References tab In the references section on the left locate and select the EJB for which the developer wants to change the default isolation level Click the Add button The Add Reference dialog opens Click the Resource Reference radio button and then Next Define the reference following the example shown in Figure 7

14

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 7 Adding a resource reference for an EJB

When you click ldquoFinishrdquo the reference definition is added to the EJB descriptor The new definition needs to be further modified To do so click on the (+) sign next to the EJB in the References list Click the new reference TestJDBCJ2C in this example to open the properties for the reference Change WebSphere Bindings and WebSphere Extensions sections as illustrated in Figure 8

15

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 8 Defining a resource reference for an EJB

Save the modified definition and then change the EJB source code to use the reference rather than directly DataSource

TroubleshootingTroubleshooting a multi-tier application may be a bit tricky because the developer needs to deal with software components that reside in separate partitions Three tools are particularly useful for pinning down the potential problem areas bull Joblog messages for a database server job mdash Provides enough details to isolate DB2 UDB for

iSeries runtime issues bull JDBC trace utility mdash Provides granular information about the data flow between the AIX

application and the iSeries server job bull Database Monitor ndash Provides detailed SQL runtime trace

Job Log MessagesAs mentioned a DB2 client communicates with a corresponding iSeries server job This server job runs the SQL requests on behalf of the client The iSeries database server jobs are called QZDASOINIT and they run in the QUSRWRK subsystem At any given time a large number of database server jobs may be active on the server so the first step is to identify the job that serves the particular client connection The easiest method to accomplish this task is to run the following CL command from the i5OS prompt

WRKOBJLCK OBJ(DB2USER) OBJTYPE(USRPRF)

Here DB2USER is the user profile that is used to connect to the iSeries server Note that a QZDASONIT job is assigned to a client after the connection has been established so the developer needs to set a breakpoint in the client application after the database connection has been established

Once the Work with Object Locks appears key in 5 (Work with Job) next to the only QZDASOINIT job that should be listed This shows the Work with Job dialog Select option 10 to

16

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

display the job log for the database server job Now the job log can be searched for any error messages generated by the DB2 runtime

Sometimes it is also useful to include debug messages in the job log The debug messages are informational messages written to the job log about the implementation of a query They describe query implementation methods such as the use of indexes join order ODP implementation (reusable versus non-reusable) and so on The easiest way to instruct an iSeries server to include the debug messages is to set the ServerTraceCategories property on the data source object

tkcpdssetServerTraceCategories(AS400JDBCDataSourceSERVER_TRACE_DEBUG_SERVER_JOB)

A sample of the job log messages with debug messages enabled is shown below

SET TRANSACTION completeSTATEMENT NAME FOUND QZ868F0A458E13AF8C Starting optimizer debug message for query Arrival sequence access was used for file COFFEESODP created ODP not deleted 5000 rows inserted in COFFEES in DB2USER STATEMENT NAME FOUND QZ868F0A4C144BF12EBlocking used for queryCursor CRSR0001 opened606 rows fetched from cursor CRSR0001 ODP not deleted Cursor CRSR0001 closed

So the job log offers fairly detailed information on how the AIX client requests were implemented by the DB2 runtime

JDBC Trace UtilityThe JTOpen driver provides a tracing utility which can be used to collect detailed client-side traces The JDBC tracing is turned off by default It can be enabled by setting the Trace property to true Heres an example of how to switch on tracing using the setTrace method on the data source object

tkcpdssetTrace(true)

The trace can also be enabled when using the DriverManagergetConnection() method for obtaining a connection to DB2 UDB for iSeries In this case the developer could add the trace property to the connection string This approach is illustrated in the following code snippet

ClassforName(comibmas400accessAS400JDBCDriver) [1] hellip con = DriverManagergetConnection(jdbcas400teraplextrace=true

db2userdb2pwd) [2]

At [1] an instance of the JTOpen JDBC Driver is initiated Then at [2] the driver is used to obtain a connection to the iSeries server Note how the trace property has been added to the database URL See the IBM Toolbox for Java JDBC properties documentation on the iSeries Information Center Web site for a complete list of properties supported by the JTOpen driver

Although the level of details provided by the trace utility is sufficient in most troubleshooting scenarios sometimes the developer may need to collect low-level traces scoped to a certain type

17

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

of information In V5R3 the IBM Toolbox for Java (as well as the latest JTOpen) added a comprehensive detailed trace facility The following is the complete list of detailed trace parameters and their purpose

bull None or ldquordquo ndash This setting disables the detailed trace bull datastream - This category is used by Toolbox classes to log dataflow between the local host

and the remote system It is not intended for use by application classes bull diagnostic - This category is used to log object state information bull error - This category is used to log errors that cause an exception bull information - This category is used to track the flow of control through the code bull warning - This category is used to log errors that are recoverable bull conversion - This category is used by Toolbox classes to log character set conversions

between Unicode and native code pages bull proxy - This category is used by Toolbox classes to log data flow between the client and the

proxy server bull pcml - This category is used to determine how PCML interprets the data that is sent to and

from the server bull jdbc - This category is used to track JDBC calls throughout the program bull thread - This category is used to enable tracing of thread information This is useful when

debugging multi-threaded applications bull all - This category will enable all previous categories

The detailed trace can be enabled when using the DriverManagergetConnection() method for obtaining a connection to DB2 UDB for iSeries In this case the developer could add the toolbox trace property to the connection string This is illustrated in the following code sample

String dbUrl = jdbcas400pwd1toolbox trace=diagnostic con = DriverManagergetConnection(dbUrl dbUser dbPassword)

Note that currently the driverrsquos DataSource interfaces do not allow the developer to directly activate the detailed tracing However they could set the server from the command line at the time the java program is launched The example below shows how the detailed trace properties could be enabled at the command line

java -Dcomibmas400accessTracecategory=diagnostic TestJDBC

The -D switch indicates to the java interpreter that the information following it will be a system property

In case of a WebSphere application the trace property can be set through the admin console In the console select Application Servers-gt server1-gt Process Definition -gt Java Virtual Machine Figure 9 shows how to set the Generic JVM Arguments for an application server instance

18

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 9 Setting JVM arguments to enable detailed Toolbox tracing

Database Monitor

The database monitor is the ultimate tool available on DB2 UDB for iSeries to collect low-level SQL traces It is mainly used to pin down the SQL performance problems Refer to the lsquoUsing iSeries Database Monitor to Identify and Tune SQL Queriesrsquo white paper for a detailed discussion on how to collect and analyze the database monitor traces httpibmcomserversenablesiteeducationiborecordhtmldtmon

IBM DB2 JDBC Universal Driver DB2 JDBC Universal Driver is one of the new features delivered with DB2 UDB Version 8 DB2 JDBC Universal Driver has been designed to eliminate the dependency on DB2 CLI runtime modules as well as to enable direct Type 4 connectivity to DB2 UDB for iSeries and DB2 UDB for zOSreg

The pure-Java (Type 4) remote connectivity is based on the DRDA open distributed protocol for cross-platform access to DB2 DRDA defines the rules the protocols and the semantics for accessing distributed data Applications can access data in a distributed relational environment by using SQL statements The iSeries DRDA application server implementation is based on multiple connection-oriented server jobs running in the QSYSWRK subsystem A DRDA listener job (QRWTLSTN) listens for TCP connect requests on port 446 Once an application requester connects to the listener job the listener wakes up one of the QRWTSRVR prestart jobs and assigns it to a given client connection Any further communication occurs directly between the client application and the QRWTSRVR job These concepts are illustrated in Figure 10

19

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 10 Accessing DB2 UDB for iSeries with DB2 Universal Driver

The DB2 Universal Driver can be loaded in an AIX partition by installing one of the DB2 Connect for AIX products (see the Additional Information section for details) It is also a part of a DB2 Enterprise Server Edition for AIX install Specifically the developer needs three JAR files in a AIX partition to successfully connect to an iSeries server db2jccjar db2jcc_license_cisuzjar and db2jcc_license_cujar The iSeries license is contained in db2jcc_license_cisuzjar Note that this file is not a part of DB2 Client In other words a DB2 Connect license is required to use the driver in production environments The location of the JAR files needs to be added to the CLASSPATH environment variable For instance the following entry could be added to the AIX profile script

CLASSPATH=homedb2inst2sqllibjavadb2jccjarCLASSPATH=$CLASSPATHhomedb2inst2sqllibjavadb2jcc_license_cujarCLASSPATH=$CLASSPATHhomedb2inst2sqllibjavadb2jcc_license_cisuzjarexport CLASSPATH

Java Runtime 131 is a prerequisite

Additionally the developer should install the latest database group PTF (SF99503 for i5OS V5R3) on the iSeries server The Informational APAR ii13348 is keeping track of any fixes relevant to DRDA above and beyond the current database group PTF

Obtaining a Connection to DB2 UDB for iSeries When Type 4 connectivity is used the DB2 Universal Driver connects directly to the DB2 on iSeries through TCPIP Note that this is different from the legacy DB2 Type 2 JDBC driver that requires a DB2 node and remote database configurations on the client accessing iSeries The following code snippet illustrates how to use the DB2 JDBC Universal Driver to obtain a connection to DB2 UDB for iSeries

20

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

try ClassforName(comibmdb2jccDB2Driver) [1] catch(javalangClassNotFoundException e) Systemerrprint(ClassNotFoundException )Systemerrprintln(egetMessage())

try DriverManagergetConnection(jdbcdb2teraplex446TERAPLEX[2]

db2userdb2pwd) hellip catch(SQLException ex) Systemerrprintln(

SQLException + exgetMessage())

At [1] an instance of the DB2 JDBC Universal Driver is instantiated Then at [2] the driver is used to obtain a connection to the iSeries server Note the proper form of the database URL required by the driver

Considerations There are several advantages of DB2 JDBC Universal Driver bull Ease of cross-platform development mdash Consistent coding techniques and consistent error

codes and messages bull Ease of deployment mdash Pure Java (no runtime client required) and a single driver for accessing

DB2 on different platforms

The ease of use comes at a price though The iSeries JTOpen driver is optimized for accessing DB2 UDB for iSeries data and it uses native iSeries protocol to communicate with the back-end database server job This usually results in better performance and more-efficient system resources utilization For instance when using the DB2 JDBC Universal Driver to access an iSeries server the executeBatch method results in a single record insert There are also some restrictions when using DB2 Universal JDBC Driver with Type 4 connectivity

bull Support for distributed transactions (JTA) is not enabled bull Driver built-in connection pooling is not supported

Refer to Java application support in DB2 for more details on DB2 JDBC Universal Driver

21

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 Connect data access This section will explore the most important aspects of DB2 Connect ndash iSeries integration - including configuration tips and coding examples

DB2 Connect provides functionality for accessing data stored in DB2 UDB for iSeries as well as DB2 UDB for zOS and DB2 UDB for OS390reg DB2 Connect offers capabilities to access DB2 family members via several SQL interfaces gateway functions such as connection pooling and federated database functionality Many applications supporting the DB2 family of products leverage DB2 Connect as a key middleware component DB2 Connect is offered as separate AIX license products

Enterprise Edition Application Server Edition

In addition to DB2 Connect there are several other DB2 UDB Version 81 products that are supported on AIX

DB2 Universal Database Enterprise Server Edition DB2 Universal Database Workgroup Server Unlimited Edition DB2 Universal Database Workgroup Server Edition DB2 Universal Database Universal Developers Edition All Clients

The DB2 Connect Enterprise Edition functionality is also contained in DB2 Enterprise Server Edition for AIX

22

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 Connect in a nutshell In the scenario described in this paper the DB2 Connect functions contained in DB2 Enterprise Edition for AIX are utilized DB2 Connect Enterprise Edition provides support for both local and remote DB2 clients This is illustrated in Figure 11 Accessing DB2 UDB for iSeries with DB2 Connect

Figure 11 Accessing DB2 UDB for iSeries with DB2 Connect

DB2 Connect implements the Distributed Relational Database Architecturetrade (DRDAreg) to reduce the cost and complexity of accessing data stored in DB2 UDB for iSeries and other DRDA-compliant database servers DRDA defines the rules the protocols and the semantics for accessing distributed data Applications can access data in a distributed relational environment by using SQL statements In a distributed environment the system running the application and sending the SQL requests across the network is called the application requester (AR) A remote database server that executes SQL requests submitted by an application requester is known as the application server (AS) In the example shown in Figure 11 (above) DB2 Connect plays the role of an application requester while DB2 UDB for iSeries is an application server In this case DB2 Connect communicates with the iSeries database through TCPIP The iSeries DRDA application server implementation is based on multiple connection-oriented server jobs running in the QSYSWRK subsystem A DRDA listener job (QRWTLSTN) listens for TCP connect requests on port 446 Once an application requester connects to the listener job the listener wakes up one of the QRWTSRVR prestart jobs and assigns it to a given client connection Any further communication occurs directly between the client application and the QRWTSRVR job

DB2 Connect supports a wide range of programming interfaces that can be used by AIX applications to access the iSeries database Embedded SQL frac34 Both static and dynamic SQL frac34 Various programming languages (Java CC++ Cobol Fortran REXX)

DB2 Call Level Interface (DB2 CLI) ODBC JDBC frac34 DB2 JDBC Type 2 Driver frac34 DB2 JDBC Type 4 Driver (Universal JDBC Driver)

23

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Note that DB2 Connect supports access to DB2 UDB for iSeries through DB2 JDBC Universal driver However for performance and ease of maintenance reasons IBM recommends that Java applications running in AIX use native iSeries Toolbox JDBC driver See the JDBC Data Access section of this paper (above) for more details On the other hand DB2 Connect is a very efficient and robust connectivity option for AIX applications especially in the environments that are not directly supported by the native iSeries JDBC driver Here are several possible scenarios that would require DB2 Connect installed in a AIX partition

Embedded SQL interface is used to access DB2 CLI or ODBC interface is used to access DB2 A single SQL interface is needed to access multiple back end DB2 server Specific DB2 Connect functionality is needed such as distributed join or connection

pooling

Prerequisites One of the DB2 Connect products or DB2 Enterprise Server Edition for AIX V81 is needed Additionally DB2 Application Development Client is required in the AIX partition to compile DB2 applications

For maximum database server stability the developer should install the latest database group PTF (SF99503 for i5OS V5R3) on the iSeries server The Informational APAR ii13348 is keeping track of any fixes relevant to DRDA above and beyond the current database group PTF

DB2 Connect configuration The following example employs i5OS V5R3 and DB2 UDB Enterprise Server Edition for AIX Version 81 FixPak 6

Configuration steps in the iSeries partition The following process lists the necessary steps to be performed on the iSeries server 1) Verify that the TCPIP stack is working correctly It is assumed that the Virtual LAN is used to

communicate with the i5OS partition First obtain the IP address of the iSeries server or its hostname and ping the iSeries server from the AIX partition

2) Create a relational database (RDB) entry for the iSeries database in the i5OS partition If this has already been created it can be displayed by using the DSPRDBDIRE command Make sure that the RDB entry with a location of LOCAL exists on the iSeries server If it does not exist use the ADDRDBDIRE command to add the appropriate RDB entry For example the following command would add an RDB entry named TPLX For simplicity it is recommended that the TCPIP host name and RDB entry remain the same

ADDRDBDIRE RDB(TPLX) RMTLOCNAME(LOCAL)

3) Create a collection called NULLID This is necessary because the utilities shipped with DB2 Connect and DB2 UDB for AIX store their packages in the NULLID collection Since it does not exist by default in the iSeries server you must create it using the following command

CRTLIB LIB(NULLID)

4) Products that support DRDA automatically perform any necessary code page conversions at the receiving system For this to happen both systems need a translation table from their code page to the partner code page The default Coded Character Set Identifier (CCSID) on the iSeries server is 65535 Since DB2 Connect does not have a translation table for this code page the developer needs to change the individual user profiles to contain a CCSID that can be converted properly by DB2 Connect For US English this is 037 For other languages see DB2 Connect Personal Edition Quick Beginning GC09-2967 The following command changes the CCSID for an individual user profile to 037

24

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

CHGUSRPRF userid CCSID(037)

5) Verify that the default port 446 for DRDA service is being used To do this go to the Configure TCPIP menu (CFGTCP) select Configure Related Tables and then select Work with service table entries Verify that the DRDA service is set for port 446

6) The Distributed Data Management (DDM) job must be started for DRDA to work If you want the DDM job to be automatically started whenever TCPIP is started change the attributes of the DDM job using the CHGDDMTCPA command and set the Autostart server parameter to YES

7) If the system administrator chooses not to autostart the server issue the following command to start the DDM server job

STRTCPSVR SERVER(DDM)

8) Make sure that the user profiles that will be used to connect to the iSeries server exist on the server

25

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Configuration steps in the AIX partition The following steps are required for DB2 Connect to be configured in the AIX partition 1) Sign on to the AIX partition as the DB2 administrator 2) Launch Client Configuration Assistant (db2ca from the command prompt) It is assumed that

VNC or an X-Windows server are being used on the workstation so that the db2ca GUI can be properly rendered

3) From the Selected pull-down menu select the Add Database using Wizard option The Select how you want to setup a connection dialog appears Select Manually configure a connection to a database and click Next This is shown in Figure 12

Figure 12 Accessing DB2 UDB for iSeries with DB2 Connect

26

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

4) On the Select a communications protocol choose TCPIP and select The database physical resides on a host or OS400 system Then select the option Connect directly to the server as shown in Figure 13 Click Next

Figure 13 mdash Selecting communications protocol

27

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

5) On the TCPIP tab fill in the host name of the iSeries server The port number should be 446 This is shown in Figure 14 Click Next

Figure 14 mdash Specifying TCPIP communication parameters

28

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

6) On the Database tab fill in the Relational Database name Use the RDB entry name (specified in step 2) in the Configuration steps in the iSeries partition section as shown in Figure 15 Click Next

Figure 15 mdash Specifying the remote database

7) If you plan to use the ODBC applications select Register this database for ODBC as a system data source on the ODBC tab Click Next

29

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

8) On the Specify the node option dialog select OS400 from the Operating System pull-down menu This is shown in Figure 16 Click Finish

Figure 16 mdash Specifying the node options

30

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

9) The Test Connection dialog appears This allows the developer to verify that the connection works Select both CLI and JDBC check boxes You are also prompted for an iSeries user ID and password as shown in Figure 17

Figure 17 mdash Testing the connection

31

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

10) The successful connection to the database server is confirmed by the message box shown in Figure 18

Figure 18 mdash Test Connection results 11) At this time a newly configured database connection should appear in the main DB2

Configuration Assistant window It is recommended that the DB2 utilities are also bound to the iSeries database The bind process creates the necessary SQL packages on the remote database In the main Configuration Assistant window click the TPLX database entry and then select Selected-gtBindhellip

32

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

12) The Bind dialog appears Click Select All and then enter the connection information as shown in Figure 19 Click Bind The Results message box appears This allows the developer to monitor the progress of the binding process Watch for any error and warning messages

Figure 19 mdash Binding the DB2 utilities This concludes the DB2 Connect configuration steps

33

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Accessing DB2 UDB for iSeries from C embedded SQL

As mentioned earlier DB2 Connect allows developers to compile and run embedded SQL applications that access DB2 UDB for iSeries data This section covers implementation details for a C embedded SQL application called cursorsjsqc (see Appendix B for source code)

Prerequisites An embedded SQL application running in an AIX partition will use DB2 Connect services to access DB2 UDB for iSeries therefore the developer needs to make sure that all components listed in section Prerequisites on page 24 are installed The developer also needs to create a remote database connection as described in the DB2 Connect configuration section of this paper on page 24

Static SQL and SQL packages To successfully run against a DB2 UDB for iSeries database an embedded SQL application needs to be first precompiled and bound to the back-end database This process creates an SQL package on the target iSeries server The SQL package contains the access plan information for the SQL statements executed by the application The internal structure of the package as well as the method how its content is used by the SQL runtime to facilitate the access plan reuse is similar to the Extended Dynamic SQL support covered in detail in the Extended Dynamic SQL and Statement Caching section of this paper (on page 9) There are however important differences between the packages created by the extended dynamic SQL support and the packages created for embedded SQL DRDA client applications The extended dynamic SQL packages support dynamic SQL interfaces such as JDBC

that can submit ad hoc SQL statements at the run time The SQL runtime can prepare the dynamic statements and add them to the package On the other hand the DRDA packages are created at the precompile time and contain static SQL In order to add new statements to the package the application needs to be precompiled and rebound again

The extended dynamic SQL package can dynamically grow up to 500MB by allocating new space as required The DRDA packages since they are created at the precompile time have a fix size and do not grow over their life time

Simple embedded SQL application The application is based on a source code provided in the DB2 UDB samples directory typically to be found at homedb2inst1sqllibsamples The cursorsjsqc performs a join between STAFF and ORG tables located in DB2USER schema (library) on the TPLX database server (the source is provided at the end of this paper in Appendix B) The join statement retrieves the DEPTNAME column from ORG NAME column from STAFF and calculates the total compensation for an employee by adding SALARY and COMM columns in STAFF The results are sorted by department name and total compensation Here is the SELECT statement used by the application

SELECT deptname name salary + IFNULL(comm0) as compensationFROM org o staff sWHERE odeptnumb = sdeptORDER BY deptname compensation DESC

The application iterates through the selected records and prints out the data to the standard output device The sample DB2USER schema was created with the following SQL statements

db2 CONNECT TO tplx USER db2user USING mypassworddb2 CALL QSYSCREATE_SQL_SAMPLE(DB2USER)

34

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Make sure that the AIX partition is logged into with the DB2 admin user profile If the defaults were selected at the DB2 installation time this profile name is db2inst1 It is also assumed that DB2USER user exists on the iSeries server and that it has appropriate authority

There are several steps that are required to create an executable for the cursorsjsqc source code First the DB2 PRECOMPILE utility needs to be called The utility creates a bind file that is used to bind the required SQL package to the TPLX database It also converts embedded SQL statements into DB2 run-time API calls and produces a pure C source file that can be processed by an AIX C compiler

db2 CONNECT TO tplx USER db2user USING mypassworddb2 prep cursorsjsqc bindfile

Note that the connect statement is required only if the developer is not already connected to the database on an iSeries server Watch for any error or warning messages returned by the DB2 prep utility The prepare step should produce cursorsjbnd and cursorsjc files in the current directory Now the developer can invoke the bind utility to prepare the statements contained in the bind file and create the package on the target iSeries database server

db2 bind cursorsjbnd

It is assumed that Visual C++ 60 is installed and configured in the AIX partition Refer to the ldquoDeveloping and Porting C and C++ Applications on AIXrdquo redbook for more information on how to use the Visual C++ compiler httpibmcomredbooksabstractssg245674htmlOpen

Use the following commands to compile the C source generated by the precompile utility

xlc -I$INSTHOMEsqllibinclude ndashc cursorsjcxlc ndasho cursorsj cursorsjo -L$INSTHOMEsqlliblib ndashldb2

Run the program from the AIX prompt

cursorsj db2user mypassword

Distributed Join DB2 UDB Version 8 provides core federated server functionality A federated system consists of a DB2 UDB instance that operates as a federated server a database that acts as the federated database one or more data sources and clients (users and applications) that access the database and data sources Federated server permits objects stored in multiple databases to be accessed together in the same query For example a query can refer to a table that resides in DB2 UDB for iSeries and join it to a table stored in DB2 UDB for AIX Such a query would constitute so called distributed join The support for DB2 UDB for iSeries as a federated data source is provided by core federated server functionality directly implemented in DB2 UDB Enterprise Server Edition and DB2 UDB Connect Enterprise Edition All other DB2 UDB family members are also supported directly by core DB2 UDB federated server An additional software product DB2 Information Integratortrade is required to access non-DB2 UDB databases such as Oracle Sybase or Microsoftreg SQL Server Consult the following white papers for a detailed discussion on DB2 federated server support Heterogeneous data access for iSeries applications Version 2 httpibmcomserversenablesiteeducationiborecordhtmlhetdata Fundamentals of IBM DB2 Federated Server and Relational Connect httpwww7bsoftwareibmcomdmddlibrarytecharticle0206purnell0206purnellhtml

35

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Distributed Join Example In this section the steps that are required to configure DB2 UDB for iSeries as a federated data source will be illustrated Then the cursorsjsqc program will be ldquotweakedrdquo so that it executes a distributed join query that accesses data stored on an iSeries server and in the local DB2 UDB for AIX database It is assumed that the developer is familiar with the DB2 federated server concepts

Note Run the following commands from the Command Line Processor prompt Load the utility by executing the db2 command at the AIX prompt 1) First the local DB2 UDB for AIX instance needs to be enabled as a DB2 federated server

This is done by setting the database manager configuration parameter FEDERATED to YES

db2=gt update dbm cfg using FEDERATED YES

The database instance needs to be restarted for the change to take effect

NOTE A federated database is a regular database in a DB2 UDB instance that has the FEDERATED parameter enabled Therefore in this example the SAMPLE database that was created earlier is used as the federated database A new database can also be created using the CREATE DATABASE command

2) Connect to the federated database

db2=gt connect to sample

3) Use the CREATE WRAPPER statement to register a wrapper for the iSeries data source Wrappers are library routines that are used by the federated server to perform operations such as connecting to a data source and retrieving data from it The default wrapper name for DB2 UDB for iSeries is DRDA Here is the command to register the DRDA wrapper

db2=gt create wrapper drda

4) Use the CREATE SERVER statement to register a data source as a server within the federated database The server definition specifies the type and version of the data source and the wrapper used for communications with this data source For the DB2 UDB for iSeries data source the node and the database names are also needed The node and database name parameters have been configured for our TPLX database in the Configuration steps in the AIX partition section (on page 24) Use the following DB2 UDB command to lookup these parameter on the federated server

db2=gt list database directory

In this case the command produced the following output

Database alias = TPLX Database name = DCSE99E1 Node name = NDE9BF76 Database release level = a00 Comment = Directory entry type = Remote Authentication = SERVER Catalog database partition number = -1

36

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Note that the node name is set to NDE9BF76 The name was generated by the Configuration Administrator utility (db2ca)

Here is the command to register the TPLX database as a federated server

db2=gt create server tplx type db2400 version 530 wrapperdrda authorization db2user password mypassword options(nodeNDE9BF76 dbname TPLX)

The command is quite complex so make sure that the syntax is correct

5) Define the user mappings that instructs the federated server what user ID and password should be used when connecting to the iSeries data source

db2=gt create user mapping for user server tplxoptions(remote_authid db2user remote_password mypassword)

Specify the nickname for the iSeries table or view A nickname is an identifier that is used by the federated server to reference an object located at the data source The following command creates a nickname for the STAFF table located in the DB2USER schema on the TPLX database

db2=gt create nickname tplx_staff for tplxdb2userstaff

6) Test the distributed join query

db2=gt SELECT deptname name salary + COALESCE(comm0) ascompensation FROM org o tplx_staff s WHERE odeptnumb =sdept ORDER BY deptname compensation DESC

Note that the native iSeries function IFNULL has been substituted with an equivalent DB2 UDB function COALESCE COALESCE is also supported on iSeries servers For better portability IBM encourages the use of COALESCE rather than IFNULL Note also that the query runs on the federated server rather than on TPLX It accesses the ORG table in the local DB2 UDB for AIX SAMPLE database and the STAFF table that resides in TPLX The federated server performs the necessary distributed join

7) Modify the cursorsjsqc so that it executes a distributed join There are two source code modifications - Change the CONNECT TO statements Now the application needs to connect to the

federated database SAMPLE rather than to TPLX

EXEC SQL CONNECT TO SAMPLEEXEC SQL CONNECT TO SAMPLE USER userid USING passwd

- Modify the select statement so that it performs a distributed join Use the statement (shown in step 6) above Save the new source version as cursordjsqc

- Prepare bind and compile the distributed join version of the program as described in the Simple C embedded SQL application section (on page 34)

db2 prep cursordjsqc bindfiledb2 bind cursordjbndxlc -I$INSTHOMEsqllibinclude ndashc cursordjcxlc ndasho cursordj cursordjo -L$INSTHOMEsqlliblib ndashldb2

37

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

- Run the program from the AIX prompt

cursordj

Connection Pooling and Connection ConcentratorA modern Web-based application typically executes a large number of short-lived transactions Executing a transaction in this environment means establishing a database connection executing a few SQL statements and terminating this connection Creating connections to the database server is a very costly process To reduce the unnecessary workload DB2 Connect implements connection pooling and connection concentrator Connection pooling mechanism allows DB2 Connect to reuse an existing connection infrastructure for subsequent connection requests The connection concentrator is an advanced technology that allows DB2 Connect to serve a potentially very large number of clients with a limited number of database connections This is accomplished by decoupling clients from a particular database connection

Note that currently neither connection pooling nor connection concentrator support DB2 UDB for iSeries Therefore for performance reasons the author strongly recommends that the application server that obtains and drops connections very frequently implements its own database connection pooling mechanism that would assign an existing pooled database connection to a new AIX process or thread

TroubleshootingTroubleshooting a multi-tier application may be a bit tricky because the developer needs to deal with software components that reside in separate partitions The authorrsquos experience shows that two tools are particularly useful for pinning down the potential problem areas The joblog messages for a database server job usually provide enough details to isolate DB2

UDB for iSeries runtime issues The DRDA trace utility provides granular information about the data flow between the AIX

application and the iSeries server job

38

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Job Log MessagesAs mentioned earlier a DB2 client communicates with a corresponding iSeries server job This server job runs the SQL requests on behalf of the client More precisely when a DB2 client submits an SQL statement the statement is passed to a server job that in turn calls the DB2 runtime to execute the statement The results are then reformatted and marshaled to the client The iSeries DRDA server jobs are called QRWTSRVR and they run in the QUSRWRK subsystem At any given time there may be a large number of DRDA server jobs active on the system so the first step is to identify the job that serves the particular client connection The easiest method to accomplish this task is to run the following CL command from the i5OS prompt

WRKOBJLCK OBJ(DB2USER) OBJTYPE(USRPRF)

Here DB2USER is the user profile that is used to connect to the iSeries server Note that a QRWTSRVR job is assigned to a client after the connection has been established so the developer needs to set a breakpoint in the client application below the CONNECT TO statement

Once the Work with Object Locks appears key in 5 (Work with Job) next to the only QRWTSRVR job that should be listed This shows the Work with Job dialog Select option 10 to display the job log for the database server job Now the developer can search the job log for any error messages generated by the DB2 runtime

Sometimes it is also useful to include debug messages in the job log The debug messages are informational messages written to the job log about the implementation of a query They describe query implementation methods such as use of indexes join order ODP implementation (reusable versus non-reusable) and so on The easiest way to instruct the iSeries server to include the debug messages is to call the following stored procedure just after the connection to the iSeries server is established

EXEC SQL call qsysqcmdexc(STRDBGUPDPROD(YES)000000002000000)

A sample of the job log messages with debug messages enabled is shown below in Figure 20

Arrival sequence access was used for file STAFFAccess path suggestion for file STAFFQuery options used to build the OS400 query access plan Ending debug message for query ODP created Blocking used for queryCursor SQLCUR201 opened1 rows fetched from cursor SQLCUR201Row not found for SQLCUR201ODP deleted Cursor SQLCUR201 closedDESCRIBE of prepared statement STMT0201 completed

Figure 20 mdash Joblog with debug messages enabled

So the job log offers fairly detailed information on how the AIX client requests were implemented by the DB2 runtime

39

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 DRDA trace utilityThe DB2 DRDA trace utility (db2drdat) provides detailed information about the data streams exchanged between DB2 Connect and target database server The output file produced by the utility contains send and receive communications buffers TCPIP error messages and SQL Communications Area (SQLCA) information Please refer to lsquoDB2 Connect Userrsquos Guidersquo manual for in-depth discussion of the DRDA trace utility

Accessing DB2 UDB for iSeries from CLI DB2 Call Level Interface (CLI ) is based on the Microsoft Open Database Connectivity (ODBC) specification and the ISO CLI standard The DB2 CLI interface gained popularity among DB2 application providers because the developer can build an ODBC application by simply linking the application with libdb2 library on a UNIX server In other words the developer directly utilizes the DB2 ODBC driver services without a need for an ODBC driver manager Additionally in contrast to embedded SQL the developer does not need to precompile or bind DB2 CLI applications because they use packages provided with DB2 UDB The developer simply compiles and links the application

Prerequisites A DB2 CLI application running in an AIX partition will use DB2 Connect services to access DB2 UDB for iSeries therefore make sure that all components listed in Prerequisites section of this paper on page 24 are installed The developer also needs to create a remote database connection as described in the DB2 Connect configuration section of this paper on page 24

Dynamic SQL and Access Plan Caching A DB2 CLI client application uses the dynamic SQL interface and does not have the capability to utilize the extended dynamic SQL support Therefore it runs lsquopurersquo dynamic SQL statements That does not mean however that the process of parsing validating and optimizing will be repeated for every execution of a given dynamic SQL statement

The DB2 UDB for iSeries database implements an internal object called System-Wide SQL Statement Cache (SWSC) The SWSC can improve the performance of programs using dynamic SQL statements by caching the access plans in a system-wide cache When a dynamic SQL statement is submitted the SQL runtime searches the SWSC to see if this statement has been previously executed If so then DB2 retrieves and reuses the key information associated with the cached statement and thereby the processing time and the resources utilization can be significantly reduced

Simple DB2 CLI C++ ApplicationThis section covers DB2 CLI implementation details for a sample C++ program called testclicpp (the source is provided at the end of this paper in Appendix C) To compile the source with Visual C++ complier use the following command in the AIX partition

xlC ndashI$INSTHOMEsqllibinclude ndashc testclicppxlC ndasho testcli testclio ndashL$INSTHOMEsqlliblib ndashldb2

The application performs a join between STAFF and ORG tables located in DB2USER schema (library) The join statement retrieves the DEPTNAME column from ORG NAME and JOB columns from STAFF and calculates the total compensation for an employee by adding SALARY and COMM columns in STAFF The results are sorted by total compensation The selection criterion is based on the current value of the department name parameter Here is the SELECT statement used by testcli

40

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

select name job salary + coalesce(comm0) as compensationfrom org o staff swhere odeptnumb = sdeptand deptname = order by compensation desc

Figure 21 shows the software components involved in the execution of this sample application

Figure 21 How a DB2 CLI client accesses DB2 UDB on an iSeries server

Although the testcli application is fairly simple it covers some important aspects of efficient CLI programming for DB2 UDB for iSeries

Reusable Open Data Paths (ODPs)An Open Data Path (ODP) definition is an internal i5OS object that is created when certain SQL statements (such as OPEN INSERT UPDATE and DELETE) are executed for the first time in a given job (or connection) The ODP can be thought of as a runtime implementation of an access plan The access plan created at the optimization time provides a recipe or in other words a sequence of steps necessary to execute the statement The ODP on the other hand provides the executable code for all requested IO operations The process of creating new ODP objects is fairly CPU- and IO-intensive so whenever possible the iSeries DB2 runtime tries to reuse existing ODPs For instance a SQLCloseCursor() API call may close the SQL cursor but leave the ODP available to be used the next time the cursor is opened This can significantly reduce the processing and response time in running SQL statements A reusable OPD usually requires 10 to 20 times less CPU resources than a newly created ODP Therefore it is important that the applications employ programming techniques that allow the DB2 runtime to reuse ODPs

With dynamic interfaces such as CLI full opens are avoided by using a prepare once execute many programming paradigm It means that when an SQL statement is going to be executed more than once you should prepare the statement just once and then reuse the prepared

41

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

statements for consecutive executions Although DB2 UDB does try to convert literals to parameter markers so that similar statements can be reused it is a better programming practice to explicitly implement parameter markers That way the chances for reusable ODPs are quite significantly improved The code snippet in Figure 22 illustrates how to implement the prepare once execute many programming technique

Define A SELECT SQL Statementstrcpy((char ) SQLStmt select name job salary + ifnull(comm0) ascompensation )ptr = strcat( (char ) SQLStmt from org o staff s )ptr = strcat( (char ) SQLStmt where odeptnumb = sdept)ptr = strcat( (char ) SQLStmt and deptname = )ptr = strcat( (char ) SQLStmt order by compensation desc) [1]

Prepare The SQL Statementrc = SQLPrepare(ExampleStmtHandle SQLStmt SQL_NTS) [2]

Bind The Columns In The Result Data Set Returned To Application Variablesrc = SQLBindCol(ExampleStmtHandle 1 SQL_C_CHAR (SQLPOINTER)

ExampleName sizeof(ExampleName) NULL)rc = SQLBindCol(ExampleStmtHandle 2 SQL_C_CHAR (SQLPOINTER)

ExampleJob sizeof(ExampleJob) NULL)rc = SQLBindCol(ExampleStmtHandle 3 SQL_C_DOUBLE (SQLPOINTER)

ampExampleComp sizeof(ExampleComp) NULL)

for (int i = 0 i lt LOOPS i++)rc=SQLBindParameter(ExampleStmtHandle

1SQL_PARAM_INPUTSQL_C_CHARSQL_CHAR10(SQLPOINTER) currentDepartment[i8]0NULL) [3]

rc = SQLExecute(ExampleStmtHandle) [4]cout ltlt endl ltlt Current Dept ltlt currentDepartment[i8] ltlt endl Display The Results Of The SQL QueryExampleShowResults()

Figure 22 Use the prepare once execute many programming technique

The error-handling code has been removed for clarity At [1] the statement text is assigned to a variable Note that a parameter marker is used in the WHERE clause The statement is then prepared just once at [2] The current value of the parameter is bound to the prepared statement at [3] The prepared statement is executed at [4] Steps [3] and [4] are repeatedly executed in a for loop

Techniques to Further Improve DB2 CLI Performance Thus far this paper has discussed the techniques used by a sample application to tune the CLI performance However depending on the application architecture other methods of improving CLI performance may be considered

Connection PoolingCurrently the CLI application connecting through DB2 Connect to DB2 UDB for iSeries does not take advantage of the connection pooling mechanism implemented by DB2 Connect Therefore for performance reasons the author strongly recommends that the application server that obtains and drops connections very frequently implements its own database connection pooling mechanism that would assign an existing pooled database connection to a new AIX process or thread

42

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Blocking

For queries which result in returning large data blocks from the iSeries server (usually 32K of data and above) ensure that the database manager configuration parameter RQRIOBLK is set to 32767 This can be done using the Command Line Processor (CLP) as follows

db2 update database manager configuration using RQRIOBLK 32767

TroubleshootingThe experience of the author shows that two tools are particularly useful for pinning down the potential problem areas bull Joblog messages for a database server job usually provides enough details to isolate DB2

runtime issues bull CLI trace utility provides granular information about the data flow between the AIX application

and the database server job

Job Log MessagesThe process of finding and analyzing the job log for a DB2 CLI connection is identical to the process outlined for an embedded SQL application in the Job Log Message section of this paper on page 39

CLI Trace The DB2 CLIODBCJDBC trace utility provides very detailed information about the data streams exchanged between DB2 Connect and target database server Refer to the DB2 Information Center for more information on how to set up and analyze the CLI traces httppublibboulderibmcominfocenterdb2v8luwindexjsptopic=comibmdb2udbdocadc000 7959htm

43

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Trademarks

IBM eServer iSeries AIX AIX 5L i5OS WebSphere DB2 DB2 Universal Database DB2 Connect OS400 zOS OS390 Distributed Relational Database Architecture DRDA and DB2 Information Integration are trademarks or registered trademarks of International Business Machines Corporation in the United States and other countries

Java and all Java-based trademarks are trademarks of Sun Microsystems Inc in the United States other countries or both

Linux is a registered trademark of Linus Torvalds in the United States other countries or both

UNIX is a registered trademark of The Open Group in the United States and other countries

Microsoft and Windows are registered trademarks of Microsoft Corporation in the United States andor other countries

All other registered trademarks and trademarks are properties of their respective owners

IBM makes no commitment to make available any products referred to herein

References in this publication to IBM products or services do not imply that IBM intends to make them available in every country in which IBM operates

Additional Information ITSO offers a Redbook that can be helpful to those who want to learn more about i5OS AIX integration

bull AIX Integration with I5OS on the IBM eServer iSeries Server (SG24-6551)

Jarek Miszczyk is the Senior Software Engineer IBM eServer Solutions Enablement IBM Rochester

[Portions of this white paper reprinted with permission from MC Mag Online published by MC Press LLP httpwwwmcpressonlinecom]

Acknowledgments The author would like to thank the following people for their advice contributions and support on this paper

Bob Bittner IBM Rochester Jon Rush IBM Rochester Prasad Vallurupalli IBM Rochester Neil Willis IBM Rochester

44

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix A Source Listing of TestJDBCjava

package comibmiseriespwdimport javasqlimport javaxnamingimport javautilHashtableimport javautilimport javaxsqlimport comibmas400access

public class TestJDBC public static void main(javalangString[] args)

throws Exception

int numOfLoops = 5000int outerNumOfLoops = 5boolean firstExec = trueConnection conStatement sPreparedStatement psPreparedStatement pstmtdelCallableStatement cstmPreparedStatement pstmtHashtable env = new Hashtable()

envput(ContextINITIAL_CONTEXT_FACTORYcomsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env)Systemoutprintln(Deploying connection pooling data source)deployDataSource() Do the work with connection pooling onlyAS400JDBCConnectionPoolDataSource tkcpds =

(AS400JDBCConnectionPoolDataSource)ctxlookup(jdbcToolkitDataSource) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPool pool = new AS400JDBCConnectionPool(tkcpds) Adds 1 connection to the pool that can be used by theapplication (creates the physical database connections based onthe data source)poolfill(1)Systemoutprintln(nStart timing Toolkit connection pooling)long startTime = SystemcurrentTimeMillis()

for (int i = 0 i lt outerNumOfLoops i++) con = poolgetConnection()consetAutoCommit(false) deleteif ( i == 0)

long startDelete = SystemcurrentTimeMillis()cstm = cstm = conprepareCall(

CALL qsysqcmdexc(CLRPFM FILE(DB2USERCOFFEES) + 000000002800000))

cstmexecuteUpdate()cstmclose()long endDelete = SystemcurrentTimeMillis()Systemoutprintln(Delete all records +

(endDelete - startDelete) + ms elapsed)

45

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

String sqlinstrlong startInsert = SystemcurrentTimeMillis() insert

pstmt =conprepareStatement(INSERT INTO COFFEES VALUES( ))for (int j = 0 j lt numOfLoops j++) pstmtsetString(1 Kona_ + IntegertoString(i))pstmtsetInt(2 150)pstmtsetFloat(3 999f)pstmtsetInt(4 0)pstmtsetInt(5 0)pstmtaddBatch()int [] updateCounts = pstmtexecuteBatch()concommit()pstmtclose()long endInsert = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for + numOfLoops + inserts

+ (endInsert - startInsert)) selectlong startSelect = SystemcurrentTimeMillis()ps = conprepareStatement(SELECT FROM COFFEES)ResultSet rs = psexecuteQuery()rsnext()rsclose()concommit()psclose()long endSelect = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for select +

(endSelect - startSelect))consetAutoCommit(true)conclose()long endTime = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for + outerNumOfLoops +

loops + (endTime - startTime))Systemexit(0)

private static void deployDataSource()throws ExceptionString serverName = teraplex String databaseName = TERAPLEX String userName = db2user String password = db2pwd

Establish a JNDI context and bind the connection pool data sourceHashtable env = new Hashtable()envput(ContextINITIAL_CONTEXT_FACTORY

comsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPoolDataSource tkcpds = new

AS400JDBCConnectionPoolDataSource()tkcpdssetServerName(serverName) tkcpdssetDatabaseName(databaseName) tkcpdssetUser(userName) tkcpdssetPassword(password) tkcpdssetDescription(Toolkit Connection Pooling DataSource)tkcpdssetSavePasswordWhenSerialized(true)tkcpdssetExtendedDynamic(true)

46

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

tkcpdssetPackage(JDBCDS)tkcpdssetPackageCache(true)tkcpdssetPackageCriteria(select)enable the following properties as requiredcpdssetTrace(true)tkcpdssetServerTraceCategories( AS400JDBCDataSourceSERVER_TRACE_DEBUG_SERVER_JOB)

ctxrebind(jdbcToolkitDataSource tkcpds)

47

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix B mdash Source Listing of cursorsjsqc

Source File Name = cursorsjsqc Licensed Materials - Property of IBM (C) COPYRIGHT International Business Machines Corp 1995 2000 2004 All Rights Reserved US Government Users Restricted Rights - Use duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp PURPOSE This sample program demonstrates the use of a CURSOR The CURSOR is processed using static SQL EXTERNAL DEPENDENCIES - Ensure existence of database for precompile purposes - Precompile with the SQL precompiler (PREP in DB2) - Bind to a database (BIND in DB2) - Compile and link with the IBM Cset++ compiler (AIX and OS2) or the Microsoft Visual C++ compiler (Windows) or the compiler supported on your platform For more information about these samples see the README file For more information on programming in C see the - Programming in C and C++ section of the Application Development Guide For more information on building C applications see the - Building C Applications section of the Application Building Guide For more information on the SQL language see the SQL Reference

include ltstdiohgt include ltstdlibhgt include ltstringhgtinclude ltsqlhgtinclude ltsqlenvhgtinclude ltsqldahgtinclude ltsqlcahgt

int SqlInfoPrint( char struct sqlca int char )void TransRollback( void)

define EMB_SQL_CHECK( MSG_STR ) rc = SqlInfoPrint( MSG_STR ampsqlca __LINE__ __FILE__) if ( rc = 0 ) TransRollback( )

return 1

EXEC SQL INCLUDE SQLCA

int main(int argc char argv[])

EXEC SQL BEGIN DECLARE SECTIONchar dname[15]

48

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

char pname[10]double compchar userid[9]char passwd[19]

EXEC SQL END DECLARE SECTION

int rc = 0printf( Sample C program CURSORSJ n )if (argc == 1)

EXEC SQL CONNECT TO TPLXEMB_SQL_CHECK(CONNECT TO TPLX)

else if (argc == 3)

strcpy (userid argv[1])strcpy (passwd argv[2])EXEC SQL CONNECT TO TPLX USER userid USING passwdEMB_SQL_CHECK(CONNECT TO TPLX)

else

printf (nUSAGE cursor [userid passwd]nn)return 1

endif

EXEC SQL DECLARE c1 CURSOR FORselect deptname name salary + ifnull(comm0) as compensationfrom org o staff swhere odeptnumb = sdeptorder by deptname compensation desc

EXEC SQL OPEN c1EMB_SQL_CHECK(OPEN CURSOR)

printf(DEPARTMENT NAME COMPENSn)printf(-----------------------------------n)do

EXEC SQL FETCH c1 INTO dname pname compif (SQLCODE = 0) breakprintf( -1515s -1010s 72fn dname pname comp )

while ( 1 )

EXEC SQL CLOSE c1EMB_SQL_CHECK(CLOSE CURSOR)

EXEC SQL CONNECT RESETEMB_SQL_CHECK(CONNECT RESET)

exit(0)

end of program CURSORSJSQC

int SqlInfoPrint( char appMsgstruct sqlca pSqlcaint linechar file )

int rc = 0char sqlInfo[1024]char sqlInfoToken[1024]char sqlstateMsg[1024]char errorMsg[1024]

if (pSqlca-gtsqlcode = 0 ampamp pSqlca-gtsqlcode = 100)

49

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

strcpy(sqlInfo )if( pSqlca-gtsqlcode lt 0) sprintf( sqlInfoToken n---- error report ----n)

strcat( sqlInfo sqlInfoToken)else sprintf( sqlInfoToken n---- warning report ----n)

strcat( sqlInfo sqlInfoToken) endif

sprintf( sqlInfoToken app message = sn appMsg)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken line = dn line)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken file = sn file)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken SQLCODE = ldn pSqlca-gtsqlcode)strcat( sqlInfo sqlInfoToken)

get error message rc = sqlaintp( errorMsg 1024 80 pSqlca) return code is the length of the errorMsg string if( rc gt 0) sprintf( sqlInfoToken sn errorMsg)

strcat( sqlInfo sqlInfoToken)

get SQLSTATE message rc = sqlogstt( sqlstateMsg 1024 80 pSqlca-gtsqlstate)if (rc == 0) sprintf( sqlInfoToken sn sqlstateMsg)

strcat( sqlInfo sqlInfoToken)

if( pSqlca-gtsqlcode lt 0) sprintf( sqlInfoToken --- end error report ---n)

strcat( sqlInfo sqlInfoToken)printf(s sqlInfo)return 1

else sprintf( sqlInfoToken --- end warning report ---n)

strcat( sqlInfo sqlInfoToken)printf(s sqlInfo)return 0

endif endif

return 0

void TransRollback( ) struct sqlca sqlca

int rc = 0 rollback the transaction printf( nRolling back the transaction n)

EXEC SQL ROLLBACKrc = SqlInfoPrint( ROLLBACK ampsqlca __LINE__ __FILE__)if( rc == 0) printf( The transaction was rolled backn)

50

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

51

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix C mdash Source Listing of testclicpp

Include The Appropriate Header Filesinclude ltsqlclihgtinclude ltsqlcli1hgtinclude ltsqlutilhgtinclude ltsqlenvhgtinclude ltstdiohgt include ltiostreamgt include ltlocalehgt include ltstringhgtdefine SQL_SQLSTATE_SIZE 5define LOOPS 8

using namespace std

Define The CLI_Class Classclass CLI_Class

Attributespublic

SQLHANDLE EnvHandleSQLHANDLE ConHandleSQLHANDLE StmtHandleSQLRETURN rcSQLCHAR Job[6]SQLCHAR Name[10]SQLDOUBLE Comp

Operationspublic

CLI_Class()~CLI_Class()SQLRETURN ShowResults()

Constructor Destructor

SQLRETURN printError( SQLHDBC SQLHSTMT)

Define The Class ConstructorCLI_ClassCLI_Class()

setlocale( LC_ALL )

Initialize The Return Code Variablerc = SQL_SUCCESS

Allocate An Environment Handlerc = SQLAllocHandle(SQL_HANDLE_ENV SQL_NULL_HANDLE ampEnvHandle)

Allocate A Connection Handleif (rc == SQL_SUCCESS)

rc = SQLAllocHandle(SQL_HANDLE_DBC EnvHandle ampConHandle)

Define The Class DestructorCLI_Class~CLI_Class()

Free The Connection Handleif (ConHandle = NULL)

SQLFreeHandle(SQL_HANDLE_DBC ConHandle)

Free The Environment Handle

52

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

if (EnvHandle = NULL)SQLFreeHandle(SQL_HANDLE_ENV EnvHandle)

Define The ShowResults() Member FunctionSQLRETURN CLI_ClassShowResults(void)

While There Are Records In The Result Data Set Generated Retrieve And Display Themcout ltlt Name Job Compensation ltlt endlcout ltlt --------- ------ ------------ ltlt endlcoutsetf(iosleft)coutprecision(2)coutsetf(iosfixed)while (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)

rc = SQLFetch(StmtHandle)if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)

coutwidth(15)cout ltlt Name

coutwidth(10)cout ltlt Job

coutwidth(7)cout ltlt Comp ltltendl

if(rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO ampamp rc = SQL_NO_DATA)printError(ConHandle StmtHandle)

else

rc = 0SQLCloseCursor(StmtHandle)

Return The ODBC API Return Code To The Calling Functionreturn(rc)

SQLRETURN CLI_ClassprintError (SQLHDBC hdbc

SQLHSTMT hstmt)

SQLCHAR buffer[SQL_MAX_MESSAGE_LENGTH + 1]SQLCHAR sqlstate[SQL_SQLSTATE_SIZE + 1]SQLINTEGER sqlcodeSQLSMALLINT lengthSQLRETURN rcwhile ((rc = SQLError(SQL_NULL_HENV hdbc hstmt

sqlstateampsqlcodebufferSQL_MAX_MESSAGE_LENGTH + 1amplength)) == SQL_SUCCESS || rc ==

SQL_SUCCESS_WITH_INFO)

cout ltlt SQLSTATE ltlt sqlstate ltlt endlcout ltlt SQLCODE ltlt sqlcode ltlt endlcout ltlt Error msg ltlt buffer ltlt endl

53

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

cout ltlt----------------------------- ltlt endl ltlt endl

return(SQL_ERROR)

----------------------------------------------------------------- The Main Function -----------------------------------------------------------------int main()

Declare The Local Memory Variables

(SQLCHAR ) db2user SQL_NTS (SQLCHAR ) test26t SQL_NTS)

SQLRETURNSQLCHARSQLCHARSQLCHARchar

SQLCHAR

rc = SQL_SUCCESSDBName[10] = TPLXSQLStmt[255]c[10]ptrcurrentDepartment[8][15] = Head Office

New England Mid Atlantic South Atlantic Great Lakes PlainsPacificMountain

Create An Instance Of The CLI_Class ClassCLI_Class Example

Connect To iSeries Database if (ExampleConHandle = NULL)

rc = SQLConnect(ExampleConHandle DBName SQL_NTS

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)ExampleprintError(ExampleConHandle SQL_NULL_HSTMT)

return(rc)

cout ltlt Successfully connected to ltlt DBName ltlt ltlt endlrc = SQLSetConnectAttr(ExampleConHandle SQL_ATTR_AUTOCOMMIT

(SQLPOINTER) SQL_AUTOCOMMIT_OFF SQL_IS_UINTEGER) Allocate An SQL Statement Handlerc = SQLAllocHandle(SQL_HANDLE_STMT ExampleConHandle

ampExampleStmtHandle)if (rc == SQL_SUCCESS)

Define A SELECT SQL Statement

strcpy((char ) SQLStmt select name job salary + ifnull(comm0) ascompensation )

ptr = strcat( (char ) SQLStmt from org o staff s )ptr = strcat( (char ) SQLStmt where odeptnumb = sdept)ptr = strcat( (char ) SQLStmt and deptname = )ptr = strcat( (char ) SQLStmt order by compensation desc)

Prepare The SQL Statementrc = SQLPrepare(ExampleStmtHandle SQLStmt SQL_NTS)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)ExampleprintError(ExampleConHandle ExampleStmtHandle)

54

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

return(rc)

Bind The Columns In The Result Data Set Returned To Application Variables

rc = SQLBindCol(ExampleStmtHandle 1 SQL_C_CHAR (SQLPOINTER)ExampleName sizeof(ExampleName) NULL)

rc = SQLBindCol(ExampleStmtHandle 2 SQL_C_CHAR (SQLPOINTER)ExampleJob sizeof(ExampleJob) NULL)

rc = SQLBindCol(ExampleStmtHandle 3 SQL_C_DOUBLE (SQLPOINTER)ampExampleComp sizeof(ExampleComp) NULL)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO) ExampleprintError(ExampleConHandle ExampleStmtHandle)

return(rc)

while (true)

for (int i = 0 i lt LOOPS i++)

rc=SQLBindParameter(ExampleStmtHandle1SQL_PARAM_INPUTSQL_C_CHARSQL_CHAR

150(SQLPOINTER) currentDepartment[i8]0NULL)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)

ExampleprintError(ExampleConHandle ExampleStmtHandle)return(rc)

rc = SQLExecute(ExampleStmtHandle)if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)

ExampleprintError(ExampleConHandle ExampleStmtHandle)return(rc)

cout ltlt endl ltlt Current Dept ltlt currentDepartment[i8] ltlt

endl Display The Results Of The SQL QueryExampleShowResults()if(rc = 0)break

if ( i500 == 0 ampamp i gt 0 )cout ltlt Loops ltlt i ltlt ltlt endl

cout ltlt AFTER ltlt LOOPS ltlt loops Press X to exit ltlt endlcin gtgt cif (c[0] == x || c[0] == X)

break

Free The SQL Statement Handleif (ExampleStmtHandle = NULL )

SQLFreeHandle(SQL_HANDLE_STMT ExampleStmtHandle) Disconnect From The Northwind Sample Databaserc = SQLDisconnect(ExampleConHandle)

Return To The Operating Systemreturn(rc)

55

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Introduction AIX 5Ltrade is quickly becoming the preferred commercial implementation of UNIX operating system The recently announced IBMreg eServertrade i5 servers can run AIX 5L in as many as 160 separate logical partitions (LPARs) This gives iSeriestrade customers a very rich portfolio of business applications that are currently available on AIXreg Traditionally many organizations use the iSeries server as a reliable and highly scalable database server The iSeries database DB2reg UDB for iSeries is fully integrated in i5OSreg and OS400reg and exploits its robust features such as single-level storage tight security and object-based architecture For these reasons IBM believes that DB2 UDB for iSeries will remain the database of choice for most iSeries shops

Generally AIX applications can use several programming environments to access the iSeries database JDBC ODBC DB2 CLI and embedded SQL However depending on the protocol and specific driver implementation an AIX application can directly communicate with a back-end database server job on an iSeries server or it may require DB2 Connecttrade Gateway services Currently only IBM Toolbox for Java JDBC driver supports a direct native connection to iSeries servers All other interfaces require DB2 Connect This paper provides connectivity options implementation tips and a number of coding examples that illustrate how to optimize the access to a DB2 UDB for iSeries database from an AIX partition for each of these programming interfaces

Disclaimer The performance information in this document is for guidance only System performance depends on many factors including system hardware system and user software and user application characteristics Customer applications must be carefully evaluated before estimating performance IBM does not warrant or represent that a user can or will achieve similar performance No warranty on system performance or price performance is expressed or implied in this document

DB2 UDB for iSeries runtime As mentioned the DB2 UDB for iSeries engine is integrated into i5OS It uses and depends on the operating system to provide many services such as locking security archivebackup buffer management and transaction services The operating system in turn uses and relies on the database engine to provide certain services From the DB2 point-of-view an AIX application running in a partition on an eServer i5 server is just a regular remote database client that uses the back-end database server jobs to submit SQL requests to SQL runtime The DB2 SQL runtime supports several interfaces that can be used to submit SQL statements The interface that is used by a particular client depends on the type of database driver used by the client to connect to DB2 For example JTOpen JDBC driver supports both dynamic and extended dynamic SQL while DB2 Universal JDBC driver supports just the dynamic SQL interface This topic will be discussed in details throughout this paper The typical data flow between an AIX client back-end database server job and DB2 SQL runtime is illustrated in Figure 1

1

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 1 - DB2 UDB for iSeries SQL runtime

DB2 SQL Runtime Interfaces Letrsquos briefly discuss the DB2 SQL runtime interfaces

Static SQL

The SQL statements are embedded in the source code of a host application program For example a stored procedure can be written in C++ and contains a number of embedded SQL statements In this case the stored procedure source code has to be processed by an SQL preshycompiler prior to compiling the host application program itself At that time the embedded SQL statements are parsed validated and optimized As a result of this process an access plan gets created for each statement The access plan is a control structure that contains information on the actions necessary to satisfy an SQL request Typically it contains

bull An access method that the optimizer selected for a given statement (for example table scan)

bull Information on associated tables and indexes that is used at runtime to determine if an access plan needs to be rebuilt due to table changes or index changes

bull Any applicable environment information such as jobrsquos code page

The access plan is then permanently stored in the program object and can be reused when the program is executed

In another scenario an embedded SQL application may be executed on a client for example in an AIX partition and access the DB2 UDB for iSeries through DB2 Connect In this case a client-side DB2 SQL precompiler stores the static SQL statements in a bind file The bind file is then

2

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

bound to the back-end database server The bind process creates an SQL package on the DB2 UDB for iSeries The package contains the access plans and other control structures that can be reused when the client program executes

Static SQL is the most efficient way to process SQL requests on an iSeries server

Dynamic SQL Dynamic SQL statements are parsed validated and optimized at the time an SQL application is executed The SQL statements are passed to the database manager in the form of a character string using the SQL statements PREPARE or EXECUTE IMMEDIATE The IBM Toolbox for JavaJTOpen JDBC driver uses this method if Extended Dynamic SQL support is not enabled The Dynamic SQL is also used by the dynamic SQL interfaces such as DB2 Call Level Interface (DB2 CLI) ODBC and JDBC when a client application connects to DB2 UDB for iSeries through DB2 Connect gateway Refer to DB2 Connect data access on page 22 of this paper for more details

Extended Dynamic SQL In Extended Dynamic SQL the SQL statements are dynamic However SQL packages are used to make the implementation of the dynamic SQL statements similar to that of static SQL The SQL statements are parsed validated and optimized and the resulting access plan is permanently stored in a SQL package Note that this process is dynamic and new statements can be added to the SQL package at the run time The IBM Toolbox for JavaJTOpen JDBC driver can take advantage of the Extended Dynamic SQL support

3

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

JDBC Data Access This section provides implementation tips and coding examples that illustrate how to optimize the access to your DB2 UDB for iSeries database from a AIX partition by using various JDBC drivers Currently IBM offers several AIX-enabled JDBC drivers that support DB2 UDB for iSeries

bull Type 4 drivers mdash IBM Toolbox for Java JTOpen and DB2 Universal JDBC Driver bull Type 2 driver mdash DB2 JDBC Type 2 Driver

The IBM Toolbox for Java iSeries driver has been implemented in pure Javatrade and optimized for accessing DB2 UDB for iSeries data It uses native iSeries protocol to communicate with the back-end database server job JTOpen is the open-source version of the IBM Toolbox for Java Licensed Program Product (LPP)

The DB2 Universal JDBC Driver is also a pure Java implementation It is a part of the DB2 UDB for AIX Version 8 product and it uses the Distributed Relational Database Architecture (DRDA) protocol for clientserver communications The driver is compatible with various DB2 UDB server platforms with appropriate DRDA Application Server (AS) level support and prerequisite stored procedures It also supports Type 2 connectivity when accessing DB2 UDB for Linuxreg UNIX and Windowsreg (DB2 UDB for LUW) databases

The traditional DB2 JDBC Type 2 Driver is built on top of DB2 Call Level Interface (CLI) It requires DB2 Connect functionality to access DB2 UDB for iSeries This is a legacy driver and IBM currently recommends that the DB2 Universal JDBC driver is used instead

Initial Configuration Considerations Practical experience shows that the JDBC application performance greatly depends on the programming techniques and the SQL access tuning However significant performance gains can be achieved by simply tweaking the AIX partition environment For example a virtual LAN connection to the back-end database can significantly streamline the data flow

4

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Virtual Versus Physical LAN One of the most significant benefits of installing AIX in an iSeries partition is the ability to utilize virtual LAN and virtual DASD This usually results in reduced hardware costs through improvements in data transfer performance and enhanced disk protection The performance tests conducted by the IBM eServer Solutions Enablement team showed that the Virtual 1Gb LAN delivered a data throughput similar to dedicated 1Gb Ethernet adapters (model 5706) connected via a dedicated Ethernet segment An example configuration is illustrated in Figure 2

Figure 2 VLAN vs 1 Gb Ethernet IOA configuration

Although similar performance can be expected for VLAN and 1Gb Ethernet the VLAN configuration has two advantages over the physical LAN connection

bull No additional communications gear is required bull It is a dedicated point-to-point connection so there is no interference from other devices on

the same network segment

On the other hand certain application scenarios may benefit from a physical LAN adapter dedicated to an AIX partition For instance in a three-tier application architecture clients connect to an application server running in a AIX partition The application server in turn connects to DB2 UDB for iSeries where data is stored and retrieved In this case configuring a separate physical LAN connection in a AIX partition has the following advantages

bull An unnecessary additional hop is eliminated from the network route bull Client-application server traffic does not unnecessarily saturate i5OS communications gear

5

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Tuning DB2 UDB for iSeries Access with IBM Toolbox for Java and JTOpen Driver This section covers JDBC implementation details for a sample Java program called TestJDBC (the source is provided at the end of this paper in Appendix A) The application uses the Java Naming and Directory Interface (JNDI) to obtain a database connection deletes 5000 records generates and inserts 5000 records and finally retrieves the newly inserted records from an SQL table called COFFEES The application executes in an AIX partition and accesses the DB2 UDB for iSeries through the JTOpen (or IBM Toolbox for Java) driver Figure 3 shows the software components involved in the execution of this simple application

Figure 3 JDBC client accessing DB2 UDB for iSeries

Apart from the JTOpen driver which can be downloaded from the IBM Toolbox for Java Web site you need three other JAR files to successfully compile and execute the JDBCTest application in a AIX partition

bull providerutiljar and fscontextjar mdashDownload a simple file system JNDI provider from Sun Microsystems JNDI Web site httpjavasuncomproductsjndidownloadsindexhtml

bull jdbc2_0-stdextjar mdash Copy the javaxsql package from the QIBMUserDataJava400ext IFS directory on the iSeries server

The location of the JAR files needs to be added to the CLASSPATH environment variable For instance the following entry could be added to the AIX profile script

6

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

CLASSPATH=homecodeJTOpenjt400jarCLASSPATH=$CLASSPATHhomecodefscontextproviderutiljarCLASSPATH=$CLASSPATHhomecodefscontextfscontextjarCLASSPATH=$CLASSPATHhomecodeJTOpenjdbc2_0-stdextjarexport CLASSPATH

To compile the source use the following command in the AIX partition

javac TestJDBCjava

Although the TestJDBC application is fairly simple it illustrates several important aspects of efficient JDBC programming for DB2 UDB for iSeries

Connection PoolingA JDBC connection can be obtained through either the DataSource or DriverManager object Either method involves significant overhead A fairly large amount of system resources is required to create and maintain the connection and then release it when it is no longer needed JTOpen allows a developer to establish a pool of database connections that can be shared by multiple client applications Connection pooling can improve the response time because the connection pool manager can locate and use an existing connection When the database request is completed the connection returns to the connection pool for reuse

In the JDBCTest sample JNDI was first used to register a connection pool-capable data source Heres an excerpt from the deployDataSource method of the sample application

Hashtable env = new Hashtable()envput(ContextINITIAL_CONTEXT_FACTORY

comsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env) [1]

Register an AS400JDBCConnectionPoolDataSource objectAS400JDBCConnectionPoolDataSource tkcpds = newAS400JDBCConnectionPoolDataSource() [2]tkcpdssetServerName(serverName) tkcpdssetDatabaseName(databaseName) tkcpdssetUser(userName) tkcpdssetPassword(password) tkcpdssetDescription(Toolkit Connection Pooling DataSourceobject) hellip ctxrebind(jdbcToolkitDataSource tkcpds) [3]

At [1] the initial JNDI context is created

Then at [2] an AS400JDBCConnectionPoolDataSource object is instantiated This is the JTOpen implementation of the javaxsqlConnectionPoolDataSource interface An AS400JDBCConnectionPoolDataSource object supports a number of methods that can be used to set iSeries-specific properties of the underlying DataSource object Some of these properties will be discussed in greater detail in the following sections of this paper

At [3] the data source object is bound to an arbitrary name that will be used in the main application Note that the deployDataSource method needs to be executed just once unless some of the data source properties need to be changed In that case the developer would need to rebind

7

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

The JNDI registered data source is then used in the main application to initialize the connection pool

AS400JDBCConnectionPoolDataSource tkcpds = [1](AS400JDBCConnectionPoolDataSource)ctxlookup(jdbcToolkitDataSource) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPool pool = newAS400JDBCConnectionPool(tkcpds)[2] Adds 1 connection to the pool that can be used by the application(creates the physical database connections based on the datasource)poolfill(1) [3] hellip con = poolgetConnection()[4]

At [1] the JNDI service is used to instantiate the AS400JDBCConnectionPoolDataSource

Then at [2] an AS400JDBCConnectionPool object is created This object is responsible for managing the connection pool

At [3] the connection pool is initialized with one connection

The pool object is used at [4] to obtain a database connection There are several additional things the developer should know about this code snippet

bull The advantage of using JNDI to register the data source object as opposed to just instantiating it in the main method is that in a more realistic scenario the data source would be registered just once at application deployment time Additionally the data source properties do not have to be hard-coded in the main method and can be changed at any time and then rebound without affecting the application

bull The AS400JDBCConnectionPool is a proprietary JTOpen implementation of a connection pool Specifically it does not implement the Referenceable interface and thus cannot be bound through JNDI services

bull The JTOpen AS400JDBCConnectionPoolDataSource does not support statement caching as described in the JDBC 30 specification Statement caching is implemented through SQL packages This feature is covered in the following section

Note The native iSeries JDBC driver supports both connection pooling and statement caching in a JDBC 30 compliant manner

8

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Extended Dynamic SQL and Statement Caching As mentioned the JTOpen data source object supports a number of properties that can be used to fine-tune the database performance In this section properties used to enable extended dynamic SQL support (see DB2 SQL Runtime Interfaces section above) and local statement caching will be discussed

Here is a relevant code excerpt from the deployDataSource method

AS400JDBCConnectionPoolDataSource tkcpds = new AS400JDBCConnectionPoolDataSource() hellip tkcpdssetExtendedDynamic(true)[1]tkcpdssetPackage(JDBCDS) [2]tkcpdssetPackageCache(true) [3]tkcpdssetPackageCriteria(select) [4]

At [1] the extended dynamic SQL support is enabled Note that the default is disabled for JTOpen The extended dynamic SQL functionality is often referred to as SQL package support The SQL packages are server-side repositories for SQL statements Packages contain the internal structures such as parse trees and access plans which are needed to execute SQL statements Because SQL packages are a shared resource the information built when a statement is prepared is available to all the users of the package This saves processing time especially in an environment where many users are using the same or similar statements Also because SQL packages are permanent this information is saved across job initiationtermination and IPLs In fact SQL packages can be saved and restored on other servers

At [2] the SQL package is named Note that the actual package name on the iSeries server is JDBCDSBAA The package name is generated by taking the name specified on the client and appending three letters that are an encoded set of the package configuration attributes By default an SQL package does not contain unparameterized select statements This behavior is overridden at [4] by setting the PackageCriteria property to select

At [3] the local statement cache is enabled A copy of the SQL package is cached on the AIX client This may improve application performance in a way similar to JDBC 30 statement caching Note however that local statement caching is not recommended for large SQL packages The copy of an SQL package is cached when the database connection is obtained This may cause increased network traffic as well as slow down the connection setup time

Reusable Open Data Paths (ODPs)An Open Data Path (ODP) definition is an internal i5OS object that is created when certain SQL statements (such as OPEN INSERT UPDATE and DELETE) are executed for the first time in a given job (or connection) The ODP can be thought of as a runtime implementation of an access plan The access plan created at the optimization time provides a recipe or in other words a sequence of steps necessary to execute the statement The ODP on the other hand provides the executable code for all requested IO operations The process of creating new ODP objects is fairly CPU- and IO-intensive so whenever possible the iSeries DB2 runtime tries to reuse existing ODPs For instance a ResultSetclose() call may close the SQL cursor but leave the ODP available to be used the next time the cursor is opened This can significantly reduce the response time in running SQL statements A reusable OPD usually requires 10 to 20 times less CPU resources than a newly created ODP Therefore it is important that the applications employ programming techniques that allow the DB2 runtime to reuse ODPs

With dynamic programming interfaces such as JDBC the most efficient way to avoid full opens is to employ the so-called prepare once execute many programming paradigm Ideally an SQL statement that is executed more than once should be prepared just once mdashfor example in the class constructor mdash and then reused for the consecutive executions At the prepare time the

9

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 engine stores the prepared statement along with the associated statement name in the QZDASOINIT jobs statement cache On the first execution the ODP created for a given statement is associated with the appropriate entry in the statement cache On consecutive executions the prepared statement and the corresponding ODP can be quickly located in the statement cache and reused The code snippet below illustrates the prepare once execute many programming technique

PreparedStatement pstmt = conprepareStatement(INSERT INTO COFFEES VALUES( ))[1] hellip for (int i = 0 i lt outerNumOfLoops i++)

insertfor (int j = 0 j lt numOfLoops j++)

pstmtsetString(1 Lavaza_ + IntegertoString(j)) hellip pstmtaddBatch()

int [] updateCounts = pstmtexecuteBatch()[2]concommit()

At [1] a PreparedStatement pstmt object is instantiated for a parameterized INSERT statement The statement is prepared just once The PreparedStatement object is then repeatedly used at [2] to perform blocked insert

Block Inserts Occasionally the developer may need to initially populate a table or insert a modified result set into a temporary table The efficiency of the insert operation for a large set of records can be dramatically improved by using the executeBatch method rather than the executeUpdate method The JTOpen driver converts parameterized insert statements in an executeBatch method to a block insert statement This significantly reduces the data flow and system resources required to perform the insert The following code snippet shows how to take advantage of the executeBatch method

10

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

PreparedStatement pstmt =conprepareStatement(INSERT INTO COFFEES VALUES( ))[1]for (int j = 0 j lt numOfLoops j++) pstmtsetString(1 Lavaza_ + IntegertoString(j))pstmtsetInt(2 i)pstmtsetFloat(3 499f)pstmtsetInt(4 0)pstmtsetInt(5 0)pstmtaddBatch() [2]

int [] updateCounts = pstmtexecuteBatch() [3]

At [1] a parameterized insert statement is prepared Note that all columns must be parameterized Otherwise the executeBatch method may throw the SQL0221 Number of rows 1 not valid exception In other words the developer should not mix parameter markers with literals or special registers in the VALUE clause

At [2] the addBatch method is used to add a new record to the client record buffer

At [3] all locally buffered data is sent to the server which in turn performs a block insert

Figure 4 shows the performance data for the executeBatch and executeUpdate methods

Figure 4 executeBatch() versus executeUpdate() performance comparison

11

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

WebSphere Considerations In certain situations an application provider may decide to deploy WebSphere Application Server in an AIX partition rather than natively in i5OS At the same time the application uses DB2 UDB for iSeries as an back-end database server Typically the WebSphere Application Server running in the AIX partition uses the virtual LAN to communicate with DB2 UDB for iSeries The WebSphere applications will access the database through a remote JDBC connection For performance and functionality reasons IBM recommends to utilize in such environments the IBM Toolbox for Java JTOpen driver Most of the tips and techniques described so far in this document hold true for WebSphere applications accessing DB2 UDB for iSeries There are however certain JDBC access aspects that are specific to this multi-tier architecture Letrsquos have a closer look at some of these considerations

Connection Pooling and Statement Caching

WebSphere Application Server provides its own connection pooling and statement caching mechanism that is by default enabled so that WebSphere applications automatically enjoy the performance benefits of these two critical programming techniques See the following link to learn more about the optimal connection pool setting in WebSphere

httppublibboulderibmcomwas40051englishinforzaiz51adminhelpudat_conpoolsethtml

Extended Dynamic SQL

For non-JTA connections WebSphere Application Server uses the comibmas400accessAS400JDBCConnectionPoolDataSource class as the iSeries JDBC provider implementation This is the DataSource implementation that has been used in all previous coding examples As mentioned the class supports a range of iSeries specific properties that can be used to fine tune JDBC performance These properties can be set through the WebSphere Application Server admin console For example herersquos the procedure to enable the extended dynamic SQL support In the WebSphere Application Server admin console navigate to the Data Source configuration dialog by selecting JDBC Providers -gt iSeriesToolbox -gt Data Sources then scroll down to the Additional Properties section Select Custom Properties link The Custom Properties dialog opens Scroll down to find the Extended Dynamic property and select it Change the default value false to true save the new configuration by clicking Apply button This is illustrated in Figure 5

12

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 5 Enabling the extended dynamic SQL through WebSphere Application Server console

The WebSphere Application Server needs to be restarted for the change to take effect The similar procedure can be followed to set other iSeries Data Source properties

Changing the WebSphere Application Server default isolation level

WebSphere Application Server V5 uses the REPEATABLE_READ (RR) isolation level for all implicit (WebSphere Application Server managed) transactions With the RR isolation level the rows selected updated deleted and inserted are locked until the end of the transaction Under certain circumstances this fairly extensive locking policy may cause locking contention especially when a WebSphere application competes for database resources with other applications that run on iSeries server For example a legacy order entry application may share data with the e-business customer care application running in WebSphere The locking contention may sometimes be eliminated by lowering the isolation level used by WebSphere Although the iSeries Data Source supports the custom transactionIsolation property resetting this property on the Data Source object will not change the default isolation level used by WebSphere for the connection objects produced by that Data Source In other words WebSphere will override the Data Source isolation level setting at the time the connection is obtained by a WebSphere application object such as servlet or Enterprise Java Bean (EJB) In order to change the default WebSphere behavior one must use the resource referencing Resource referencing allows a programmer to lookup DataSource or EJB objects using alias names rather than JNDI names Additionally by creating a resource reference a programmer can change certain properties of the underlying object Specifically a DataSource reference can be used to set a different isolation level for the connections produced by this database resource Typically resource references are defined by a programmer in a application development tool such as WebSphere Studio Application Developer The method to specify a DataSource reference differs depending on whether a programmer plans to use the reference in a servlet or in an EJB Letrsquos start with outlining the configuration process for a servlet In WebSphere Studio Application Developer open the deployment descriptor editor for the web project that contains the servlet To do so double click on the webxml file under WEB-INF directory in the web project In the deployment editor dialog select the References tab and then select Resource tab located in the top of the dialog that appears Under Resource References section select the Add button Herersquos an example of a DataSource reference created for iSeries DataSource named TestJDBCDS Note that the reference changes the default isolation level to READ_COMMITTED

13

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 6 Defining a resource reference for a servlet

Once the resource reference has been defined and saved the servlet source code needs to be changed to reflect the fact that a resource reference is used to obtain a DataSource from the JNDI service Herersquos the relevant code snippet try

ctx = new InitialContext() ds = (DataSource)ctxlookup(javacompenvTestJDBCJ2C)

catch (Exception e) eprintStackTrace(out)

Now the ds DataSource object will produce connections that by default run with the isolation level of READ_COMMITTED (RC)

As mentioned the process of defining a resource reference for an EJB differs from the process that is used in the case of a servlet In WebSphere Studio Application Developer open the deployment descriptor editor for the EJB project that contains the EJB To do so double click on the ejb-jarxml file under WEB-INF directory in the project In the deployment editor dialog select the References tab In the references section on the left locate and select the EJB for which the developer wants to change the default isolation level Click the Add button The Add Reference dialog opens Click the Resource Reference radio button and then Next Define the reference following the example shown in Figure 7

14

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 7 Adding a resource reference for an EJB

When you click ldquoFinishrdquo the reference definition is added to the EJB descriptor The new definition needs to be further modified To do so click on the (+) sign next to the EJB in the References list Click the new reference TestJDBCJ2C in this example to open the properties for the reference Change WebSphere Bindings and WebSphere Extensions sections as illustrated in Figure 8

15

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 8 Defining a resource reference for an EJB

Save the modified definition and then change the EJB source code to use the reference rather than directly DataSource

TroubleshootingTroubleshooting a multi-tier application may be a bit tricky because the developer needs to deal with software components that reside in separate partitions Three tools are particularly useful for pinning down the potential problem areas bull Joblog messages for a database server job mdash Provides enough details to isolate DB2 UDB for

iSeries runtime issues bull JDBC trace utility mdash Provides granular information about the data flow between the AIX

application and the iSeries server job bull Database Monitor ndash Provides detailed SQL runtime trace

Job Log MessagesAs mentioned a DB2 client communicates with a corresponding iSeries server job This server job runs the SQL requests on behalf of the client The iSeries database server jobs are called QZDASOINIT and they run in the QUSRWRK subsystem At any given time a large number of database server jobs may be active on the server so the first step is to identify the job that serves the particular client connection The easiest method to accomplish this task is to run the following CL command from the i5OS prompt

WRKOBJLCK OBJ(DB2USER) OBJTYPE(USRPRF)

Here DB2USER is the user profile that is used to connect to the iSeries server Note that a QZDASONIT job is assigned to a client after the connection has been established so the developer needs to set a breakpoint in the client application after the database connection has been established

Once the Work with Object Locks appears key in 5 (Work with Job) next to the only QZDASOINIT job that should be listed This shows the Work with Job dialog Select option 10 to

16

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

display the job log for the database server job Now the job log can be searched for any error messages generated by the DB2 runtime

Sometimes it is also useful to include debug messages in the job log The debug messages are informational messages written to the job log about the implementation of a query They describe query implementation methods such as the use of indexes join order ODP implementation (reusable versus non-reusable) and so on The easiest way to instruct an iSeries server to include the debug messages is to set the ServerTraceCategories property on the data source object

tkcpdssetServerTraceCategories(AS400JDBCDataSourceSERVER_TRACE_DEBUG_SERVER_JOB)

A sample of the job log messages with debug messages enabled is shown below

SET TRANSACTION completeSTATEMENT NAME FOUND QZ868F0A458E13AF8C Starting optimizer debug message for query Arrival sequence access was used for file COFFEESODP created ODP not deleted 5000 rows inserted in COFFEES in DB2USER STATEMENT NAME FOUND QZ868F0A4C144BF12EBlocking used for queryCursor CRSR0001 opened606 rows fetched from cursor CRSR0001 ODP not deleted Cursor CRSR0001 closed

So the job log offers fairly detailed information on how the AIX client requests were implemented by the DB2 runtime

JDBC Trace UtilityThe JTOpen driver provides a tracing utility which can be used to collect detailed client-side traces The JDBC tracing is turned off by default It can be enabled by setting the Trace property to true Heres an example of how to switch on tracing using the setTrace method on the data source object

tkcpdssetTrace(true)

The trace can also be enabled when using the DriverManagergetConnection() method for obtaining a connection to DB2 UDB for iSeries In this case the developer could add the trace property to the connection string This approach is illustrated in the following code snippet

ClassforName(comibmas400accessAS400JDBCDriver) [1] hellip con = DriverManagergetConnection(jdbcas400teraplextrace=true

db2userdb2pwd) [2]

At [1] an instance of the JTOpen JDBC Driver is initiated Then at [2] the driver is used to obtain a connection to the iSeries server Note how the trace property has been added to the database URL See the IBM Toolbox for Java JDBC properties documentation on the iSeries Information Center Web site for a complete list of properties supported by the JTOpen driver

Although the level of details provided by the trace utility is sufficient in most troubleshooting scenarios sometimes the developer may need to collect low-level traces scoped to a certain type

17

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

of information In V5R3 the IBM Toolbox for Java (as well as the latest JTOpen) added a comprehensive detailed trace facility The following is the complete list of detailed trace parameters and their purpose

bull None or ldquordquo ndash This setting disables the detailed trace bull datastream - This category is used by Toolbox classes to log dataflow between the local host

and the remote system It is not intended for use by application classes bull diagnostic - This category is used to log object state information bull error - This category is used to log errors that cause an exception bull information - This category is used to track the flow of control through the code bull warning - This category is used to log errors that are recoverable bull conversion - This category is used by Toolbox classes to log character set conversions

between Unicode and native code pages bull proxy - This category is used by Toolbox classes to log data flow between the client and the

proxy server bull pcml - This category is used to determine how PCML interprets the data that is sent to and

from the server bull jdbc - This category is used to track JDBC calls throughout the program bull thread - This category is used to enable tracing of thread information This is useful when

debugging multi-threaded applications bull all - This category will enable all previous categories

The detailed trace can be enabled when using the DriverManagergetConnection() method for obtaining a connection to DB2 UDB for iSeries In this case the developer could add the toolbox trace property to the connection string This is illustrated in the following code sample

String dbUrl = jdbcas400pwd1toolbox trace=diagnostic con = DriverManagergetConnection(dbUrl dbUser dbPassword)

Note that currently the driverrsquos DataSource interfaces do not allow the developer to directly activate the detailed tracing However they could set the server from the command line at the time the java program is launched The example below shows how the detailed trace properties could be enabled at the command line

java -Dcomibmas400accessTracecategory=diagnostic TestJDBC

The -D switch indicates to the java interpreter that the information following it will be a system property

In case of a WebSphere application the trace property can be set through the admin console In the console select Application Servers-gt server1-gt Process Definition -gt Java Virtual Machine Figure 9 shows how to set the Generic JVM Arguments for an application server instance

18

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 9 Setting JVM arguments to enable detailed Toolbox tracing

Database Monitor

The database monitor is the ultimate tool available on DB2 UDB for iSeries to collect low-level SQL traces It is mainly used to pin down the SQL performance problems Refer to the lsquoUsing iSeries Database Monitor to Identify and Tune SQL Queriesrsquo white paper for a detailed discussion on how to collect and analyze the database monitor traces httpibmcomserversenablesiteeducationiborecordhtmldtmon

IBM DB2 JDBC Universal Driver DB2 JDBC Universal Driver is one of the new features delivered with DB2 UDB Version 8 DB2 JDBC Universal Driver has been designed to eliminate the dependency on DB2 CLI runtime modules as well as to enable direct Type 4 connectivity to DB2 UDB for iSeries and DB2 UDB for zOSreg

The pure-Java (Type 4) remote connectivity is based on the DRDA open distributed protocol for cross-platform access to DB2 DRDA defines the rules the protocols and the semantics for accessing distributed data Applications can access data in a distributed relational environment by using SQL statements The iSeries DRDA application server implementation is based on multiple connection-oriented server jobs running in the QSYSWRK subsystem A DRDA listener job (QRWTLSTN) listens for TCP connect requests on port 446 Once an application requester connects to the listener job the listener wakes up one of the QRWTSRVR prestart jobs and assigns it to a given client connection Any further communication occurs directly between the client application and the QRWTSRVR job These concepts are illustrated in Figure 10

19

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 10 Accessing DB2 UDB for iSeries with DB2 Universal Driver

The DB2 Universal Driver can be loaded in an AIX partition by installing one of the DB2 Connect for AIX products (see the Additional Information section for details) It is also a part of a DB2 Enterprise Server Edition for AIX install Specifically the developer needs three JAR files in a AIX partition to successfully connect to an iSeries server db2jccjar db2jcc_license_cisuzjar and db2jcc_license_cujar The iSeries license is contained in db2jcc_license_cisuzjar Note that this file is not a part of DB2 Client In other words a DB2 Connect license is required to use the driver in production environments The location of the JAR files needs to be added to the CLASSPATH environment variable For instance the following entry could be added to the AIX profile script

CLASSPATH=homedb2inst2sqllibjavadb2jccjarCLASSPATH=$CLASSPATHhomedb2inst2sqllibjavadb2jcc_license_cujarCLASSPATH=$CLASSPATHhomedb2inst2sqllibjavadb2jcc_license_cisuzjarexport CLASSPATH

Java Runtime 131 is a prerequisite

Additionally the developer should install the latest database group PTF (SF99503 for i5OS V5R3) on the iSeries server The Informational APAR ii13348 is keeping track of any fixes relevant to DRDA above and beyond the current database group PTF

Obtaining a Connection to DB2 UDB for iSeries When Type 4 connectivity is used the DB2 Universal Driver connects directly to the DB2 on iSeries through TCPIP Note that this is different from the legacy DB2 Type 2 JDBC driver that requires a DB2 node and remote database configurations on the client accessing iSeries The following code snippet illustrates how to use the DB2 JDBC Universal Driver to obtain a connection to DB2 UDB for iSeries

20

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

try ClassforName(comibmdb2jccDB2Driver) [1] catch(javalangClassNotFoundException e) Systemerrprint(ClassNotFoundException )Systemerrprintln(egetMessage())

try DriverManagergetConnection(jdbcdb2teraplex446TERAPLEX[2]

db2userdb2pwd) hellip catch(SQLException ex) Systemerrprintln(

SQLException + exgetMessage())

At [1] an instance of the DB2 JDBC Universal Driver is instantiated Then at [2] the driver is used to obtain a connection to the iSeries server Note the proper form of the database URL required by the driver

Considerations There are several advantages of DB2 JDBC Universal Driver bull Ease of cross-platform development mdash Consistent coding techniques and consistent error

codes and messages bull Ease of deployment mdash Pure Java (no runtime client required) and a single driver for accessing

DB2 on different platforms

The ease of use comes at a price though The iSeries JTOpen driver is optimized for accessing DB2 UDB for iSeries data and it uses native iSeries protocol to communicate with the back-end database server job This usually results in better performance and more-efficient system resources utilization For instance when using the DB2 JDBC Universal Driver to access an iSeries server the executeBatch method results in a single record insert There are also some restrictions when using DB2 Universal JDBC Driver with Type 4 connectivity

bull Support for distributed transactions (JTA) is not enabled bull Driver built-in connection pooling is not supported

Refer to Java application support in DB2 for more details on DB2 JDBC Universal Driver

21

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 Connect data access This section will explore the most important aspects of DB2 Connect ndash iSeries integration - including configuration tips and coding examples

DB2 Connect provides functionality for accessing data stored in DB2 UDB for iSeries as well as DB2 UDB for zOS and DB2 UDB for OS390reg DB2 Connect offers capabilities to access DB2 family members via several SQL interfaces gateway functions such as connection pooling and federated database functionality Many applications supporting the DB2 family of products leverage DB2 Connect as a key middleware component DB2 Connect is offered as separate AIX license products

Enterprise Edition Application Server Edition

In addition to DB2 Connect there are several other DB2 UDB Version 81 products that are supported on AIX

DB2 Universal Database Enterprise Server Edition DB2 Universal Database Workgroup Server Unlimited Edition DB2 Universal Database Workgroup Server Edition DB2 Universal Database Universal Developers Edition All Clients

The DB2 Connect Enterprise Edition functionality is also contained in DB2 Enterprise Server Edition for AIX

22

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 Connect in a nutshell In the scenario described in this paper the DB2 Connect functions contained in DB2 Enterprise Edition for AIX are utilized DB2 Connect Enterprise Edition provides support for both local and remote DB2 clients This is illustrated in Figure 11 Accessing DB2 UDB for iSeries with DB2 Connect

Figure 11 Accessing DB2 UDB for iSeries with DB2 Connect

DB2 Connect implements the Distributed Relational Database Architecturetrade (DRDAreg) to reduce the cost and complexity of accessing data stored in DB2 UDB for iSeries and other DRDA-compliant database servers DRDA defines the rules the protocols and the semantics for accessing distributed data Applications can access data in a distributed relational environment by using SQL statements In a distributed environment the system running the application and sending the SQL requests across the network is called the application requester (AR) A remote database server that executes SQL requests submitted by an application requester is known as the application server (AS) In the example shown in Figure 11 (above) DB2 Connect plays the role of an application requester while DB2 UDB for iSeries is an application server In this case DB2 Connect communicates with the iSeries database through TCPIP The iSeries DRDA application server implementation is based on multiple connection-oriented server jobs running in the QSYSWRK subsystem A DRDA listener job (QRWTLSTN) listens for TCP connect requests on port 446 Once an application requester connects to the listener job the listener wakes up one of the QRWTSRVR prestart jobs and assigns it to a given client connection Any further communication occurs directly between the client application and the QRWTSRVR job

DB2 Connect supports a wide range of programming interfaces that can be used by AIX applications to access the iSeries database Embedded SQL frac34 Both static and dynamic SQL frac34 Various programming languages (Java CC++ Cobol Fortran REXX)

DB2 Call Level Interface (DB2 CLI) ODBC JDBC frac34 DB2 JDBC Type 2 Driver frac34 DB2 JDBC Type 4 Driver (Universal JDBC Driver)

23

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Note that DB2 Connect supports access to DB2 UDB for iSeries through DB2 JDBC Universal driver However for performance and ease of maintenance reasons IBM recommends that Java applications running in AIX use native iSeries Toolbox JDBC driver See the JDBC Data Access section of this paper (above) for more details On the other hand DB2 Connect is a very efficient and robust connectivity option for AIX applications especially in the environments that are not directly supported by the native iSeries JDBC driver Here are several possible scenarios that would require DB2 Connect installed in a AIX partition

Embedded SQL interface is used to access DB2 CLI or ODBC interface is used to access DB2 A single SQL interface is needed to access multiple back end DB2 server Specific DB2 Connect functionality is needed such as distributed join or connection

pooling

Prerequisites One of the DB2 Connect products or DB2 Enterprise Server Edition for AIX V81 is needed Additionally DB2 Application Development Client is required in the AIX partition to compile DB2 applications

For maximum database server stability the developer should install the latest database group PTF (SF99503 for i5OS V5R3) on the iSeries server The Informational APAR ii13348 is keeping track of any fixes relevant to DRDA above and beyond the current database group PTF

DB2 Connect configuration The following example employs i5OS V5R3 and DB2 UDB Enterprise Server Edition for AIX Version 81 FixPak 6

Configuration steps in the iSeries partition The following process lists the necessary steps to be performed on the iSeries server 1) Verify that the TCPIP stack is working correctly It is assumed that the Virtual LAN is used to

communicate with the i5OS partition First obtain the IP address of the iSeries server or its hostname and ping the iSeries server from the AIX partition

2) Create a relational database (RDB) entry for the iSeries database in the i5OS partition If this has already been created it can be displayed by using the DSPRDBDIRE command Make sure that the RDB entry with a location of LOCAL exists on the iSeries server If it does not exist use the ADDRDBDIRE command to add the appropriate RDB entry For example the following command would add an RDB entry named TPLX For simplicity it is recommended that the TCPIP host name and RDB entry remain the same

ADDRDBDIRE RDB(TPLX) RMTLOCNAME(LOCAL)

3) Create a collection called NULLID This is necessary because the utilities shipped with DB2 Connect and DB2 UDB for AIX store their packages in the NULLID collection Since it does not exist by default in the iSeries server you must create it using the following command

CRTLIB LIB(NULLID)

4) Products that support DRDA automatically perform any necessary code page conversions at the receiving system For this to happen both systems need a translation table from their code page to the partner code page The default Coded Character Set Identifier (CCSID) on the iSeries server is 65535 Since DB2 Connect does not have a translation table for this code page the developer needs to change the individual user profiles to contain a CCSID that can be converted properly by DB2 Connect For US English this is 037 For other languages see DB2 Connect Personal Edition Quick Beginning GC09-2967 The following command changes the CCSID for an individual user profile to 037

24

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

CHGUSRPRF userid CCSID(037)

5) Verify that the default port 446 for DRDA service is being used To do this go to the Configure TCPIP menu (CFGTCP) select Configure Related Tables and then select Work with service table entries Verify that the DRDA service is set for port 446

6) The Distributed Data Management (DDM) job must be started for DRDA to work If you want the DDM job to be automatically started whenever TCPIP is started change the attributes of the DDM job using the CHGDDMTCPA command and set the Autostart server parameter to YES

7) If the system administrator chooses not to autostart the server issue the following command to start the DDM server job

STRTCPSVR SERVER(DDM)

8) Make sure that the user profiles that will be used to connect to the iSeries server exist on the server

25

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Configuration steps in the AIX partition The following steps are required for DB2 Connect to be configured in the AIX partition 1) Sign on to the AIX partition as the DB2 administrator 2) Launch Client Configuration Assistant (db2ca from the command prompt) It is assumed that

VNC or an X-Windows server are being used on the workstation so that the db2ca GUI can be properly rendered

3) From the Selected pull-down menu select the Add Database using Wizard option The Select how you want to setup a connection dialog appears Select Manually configure a connection to a database and click Next This is shown in Figure 12

Figure 12 Accessing DB2 UDB for iSeries with DB2 Connect

26

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

4) On the Select a communications protocol choose TCPIP and select The database physical resides on a host or OS400 system Then select the option Connect directly to the server as shown in Figure 13 Click Next

Figure 13 mdash Selecting communications protocol

27

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

5) On the TCPIP tab fill in the host name of the iSeries server The port number should be 446 This is shown in Figure 14 Click Next

Figure 14 mdash Specifying TCPIP communication parameters

28

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

6) On the Database tab fill in the Relational Database name Use the RDB entry name (specified in step 2) in the Configuration steps in the iSeries partition section as shown in Figure 15 Click Next

Figure 15 mdash Specifying the remote database

7) If you plan to use the ODBC applications select Register this database for ODBC as a system data source on the ODBC tab Click Next

29

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

8) On the Specify the node option dialog select OS400 from the Operating System pull-down menu This is shown in Figure 16 Click Finish

Figure 16 mdash Specifying the node options

30

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

9) The Test Connection dialog appears This allows the developer to verify that the connection works Select both CLI and JDBC check boxes You are also prompted for an iSeries user ID and password as shown in Figure 17

Figure 17 mdash Testing the connection

31

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

10) The successful connection to the database server is confirmed by the message box shown in Figure 18

Figure 18 mdash Test Connection results 11) At this time a newly configured database connection should appear in the main DB2

Configuration Assistant window It is recommended that the DB2 utilities are also bound to the iSeries database The bind process creates the necessary SQL packages on the remote database In the main Configuration Assistant window click the TPLX database entry and then select Selected-gtBindhellip

32

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

12) The Bind dialog appears Click Select All and then enter the connection information as shown in Figure 19 Click Bind The Results message box appears This allows the developer to monitor the progress of the binding process Watch for any error and warning messages

Figure 19 mdash Binding the DB2 utilities This concludes the DB2 Connect configuration steps

33

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Accessing DB2 UDB for iSeries from C embedded SQL

As mentioned earlier DB2 Connect allows developers to compile and run embedded SQL applications that access DB2 UDB for iSeries data This section covers implementation details for a C embedded SQL application called cursorsjsqc (see Appendix B for source code)

Prerequisites An embedded SQL application running in an AIX partition will use DB2 Connect services to access DB2 UDB for iSeries therefore the developer needs to make sure that all components listed in section Prerequisites on page 24 are installed The developer also needs to create a remote database connection as described in the DB2 Connect configuration section of this paper on page 24

Static SQL and SQL packages To successfully run against a DB2 UDB for iSeries database an embedded SQL application needs to be first precompiled and bound to the back-end database This process creates an SQL package on the target iSeries server The SQL package contains the access plan information for the SQL statements executed by the application The internal structure of the package as well as the method how its content is used by the SQL runtime to facilitate the access plan reuse is similar to the Extended Dynamic SQL support covered in detail in the Extended Dynamic SQL and Statement Caching section of this paper (on page 9) There are however important differences between the packages created by the extended dynamic SQL support and the packages created for embedded SQL DRDA client applications The extended dynamic SQL packages support dynamic SQL interfaces such as JDBC

that can submit ad hoc SQL statements at the run time The SQL runtime can prepare the dynamic statements and add them to the package On the other hand the DRDA packages are created at the precompile time and contain static SQL In order to add new statements to the package the application needs to be precompiled and rebound again

The extended dynamic SQL package can dynamically grow up to 500MB by allocating new space as required The DRDA packages since they are created at the precompile time have a fix size and do not grow over their life time

Simple embedded SQL application The application is based on a source code provided in the DB2 UDB samples directory typically to be found at homedb2inst1sqllibsamples The cursorsjsqc performs a join between STAFF and ORG tables located in DB2USER schema (library) on the TPLX database server (the source is provided at the end of this paper in Appendix B) The join statement retrieves the DEPTNAME column from ORG NAME column from STAFF and calculates the total compensation for an employee by adding SALARY and COMM columns in STAFF The results are sorted by department name and total compensation Here is the SELECT statement used by the application

SELECT deptname name salary + IFNULL(comm0) as compensationFROM org o staff sWHERE odeptnumb = sdeptORDER BY deptname compensation DESC

The application iterates through the selected records and prints out the data to the standard output device The sample DB2USER schema was created with the following SQL statements

db2 CONNECT TO tplx USER db2user USING mypassworddb2 CALL QSYSCREATE_SQL_SAMPLE(DB2USER)

34

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Make sure that the AIX partition is logged into with the DB2 admin user profile If the defaults were selected at the DB2 installation time this profile name is db2inst1 It is also assumed that DB2USER user exists on the iSeries server and that it has appropriate authority

There are several steps that are required to create an executable for the cursorsjsqc source code First the DB2 PRECOMPILE utility needs to be called The utility creates a bind file that is used to bind the required SQL package to the TPLX database It also converts embedded SQL statements into DB2 run-time API calls and produces a pure C source file that can be processed by an AIX C compiler

db2 CONNECT TO tplx USER db2user USING mypassworddb2 prep cursorsjsqc bindfile

Note that the connect statement is required only if the developer is not already connected to the database on an iSeries server Watch for any error or warning messages returned by the DB2 prep utility The prepare step should produce cursorsjbnd and cursorsjc files in the current directory Now the developer can invoke the bind utility to prepare the statements contained in the bind file and create the package on the target iSeries database server

db2 bind cursorsjbnd

It is assumed that Visual C++ 60 is installed and configured in the AIX partition Refer to the ldquoDeveloping and Porting C and C++ Applications on AIXrdquo redbook for more information on how to use the Visual C++ compiler httpibmcomredbooksabstractssg245674htmlOpen

Use the following commands to compile the C source generated by the precompile utility

xlc -I$INSTHOMEsqllibinclude ndashc cursorsjcxlc ndasho cursorsj cursorsjo -L$INSTHOMEsqlliblib ndashldb2

Run the program from the AIX prompt

cursorsj db2user mypassword

Distributed Join DB2 UDB Version 8 provides core federated server functionality A federated system consists of a DB2 UDB instance that operates as a federated server a database that acts as the federated database one or more data sources and clients (users and applications) that access the database and data sources Federated server permits objects stored in multiple databases to be accessed together in the same query For example a query can refer to a table that resides in DB2 UDB for iSeries and join it to a table stored in DB2 UDB for AIX Such a query would constitute so called distributed join The support for DB2 UDB for iSeries as a federated data source is provided by core federated server functionality directly implemented in DB2 UDB Enterprise Server Edition and DB2 UDB Connect Enterprise Edition All other DB2 UDB family members are also supported directly by core DB2 UDB federated server An additional software product DB2 Information Integratortrade is required to access non-DB2 UDB databases such as Oracle Sybase or Microsoftreg SQL Server Consult the following white papers for a detailed discussion on DB2 federated server support Heterogeneous data access for iSeries applications Version 2 httpibmcomserversenablesiteeducationiborecordhtmlhetdata Fundamentals of IBM DB2 Federated Server and Relational Connect httpwww7bsoftwareibmcomdmddlibrarytecharticle0206purnell0206purnellhtml

35

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Distributed Join Example In this section the steps that are required to configure DB2 UDB for iSeries as a federated data source will be illustrated Then the cursorsjsqc program will be ldquotweakedrdquo so that it executes a distributed join query that accesses data stored on an iSeries server and in the local DB2 UDB for AIX database It is assumed that the developer is familiar with the DB2 federated server concepts

Note Run the following commands from the Command Line Processor prompt Load the utility by executing the db2 command at the AIX prompt 1) First the local DB2 UDB for AIX instance needs to be enabled as a DB2 federated server

This is done by setting the database manager configuration parameter FEDERATED to YES

db2=gt update dbm cfg using FEDERATED YES

The database instance needs to be restarted for the change to take effect

NOTE A federated database is a regular database in a DB2 UDB instance that has the FEDERATED parameter enabled Therefore in this example the SAMPLE database that was created earlier is used as the federated database A new database can also be created using the CREATE DATABASE command

2) Connect to the federated database

db2=gt connect to sample

3) Use the CREATE WRAPPER statement to register a wrapper for the iSeries data source Wrappers are library routines that are used by the federated server to perform operations such as connecting to a data source and retrieving data from it The default wrapper name for DB2 UDB for iSeries is DRDA Here is the command to register the DRDA wrapper

db2=gt create wrapper drda

4) Use the CREATE SERVER statement to register a data source as a server within the federated database The server definition specifies the type and version of the data source and the wrapper used for communications with this data source For the DB2 UDB for iSeries data source the node and the database names are also needed The node and database name parameters have been configured for our TPLX database in the Configuration steps in the AIX partition section (on page 24) Use the following DB2 UDB command to lookup these parameter on the federated server

db2=gt list database directory

In this case the command produced the following output

Database alias = TPLX Database name = DCSE99E1 Node name = NDE9BF76 Database release level = a00 Comment = Directory entry type = Remote Authentication = SERVER Catalog database partition number = -1

36

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Note that the node name is set to NDE9BF76 The name was generated by the Configuration Administrator utility (db2ca)

Here is the command to register the TPLX database as a federated server

db2=gt create server tplx type db2400 version 530 wrapperdrda authorization db2user password mypassword options(nodeNDE9BF76 dbname TPLX)

The command is quite complex so make sure that the syntax is correct

5) Define the user mappings that instructs the federated server what user ID and password should be used when connecting to the iSeries data source

db2=gt create user mapping for user server tplxoptions(remote_authid db2user remote_password mypassword)

Specify the nickname for the iSeries table or view A nickname is an identifier that is used by the federated server to reference an object located at the data source The following command creates a nickname for the STAFF table located in the DB2USER schema on the TPLX database

db2=gt create nickname tplx_staff for tplxdb2userstaff

6) Test the distributed join query

db2=gt SELECT deptname name salary + COALESCE(comm0) ascompensation FROM org o tplx_staff s WHERE odeptnumb =sdept ORDER BY deptname compensation DESC

Note that the native iSeries function IFNULL has been substituted with an equivalent DB2 UDB function COALESCE COALESCE is also supported on iSeries servers For better portability IBM encourages the use of COALESCE rather than IFNULL Note also that the query runs on the federated server rather than on TPLX It accesses the ORG table in the local DB2 UDB for AIX SAMPLE database and the STAFF table that resides in TPLX The federated server performs the necessary distributed join

7) Modify the cursorsjsqc so that it executes a distributed join There are two source code modifications - Change the CONNECT TO statements Now the application needs to connect to the

federated database SAMPLE rather than to TPLX

EXEC SQL CONNECT TO SAMPLEEXEC SQL CONNECT TO SAMPLE USER userid USING passwd

- Modify the select statement so that it performs a distributed join Use the statement (shown in step 6) above Save the new source version as cursordjsqc

- Prepare bind and compile the distributed join version of the program as described in the Simple C embedded SQL application section (on page 34)

db2 prep cursordjsqc bindfiledb2 bind cursordjbndxlc -I$INSTHOMEsqllibinclude ndashc cursordjcxlc ndasho cursordj cursordjo -L$INSTHOMEsqlliblib ndashldb2

37

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

- Run the program from the AIX prompt

cursordj

Connection Pooling and Connection ConcentratorA modern Web-based application typically executes a large number of short-lived transactions Executing a transaction in this environment means establishing a database connection executing a few SQL statements and terminating this connection Creating connections to the database server is a very costly process To reduce the unnecessary workload DB2 Connect implements connection pooling and connection concentrator Connection pooling mechanism allows DB2 Connect to reuse an existing connection infrastructure for subsequent connection requests The connection concentrator is an advanced technology that allows DB2 Connect to serve a potentially very large number of clients with a limited number of database connections This is accomplished by decoupling clients from a particular database connection

Note that currently neither connection pooling nor connection concentrator support DB2 UDB for iSeries Therefore for performance reasons the author strongly recommends that the application server that obtains and drops connections very frequently implements its own database connection pooling mechanism that would assign an existing pooled database connection to a new AIX process or thread

TroubleshootingTroubleshooting a multi-tier application may be a bit tricky because the developer needs to deal with software components that reside in separate partitions The authorrsquos experience shows that two tools are particularly useful for pinning down the potential problem areas The joblog messages for a database server job usually provide enough details to isolate DB2

UDB for iSeries runtime issues The DRDA trace utility provides granular information about the data flow between the AIX

application and the iSeries server job

38

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Job Log MessagesAs mentioned earlier a DB2 client communicates with a corresponding iSeries server job This server job runs the SQL requests on behalf of the client More precisely when a DB2 client submits an SQL statement the statement is passed to a server job that in turn calls the DB2 runtime to execute the statement The results are then reformatted and marshaled to the client The iSeries DRDA server jobs are called QRWTSRVR and they run in the QUSRWRK subsystem At any given time there may be a large number of DRDA server jobs active on the system so the first step is to identify the job that serves the particular client connection The easiest method to accomplish this task is to run the following CL command from the i5OS prompt

WRKOBJLCK OBJ(DB2USER) OBJTYPE(USRPRF)

Here DB2USER is the user profile that is used to connect to the iSeries server Note that a QRWTSRVR job is assigned to a client after the connection has been established so the developer needs to set a breakpoint in the client application below the CONNECT TO statement

Once the Work with Object Locks appears key in 5 (Work with Job) next to the only QRWTSRVR job that should be listed This shows the Work with Job dialog Select option 10 to display the job log for the database server job Now the developer can search the job log for any error messages generated by the DB2 runtime

Sometimes it is also useful to include debug messages in the job log The debug messages are informational messages written to the job log about the implementation of a query They describe query implementation methods such as use of indexes join order ODP implementation (reusable versus non-reusable) and so on The easiest way to instruct the iSeries server to include the debug messages is to call the following stored procedure just after the connection to the iSeries server is established

EXEC SQL call qsysqcmdexc(STRDBGUPDPROD(YES)000000002000000)

A sample of the job log messages with debug messages enabled is shown below in Figure 20

Arrival sequence access was used for file STAFFAccess path suggestion for file STAFFQuery options used to build the OS400 query access plan Ending debug message for query ODP created Blocking used for queryCursor SQLCUR201 opened1 rows fetched from cursor SQLCUR201Row not found for SQLCUR201ODP deleted Cursor SQLCUR201 closedDESCRIBE of prepared statement STMT0201 completed

Figure 20 mdash Joblog with debug messages enabled

So the job log offers fairly detailed information on how the AIX client requests were implemented by the DB2 runtime

39

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 DRDA trace utilityThe DB2 DRDA trace utility (db2drdat) provides detailed information about the data streams exchanged between DB2 Connect and target database server The output file produced by the utility contains send and receive communications buffers TCPIP error messages and SQL Communications Area (SQLCA) information Please refer to lsquoDB2 Connect Userrsquos Guidersquo manual for in-depth discussion of the DRDA trace utility

Accessing DB2 UDB for iSeries from CLI DB2 Call Level Interface (CLI ) is based on the Microsoft Open Database Connectivity (ODBC) specification and the ISO CLI standard The DB2 CLI interface gained popularity among DB2 application providers because the developer can build an ODBC application by simply linking the application with libdb2 library on a UNIX server In other words the developer directly utilizes the DB2 ODBC driver services without a need for an ODBC driver manager Additionally in contrast to embedded SQL the developer does not need to precompile or bind DB2 CLI applications because they use packages provided with DB2 UDB The developer simply compiles and links the application

Prerequisites A DB2 CLI application running in an AIX partition will use DB2 Connect services to access DB2 UDB for iSeries therefore make sure that all components listed in Prerequisites section of this paper on page 24 are installed The developer also needs to create a remote database connection as described in the DB2 Connect configuration section of this paper on page 24

Dynamic SQL and Access Plan Caching A DB2 CLI client application uses the dynamic SQL interface and does not have the capability to utilize the extended dynamic SQL support Therefore it runs lsquopurersquo dynamic SQL statements That does not mean however that the process of parsing validating and optimizing will be repeated for every execution of a given dynamic SQL statement

The DB2 UDB for iSeries database implements an internal object called System-Wide SQL Statement Cache (SWSC) The SWSC can improve the performance of programs using dynamic SQL statements by caching the access plans in a system-wide cache When a dynamic SQL statement is submitted the SQL runtime searches the SWSC to see if this statement has been previously executed If so then DB2 retrieves and reuses the key information associated with the cached statement and thereby the processing time and the resources utilization can be significantly reduced

Simple DB2 CLI C++ ApplicationThis section covers DB2 CLI implementation details for a sample C++ program called testclicpp (the source is provided at the end of this paper in Appendix C) To compile the source with Visual C++ complier use the following command in the AIX partition

xlC ndashI$INSTHOMEsqllibinclude ndashc testclicppxlC ndasho testcli testclio ndashL$INSTHOMEsqlliblib ndashldb2

The application performs a join between STAFF and ORG tables located in DB2USER schema (library) The join statement retrieves the DEPTNAME column from ORG NAME and JOB columns from STAFF and calculates the total compensation for an employee by adding SALARY and COMM columns in STAFF The results are sorted by total compensation The selection criterion is based on the current value of the department name parameter Here is the SELECT statement used by testcli

40

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

select name job salary + coalesce(comm0) as compensationfrom org o staff swhere odeptnumb = sdeptand deptname = order by compensation desc

Figure 21 shows the software components involved in the execution of this sample application

Figure 21 How a DB2 CLI client accesses DB2 UDB on an iSeries server

Although the testcli application is fairly simple it covers some important aspects of efficient CLI programming for DB2 UDB for iSeries

Reusable Open Data Paths (ODPs)An Open Data Path (ODP) definition is an internal i5OS object that is created when certain SQL statements (such as OPEN INSERT UPDATE and DELETE) are executed for the first time in a given job (or connection) The ODP can be thought of as a runtime implementation of an access plan The access plan created at the optimization time provides a recipe or in other words a sequence of steps necessary to execute the statement The ODP on the other hand provides the executable code for all requested IO operations The process of creating new ODP objects is fairly CPU- and IO-intensive so whenever possible the iSeries DB2 runtime tries to reuse existing ODPs For instance a SQLCloseCursor() API call may close the SQL cursor but leave the ODP available to be used the next time the cursor is opened This can significantly reduce the processing and response time in running SQL statements A reusable OPD usually requires 10 to 20 times less CPU resources than a newly created ODP Therefore it is important that the applications employ programming techniques that allow the DB2 runtime to reuse ODPs

With dynamic interfaces such as CLI full opens are avoided by using a prepare once execute many programming paradigm It means that when an SQL statement is going to be executed more than once you should prepare the statement just once and then reuse the prepared

41

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

statements for consecutive executions Although DB2 UDB does try to convert literals to parameter markers so that similar statements can be reused it is a better programming practice to explicitly implement parameter markers That way the chances for reusable ODPs are quite significantly improved The code snippet in Figure 22 illustrates how to implement the prepare once execute many programming technique

Define A SELECT SQL Statementstrcpy((char ) SQLStmt select name job salary + ifnull(comm0) ascompensation )ptr = strcat( (char ) SQLStmt from org o staff s )ptr = strcat( (char ) SQLStmt where odeptnumb = sdept)ptr = strcat( (char ) SQLStmt and deptname = )ptr = strcat( (char ) SQLStmt order by compensation desc) [1]

Prepare The SQL Statementrc = SQLPrepare(ExampleStmtHandle SQLStmt SQL_NTS) [2]

Bind The Columns In The Result Data Set Returned To Application Variablesrc = SQLBindCol(ExampleStmtHandle 1 SQL_C_CHAR (SQLPOINTER)

ExampleName sizeof(ExampleName) NULL)rc = SQLBindCol(ExampleStmtHandle 2 SQL_C_CHAR (SQLPOINTER)

ExampleJob sizeof(ExampleJob) NULL)rc = SQLBindCol(ExampleStmtHandle 3 SQL_C_DOUBLE (SQLPOINTER)

ampExampleComp sizeof(ExampleComp) NULL)

for (int i = 0 i lt LOOPS i++)rc=SQLBindParameter(ExampleStmtHandle

1SQL_PARAM_INPUTSQL_C_CHARSQL_CHAR10(SQLPOINTER) currentDepartment[i8]0NULL) [3]

rc = SQLExecute(ExampleStmtHandle) [4]cout ltlt endl ltlt Current Dept ltlt currentDepartment[i8] ltlt endl Display The Results Of The SQL QueryExampleShowResults()

Figure 22 Use the prepare once execute many programming technique

The error-handling code has been removed for clarity At [1] the statement text is assigned to a variable Note that a parameter marker is used in the WHERE clause The statement is then prepared just once at [2] The current value of the parameter is bound to the prepared statement at [3] The prepared statement is executed at [4] Steps [3] and [4] are repeatedly executed in a for loop

Techniques to Further Improve DB2 CLI Performance Thus far this paper has discussed the techniques used by a sample application to tune the CLI performance However depending on the application architecture other methods of improving CLI performance may be considered

Connection PoolingCurrently the CLI application connecting through DB2 Connect to DB2 UDB for iSeries does not take advantage of the connection pooling mechanism implemented by DB2 Connect Therefore for performance reasons the author strongly recommends that the application server that obtains and drops connections very frequently implements its own database connection pooling mechanism that would assign an existing pooled database connection to a new AIX process or thread

42

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Blocking

For queries which result in returning large data blocks from the iSeries server (usually 32K of data and above) ensure that the database manager configuration parameter RQRIOBLK is set to 32767 This can be done using the Command Line Processor (CLP) as follows

db2 update database manager configuration using RQRIOBLK 32767

TroubleshootingThe experience of the author shows that two tools are particularly useful for pinning down the potential problem areas bull Joblog messages for a database server job usually provides enough details to isolate DB2

runtime issues bull CLI trace utility provides granular information about the data flow between the AIX application

and the database server job

Job Log MessagesThe process of finding and analyzing the job log for a DB2 CLI connection is identical to the process outlined for an embedded SQL application in the Job Log Message section of this paper on page 39

CLI Trace The DB2 CLIODBCJDBC trace utility provides very detailed information about the data streams exchanged between DB2 Connect and target database server Refer to the DB2 Information Center for more information on how to set up and analyze the CLI traces httppublibboulderibmcominfocenterdb2v8luwindexjsptopic=comibmdb2udbdocadc000 7959htm

43

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Trademarks

IBM eServer iSeries AIX AIX 5L i5OS WebSphere DB2 DB2 Universal Database DB2 Connect OS400 zOS OS390 Distributed Relational Database Architecture DRDA and DB2 Information Integration are trademarks or registered trademarks of International Business Machines Corporation in the United States and other countries

Java and all Java-based trademarks are trademarks of Sun Microsystems Inc in the United States other countries or both

Linux is a registered trademark of Linus Torvalds in the United States other countries or both

UNIX is a registered trademark of The Open Group in the United States and other countries

Microsoft and Windows are registered trademarks of Microsoft Corporation in the United States andor other countries

All other registered trademarks and trademarks are properties of their respective owners

IBM makes no commitment to make available any products referred to herein

References in this publication to IBM products or services do not imply that IBM intends to make them available in every country in which IBM operates

Additional Information ITSO offers a Redbook that can be helpful to those who want to learn more about i5OS AIX integration

bull AIX Integration with I5OS on the IBM eServer iSeries Server (SG24-6551)

Jarek Miszczyk is the Senior Software Engineer IBM eServer Solutions Enablement IBM Rochester

[Portions of this white paper reprinted with permission from MC Mag Online published by MC Press LLP httpwwwmcpressonlinecom]

Acknowledgments The author would like to thank the following people for their advice contributions and support on this paper

Bob Bittner IBM Rochester Jon Rush IBM Rochester Prasad Vallurupalli IBM Rochester Neil Willis IBM Rochester

44

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix A Source Listing of TestJDBCjava

package comibmiseriespwdimport javasqlimport javaxnamingimport javautilHashtableimport javautilimport javaxsqlimport comibmas400access

public class TestJDBC public static void main(javalangString[] args)

throws Exception

int numOfLoops = 5000int outerNumOfLoops = 5boolean firstExec = trueConnection conStatement sPreparedStatement psPreparedStatement pstmtdelCallableStatement cstmPreparedStatement pstmtHashtable env = new Hashtable()

envput(ContextINITIAL_CONTEXT_FACTORYcomsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env)Systemoutprintln(Deploying connection pooling data source)deployDataSource() Do the work with connection pooling onlyAS400JDBCConnectionPoolDataSource tkcpds =

(AS400JDBCConnectionPoolDataSource)ctxlookup(jdbcToolkitDataSource) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPool pool = new AS400JDBCConnectionPool(tkcpds) Adds 1 connection to the pool that can be used by theapplication (creates the physical database connections based onthe data source)poolfill(1)Systemoutprintln(nStart timing Toolkit connection pooling)long startTime = SystemcurrentTimeMillis()

for (int i = 0 i lt outerNumOfLoops i++) con = poolgetConnection()consetAutoCommit(false) deleteif ( i == 0)

long startDelete = SystemcurrentTimeMillis()cstm = cstm = conprepareCall(

CALL qsysqcmdexc(CLRPFM FILE(DB2USERCOFFEES) + 000000002800000))

cstmexecuteUpdate()cstmclose()long endDelete = SystemcurrentTimeMillis()Systemoutprintln(Delete all records +

(endDelete - startDelete) + ms elapsed)

45

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

String sqlinstrlong startInsert = SystemcurrentTimeMillis() insert

pstmt =conprepareStatement(INSERT INTO COFFEES VALUES( ))for (int j = 0 j lt numOfLoops j++) pstmtsetString(1 Kona_ + IntegertoString(i))pstmtsetInt(2 150)pstmtsetFloat(3 999f)pstmtsetInt(4 0)pstmtsetInt(5 0)pstmtaddBatch()int [] updateCounts = pstmtexecuteBatch()concommit()pstmtclose()long endInsert = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for + numOfLoops + inserts

+ (endInsert - startInsert)) selectlong startSelect = SystemcurrentTimeMillis()ps = conprepareStatement(SELECT FROM COFFEES)ResultSet rs = psexecuteQuery()rsnext()rsclose()concommit()psclose()long endSelect = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for select +

(endSelect - startSelect))consetAutoCommit(true)conclose()long endTime = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for + outerNumOfLoops +

loops + (endTime - startTime))Systemexit(0)

private static void deployDataSource()throws ExceptionString serverName = teraplex String databaseName = TERAPLEX String userName = db2user String password = db2pwd

Establish a JNDI context and bind the connection pool data sourceHashtable env = new Hashtable()envput(ContextINITIAL_CONTEXT_FACTORY

comsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPoolDataSource tkcpds = new

AS400JDBCConnectionPoolDataSource()tkcpdssetServerName(serverName) tkcpdssetDatabaseName(databaseName) tkcpdssetUser(userName) tkcpdssetPassword(password) tkcpdssetDescription(Toolkit Connection Pooling DataSource)tkcpdssetSavePasswordWhenSerialized(true)tkcpdssetExtendedDynamic(true)

46

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

tkcpdssetPackage(JDBCDS)tkcpdssetPackageCache(true)tkcpdssetPackageCriteria(select)enable the following properties as requiredcpdssetTrace(true)tkcpdssetServerTraceCategories( AS400JDBCDataSourceSERVER_TRACE_DEBUG_SERVER_JOB)

ctxrebind(jdbcToolkitDataSource tkcpds)

47

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix B mdash Source Listing of cursorsjsqc

Source File Name = cursorsjsqc Licensed Materials - Property of IBM (C) COPYRIGHT International Business Machines Corp 1995 2000 2004 All Rights Reserved US Government Users Restricted Rights - Use duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp PURPOSE This sample program demonstrates the use of a CURSOR The CURSOR is processed using static SQL EXTERNAL DEPENDENCIES - Ensure existence of database for precompile purposes - Precompile with the SQL precompiler (PREP in DB2) - Bind to a database (BIND in DB2) - Compile and link with the IBM Cset++ compiler (AIX and OS2) or the Microsoft Visual C++ compiler (Windows) or the compiler supported on your platform For more information about these samples see the README file For more information on programming in C see the - Programming in C and C++ section of the Application Development Guide For more information on building C applications see the - Building C Applications section of the Application Building Guide For more information on the SQL language see the SQL Reference

include ltstdiohgt include ltstdlibhgt include ltstringhgtinclude ltsqlhgtinclude ltsqlenvhgtinclude ltsqldahgtinclude ltsqlcahgt

int SqlInfoPrint( char struct sqlca int char )void TransRollback( void)

define EMB_SQL_CHECK( MSG_STR ) rc = SqlInfoPrint( MSG_STR ampsqlca __LINE__ __FILE__) if ( rc = 0 ) TransRollback( )

return 1

EXEC SQL INCLUDE SQLCA

int main(int argc char argv[])

EXEC SQL BEGIN DECLARE SECTIONchar dname[15]

48

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

char pname[10]double compchar userid[9]char passwd[19]

EXEC SQL END DECLARE SECTION

int rc = 0printf( Sample C program CURSORSJ n )if (argc == 1)

EXEC SQL CONNECT TO TPLXEMB_SQL_CHECK(CONNECT TO TPLX)

else if (argc == 3)

strcpy (userid argv[1])strcpy (passwd argv[2])EXEC SQL CONNECT TO TPLX USER userid USING passwdEMB_SQL_CHECK(CONNECT TO TPLX)

else

printf (nUSAGE cursor [userid passwd]nn)return 1

endif

EXEC SQL DECLARE c1 CURSOR FORselect deptname name salary + ifnull(comm0) as compensationfrom org o staff swhere odeptnumb = sdeptorder by deptname compensation desc

EXEC SQL OPEN c1EMB_SQL_CHECK(OPEN CURSOR)

printf(DEPARTMENT NAME COMPENSn)printf(-----------------------------------n)do

EXEC SQL FETCH c1 INTO dname pname compif (SQLCODE = 0) breakprintf( -1515s -1010s 72fn dname pname comp )

while ( 1 )

EXEC SQL CLOSE c1EMB_SQL_CHECK(CLOSE CURSOR)

EXEC SQL CONNECT RESETEMB_SQL_CHECK(CONNECT RESET)

exit(0)

end of program CURSORSJSQC

int SqlInfoPrint( char appMsgstruct sqlca pSqlcaint linechar file )

int rc = 0char sqlInfo[1024]char sqlInfoToken[1024]char sqlstateMsg[1024]char errorMsg[1024]

if (pSqlca-gtsqlcode = 0 ampamp pSqlca-gtsqlcode = 100)

49

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

strcpy(sqlInfo )if( pSqlca-gtsqlcode lt 0) sprintf( sqlInfoToken n---- error report ----n)

strcat( sqlInfo sqlInfoToken)else sprintf( sqlInfoToken n---- warning report ----n)

strcat( sqlInfo sqlInfoToken) endif

sprintf( sqlInfoToken app message = sn appMsg)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken line = dn line)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken file = sn file)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken SQLCODE = ldn pSqlca-gtsqlcode)strcat( sqlInfo sqlInfoToken)

get error message rc = sqlaintp( errorMsg 1024 80 pSqlca) return code is the length of the errorMsg string if( rc gt 0) sprintf( sqlInfoToken sn errorMsg)

strcat( sqlInfo sqlInfoToken)

get SQLSTATE message rc = sqlogstt( sqlstateMsg 1024 80 pSqlca-gtsqlstate)if (rc == 0) sprintf( sqlInfoToken sn sqlstateMsg)

strcat( sqlInfo sqlInfoToken)

if( pSqlca-gtsqlcode lt 0) sprintf( sqlInfoToken --- end error report ---n)

strcat( sqlInfo sqlInfoToken)printf(s sqlInfo)return 1

else sprintf( sqlInfoToken --- end warning report ---n)

strcat( sqlInfo sqlInfoToken)printf(s sqlInfo)return 0

endif endif

return 0

void TransRollback( ) struct sqlca sqlca

int rc = 0 rollback the transaction printf( nRolling back the transaction n)

EXEC SQL ROLLBACKrc = SqlInfoPrint( ROLLBACK ampsqlca __LINE__ __FILE__)if( rc == 0) printf( The transaction was rolled backn)

50

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

51

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix C mdash Source Listing of testclicpp

Include The Appropriate Header Filesinclude ltsqlclihgtinclude ltsqlcli1hgtinclude ltsqlutilhgtinclude ltsqlenvhgtinclude ltstdiohgt include ltiostreamgt include ltlocalehgt include ltstringhgtdefine SQL_SQLSTATE_SIZE 5define LOOPS 8

using namespace std

Define The CLI_Class Classclass CLI_Class

Attributespublic

SQLHANDLE EnvHandleSQLHANDLE ConHandleSQLHANDLE StmtHandleSQLRETURN rcSQLCHAR Job[6]SQLCHAR Name[10]SQLDOUBLE Comp

Operationspublic

CLI_Class()~CLI_Class()SQLRETURN ShowResults()

Constructor Destructor

SQLRETURN printError( SQLHDBC SQLHSTMT)

Define The Class ConstructorCLI_ClassCLI_Class()

setlocale( LC_ALL )

Initialize The Return Code Variablerc = SQL_SUCCESS

Allocate An Environment Handlerc = SQLAllocHandle(SQL_HANDLE_ENV SQL_NULL_HANDLE ampEnvHandle)

Allocate A Connection Handleif (rc == SQL_SUCCESS)

rc = SQLAllocHandle(SQL_HANDLE_DBC EnvHandle ampConHandle)

Define The Class DestructorCLI_Class~CLI_Class()

Free The Connection Handleif (ConHandle = NULL)

SQLFreeHandle(SQL_HANDLE_DBC ConHandle)

Free The Environment Handle

52

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

if (EnvHandle = NULL)SQLFreeHandle(SQL_HANDLE_ENV EnvHandle)

Define The ShowResults() Member FunctionSQLRETURN CLI_ClassShowResults(void)

While There Are Records In The Result Data Set Generated Retrieve And Display Themcout ltlt Name Job Compensation ltlt endlcout ltlt --------- ------ ------------ ltlt endlcoutsetf(iosleft)coutprecision(2)coutsetf(iosfixed)while (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)

rc = SQLFetch(StmtHandle)if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)

coutwidth(15)cout ltlt Name

coutwidth(10)cout ltlt Job

coutwidth(7)cout ltlt Comp ltltendl

if(rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO ampamp rc = SQL_NO_DATA)printError(ConHandle StmtHandle)

else

rc = 0SQLCloseCursor(StmtHandle)

Return The ODBC API Return Code To The Calling Functionreturn(rc)

SQLRETURN CLI_ClassprintError (SQLHDBC hdbc

SQLHSTMT hstmt)

SQLCHAR buffer[SQL_MAX_MESSAGE_LENGTH + 1]SQLCHAR sqlstate[SQL_SQLSTATE_SIZE + 1]SQLINTEGER sqlcodeSQLSMALLINT lengthSQLRETURN rcwhile ((rc = SQLError(SQL_NULL_HENV hdbc hstmt

sqlstateampsqlcodebufferSQL_MAX_MESSAGE_LENGTH + 1amplength)) == SQL_SUCCESS || rc ==

SQL_SUCCESS_WITH_INFO)

cout ltlt SQLSTATE ltlt sqlstate ltlt endlcout ltlt SQLCODE ltlt sqlcode ltlt endlcout ltlt Error msg ltlt buffer ltlt endl

53

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

cout ltlt----------------------------- ltlt endl ltlt endl

return(SQL_ERROR)

----------------------------------------------------------------- The Main Function -----------------------------------------------------------------int main()

Declare The Local Memory Variables

(SQLCHAR ) db2user SQL_NTS (SQLCHAR ) test26t SQL_NTS)

SQLRETURNSQLCHARSQLCHARSQLCHARchar

SQLCHAR

rc = SQL_SUCCESSDBName[10] = TPLXSQLStmt[255]c[10]ptrcurrentDepartment[8][15] = Head Office

New England Mid Atlantic South Atlantic Great Lakes PlainsPacificMountain

Create An Instance Of The CLI_Class ClassCLI_Class Example

Connect To iSeries Database if (ExampleConHandle = NULL)

rc = SQLConnect(ExampleConHandle DBName SQL_NTS

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)ExampleprintError(ExampleConHandle SQL_NULL_HSTMT)

return(rc)

cout ltlt Successfully connected to ltlt DBName ltlt ltlt endlrc = SQLSetConnectAttr(ExampleConHandle SQL_ATTR_AUTOCOMMIT

(SQLPOINTER) SQL_AUTOCOMMIT_OFF SQL_IS_UINTEGER) Allocate An SQL Statement Handlerc = SQLAllocHandle(SQL_HANDLE_STMT ExampleConHandle

ampExampleStmtHandle)if (rc == SQL_SUCCESS)

Define A SELECT SQL Statement

strcpy((char ) SQLStmt select name job salary + ifnull(comm0) ascompensation )

ptr = strcat( (char ) SQLStmt from org o staff s )ptr = strcat( (char ) SQLStmt where odeptnumb = sdept)ptr = strcat( (char ) SQLStmt and deptname = )ptr = strcat( (char ) SQLStmt order by compensation desc)

Prepare The SQL Statementrc = SQLPrepare(ExampleStmtHandle SQLStmt SQL_NTS)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)ExampleprintError(ExampleConHandle ExampleStmtHandle)

54

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

return(rc)

Bind The Columns In The Result Data Set Returned To Application Variables

rc = SQLBindCol(ExampleStmtHandle 1 SQL_C_CHAR (SQLPOINTER)ExampleName sizeof(ExampleName) NULL)

rc = SQLBindCol(ExampleStmtHandle 2 SQL_C_CHAR (SQLPOINTER)ExampleJob sizeof(ExampleJob) NULL)

rc = SQLBindCol(ExampleStmtHandle 3 SQL_C_DOUBLE (SQLPOINTER)ampExampleComp sizeof(ExampleComp) NULL)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO) ExampleprintError(ExampleConHandle ExampleStmtHandle)

return(rc)

while (true)

for (int i = 0 i lt LOOPS i++)

rc=SQLBindParameter(ExampleStmtHandle1SQL_PARAM_INPUTSQL_C_CHARSQL_CHAR

150(SQLPOINTER) currentDepartment[i8]0NULL)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)

ExampleprintError(ExampleConHandle ExampleStmtHandle)return(rc)

rc = SQLExecute(ExampleStmtHandle)if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)

ExampleprintError(ExampleConHandle ExampleStmtHandle)return(rc)

cout ltlt endl ltlt Current Dept ltlt currentDepartment[i8] ltlt

endl Display The Results Of The SQL QueryExampleShowResults()if(rc = 0)break

if ( i500 == 0 ampamp i gt 0 )cout ltlt Loops ltlt i ltlt ltlt endl

cout ltlt AFTER ltlt LOOPS ltlt loops Press X to exit ltlt endlcin gtgt cif (c[0] == x || c[0] == X)

break

Free The SQL Statement Handleif (ExampleStmtHandle = NULL )

SQLFreeHandle(SQL_HANDLE_STMT ExampleStmtHandle) Disconnect From The Northwind Sample Databaserc = SQLDisconnect(ExampleConHandle)

Return To The Operating Systemreturn(rc)

55

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 1 - DB2 UDB for iSeries SQL runtime

DB2 SQL Runtime Interfaces Letrsquos briefly discuss the DB2 SQL runtime interfaces

Static SQL

The SQL statements are embedded in the source code of a host application program For example a stored procedure can be written in C++ and contains a number of embedded SQL statements In this case the stored procedure source code has to be processed by an SQL preshycompiler prior to compiling the host application program itself At that time the embedded SQL statements are parsed validated and optimized As a result of this process an access plan gets created for each statement The access plan is a control structure that contains information on the actions necessary to satisfy an SQL request Typically it contains

bull An access method that the optimizer selected for a given statement (for example table scan)

bull Information on associated tables and indexes that is used at runtime to determine if an access plan needs to be rebuilt due to table changes or index changes

bull Any applicable environment information such as jobrsquos code page

The access plan is then permanently stored in the program object and can be reused when the program is executed

In another scenario an embedded SQL application may be executed on a client for example in an AIX partition and access the DB2 UDB for iSeries through DB2 Connect In this case a client-side DB2 SQL precompiler stores the static SQL statements in a bind file The bind file is then

2

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

bound to the back-end database server The bind process creates an SQL package on the DB2 UDB for iSeries The package contains the access plans and other control structures that can be reused when the client program executes

Static SQL is the most efficient way to process SQL requests on an iSeries server

Dynamic SQL Dynamic SQL statements are parsed validated and optimized at the time an SQL application is executed The SQL statements are passed to the database manager in the form of a character string using the SQL statements PREPARE or EXECUTE IMMEDIATE The IBM Toolbox for JavaJTOpen JDBC driver uses this method if Extended Dynamic SQL support is not enabled The Dynamic SQL is also used by the dynamic SQL interfaces such as DB2 Call Level Interface (DB2 CLI) ODBC and JDBC when a client application connects to DB2 UDB for iSeries through DB2 Connect gateway Refer to DB2 Connect data access on page 22 of this paper for more details

Extended Dynamic SQL In Extended Dynamic SQL the SQL statements are dynamic However SQL packages are used to make the implementation of the dynamic SQL statements similar to that of static SQL The SQL statements are parsed validated and optimized and the resulting access plan is permanently stored in a SQL package Note that this process is dynamic and new statements can be added to the SQL package at the run time The IBM Toolbox for JavaJTOpen JDBC driver can take advantage of the Extended Dynamic SQL support

3

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

JDBC Data Access This section provides implementation tips and coding examples that illustrate how to optimize the access to your DB2 UDB for iSeries database from a AIX partition by using various JDBC drivers Currently IBM offers several AIX-enabled JDBC drivers that support DB2 UDB for iSeries

bull Type 4 drivers mdash IBM Toolbox for Java JTOpen and DB2 Universal JDBC Driver bull Type 2 driver mdash DB2 JDBC Type 2 Driver

The IBM Toolbox for Java iSeries driver has been implemented in pure Javatrade and optimized for accessing DB2 UDB for iSeries data It uses native iSeries protocol to communicate with the back-end database server job JTOpen is the open-source version of the IBM Toolbox for Java Licensed Program Product (LPP)

The DB2 Universal JDBC Driver is also a pure Java implementation It is a part of the DB2 UDB for AIX Version 8 product and it uses the Distributed Relational Database Architecture (DRDA) protocol for clientserver communications The driver is compatible with various DB2 UDB server platforms with appropriate DRDA Application Server (AS) level support and prerequisite stored procedures It also supports Type 2 connectivity when accessing DB2 UDB for Linuxreg UNIX and Windowsreg (DB2 UDB for LUW) databases

The traditional DB2 JDBC Type 2 Driver is built on top of DB2 Call Level Interface (CLI) It requires DB2 Connect functionality to access DB2 UDB for iSeries This is a legacy driver and IBM currently recommends that the DB2 Universal JDBC driver is used instead

Initial Configuration Considerations Practical experience shows that the JDBC application performance greatly depends on the programming techniques and the SQL access tuning However significant performance gains can be achieved by simply tweaking the AIX partition environment For example a virtual LAN connection to the back-end database can significantly streamline the data flow

4

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Virtual Versus Physical LAN One of the most significant benefits of installing AIX in an iSeries partition is the ability to utilize virtual LAN and virtual DASD This usually results in reduced hardware costs through improvements in data transfer performance and enhanced disk protection The performance tests conducted by the IBM eServer Solutions Enablement team showed that the Virtual 1Gb LAN delivered a data throughput similar to dedicated 1Gb Ethernet adapters (model 5706) connected via a dedicated Ethernet segment An example configuration is illustrated in Figure 2

Figure 2 VLAN vs 1 Gb Ethernet IOA configuration

Although similar performance can be expected for VLAN and 1Gb Ethernet the VLAN configuration has two advantages over the physical LAN connection

bull No additional communications gear is required bull It is a dedicated point-to-point connection so there is no interference from other devices on

the same network segment

On the other hand certain application scenarios may benefit from a physical LAN adapter dedicated to an AIX partition For instance in a three-tier application architecture clients connect to an application server running in a AIX partition The application server in turn connects to DB2 UDB for iSeries where data is stored and retrieved In this case configuring a separate physical LAN connection in a AIX partition has the following advantages

bull An unnecessary additional hop is eliminated from the network route bull Client-application server traffic does not unnecessarily saturate i5OS communications gear

5

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Tuning DB2 UDB for iSeries Access with IBM Toolbox for Java and JTOpen Driver This section covers JDBC implementation details for a sample Java program called TestJDBC (the source is provided at the end of this paper in Appendix A) The application uses the Java Naming and Directory Interface (JNDI) to obtain a database connection deletes 5000 records generates and inserts 5000 records and finally retrieves the newly inserted records from an SQL table called COFFEES The application executes in an AIX partition and accesses the DB2 UDB for iSeries through the JTOpen (or IBM Toolbox for Java) driver Figure 3 shows the software components involved in the execution of this simple application

Figure 3 JDBC client accessing DB2 UDB for iSeries

Apart from the JTOpen driver which can be downloaded from the IBM Toolbox for Java Web site you need three other JAR files to successfully compile and execute the JDBCTest application in a AIX partition

bull providerutiljar and fscontextjar mdashDownload a simple file system JNDI provider from Sun Microsystems JNDI Web site httpjavasuncomproductsjndidownloadsindexhtml

bull jdbc2_0-stdextjar mdash Copy the javaxsql package from the QIBMUserDataJava400ext IFS directory on the iSeries server

The location of the JAR files needs to be added to the CLASSPATH environment variable For instance the following entry could be added to the AIX profile script

6

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

CLASSPATH=homecodeJTOpenjt400jarCLASSPATH=$CLASSPATHhomecodefscontextproviderutiljarCLASSPATH=$CLASSPATHhomecodefscontextfscontextjarCLASSPATH=$CLASSPATHhomecodeJTOpenjdbc2_0-stdextjarexport CLASSPATH

To compile the source use the following command in the AIX partition

javac TestJDBCjava

Although the TestJDBC application is fairly simple it illustrates several important aspects of efficient JDBC programming for DB2 UDB for iSeries

Connection PoolingA JDBC connection can be obtained through either the DataSource or DriverManager object Either method involves significant overhead A fairly large amount of system resources is required to create and maintain the connection and then release it when it is no longer needed JTOpen allows a developer to establish a pool of database connections that can be shared by multiple client applications Connection pooling can improve the response time because the connection pool manager can locate and use an existing connection When the database request is completed the connection returns to the connection pool for reuse

In the JDBCTest sample JNDI was first used to register a connection pool-capable data source Heres an excerpt from the deployDataSource method of the sample application

Hashtable env = new Hashtable()envput(ContextINITIAL_CONTEXT_FACTORY

comsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env) [1]

Register an AS400JDBCConnectionPoolDataSource objectAS400JDBCConnectionPoolDataSource tkcpds = newAS400JDBCConnectionPoolDataSource() [2]tkcpdssetServerName(serverName) tkcpdssetDatabaseName(databaseName) tkcpdssetUser(userName) tkcpdssetPassword(password) tkcpdssetDescription(Toolkit Connection Pooling DataSourceobject) hellip ctxrebind(jdbcToolkitDataSource tkcpds) [3]

At [1] the initial JNDI context is created

Then at [2] an AS400JDBCConnectionPoolDataSource object is instantiated This is the JTOpen implementation of the javaxsqlConnectionPoolDataSource interface An AS400JDBCConnectionPoolDataSource object supports a number of methods that can be used to set iSeries-specific properties of the underlying DataSource object Some of these properties will be discussed in greater detail in the following sections of this paper

At [3] the data source object is bound to an arbitrary name that will be used in the main application Note that the deployDataSource method needs to be executed just once unless some of the data source properties need to be changed In that case the developer would need to rebind

7

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

The JNDI registered data source is then used in the main application to initialize the connection pool

AS400JDBCConnectionPoolDataSource tkcpds = [1](AS400JDBCConnectionPoolDataSource)ctxlookup(jdbcToolkitDataSource) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPool pool = newAS400JDBCConnectionPool(tkcpds)[2] Adds 1 connection to the pool that can be used by the application(creates the physical database connections based on the datasource)poolfill(1) [3] hellip con = poolgetConnection()[4]

At [1] the JNDI service is used to instantiate the AS400JDBCConnectionPoolDataSource

Then at [2] an AS400JDBCConnectionPool object is created This object is responsible for managing the connection pool

At [3] the connection pool is initialized with one connection

The pool object is used at [4] to obtain a database connection There are several additional things the developer should know about this code snippet

bull The advantage of using JNDI to register the data source object as opposed to just instantiating it in the main method is that in a more realistic scenario the data source would be registered just once at application deployment time Additionally the data source properties do not have to be hard-coded in the main method and can be changed at any time and then rebound without affecting the application

bull The AS400JDBCConnectionPool is a proprietary JTOpen implementation of a connection pool Specifically it does not implement the Referenceable interface and thus cannot be bound through JNDI services

bull The JTOpen AS400JDBCConnectionPoolDataSource does not support statement caching as described in the JDBC 30 specification Statement caching is implemented through SQL packages This feature is covered in the following section

Note The native iSeries JDBC driver supports both connection pooling and statement caching in a JDBC 30 compliant manner

8

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Extended Dynamic SQL and Statement Caching As mentioned the JTOpen data source object supports a number of properties that can be used to fine-tune the database performance In this section properties used to enable extended dynamic SQL support (see DB2 SQL Runtime Interfaces section above) and local statement caching will be discussed

Here is a relevant code excerpt from the deployDataSource method

AS400JDBCConnectionPoolDataSource tkcpds = new AS400JDBCConnectionPoolDataSource() hellip tkcpdssetExtendedDynamic(true)[1]tkcpdssetPackage(JDBCDS) [2]tkcpdssetPackageCache(true) [3]tkcpdssetPackageCriteria(select) [4]

At [1] the extended dynamic SQL support is enabled Note that the default is disabled for JTOpen The extended dynamic SQL functionality is often referred to as SQL package support The SQL packages are server-side repositories for SQL statements Packages contain the internal structures such as parse trees and access plans which are needed to execute SQL statements Because SQL packages are a shared resource the information built when a statement is prepared is available to all the users of the package This saves processing time especially in an environment where many users are using the same or similar statements Also because SQL packages are permanent this information is saved across job initiationtermination and IPLs In fact SQL packages can be saved and restored on other servers

At [2] the SQL package is named Note that the actual package name on the iSeries server is JDBCDSBAA The package name is generated by taking the name specified on the client and appending three letters that are an encoded set of the package configuration attributes By default an SQL package does not contain unparameterized select statements This behavior is overridden at [4] by setting the PackageCriteria property to select

At [3] the local statement cache is enabled A copy of the SQL package is cached on the AIX client This may improve application performance in a way similar to JDBC 30 statement caching Note however that local statement caching is not recommended for large SQL packages The copy of an SQL package is cached when the database connection is obtained This may cause increased network traffic as well as slow down the connection setup time

Reusable Open Data Paths (ODPs)An Open Data Path (ODP) definition is an internal i5OS object that is created when certain SQL statements (such as OPEN INSERT UPDATE and DELETE) are executed for the first time in a given job (or connection) The ODP can be thought of as a runtime implementation of an access plan The access plan created at the optimization time provides a recipe or in other words a sequence of steps necessary to execute the statement The ODP on the other hand provides the executable code for all requested IO operations The process of creating new ODP objects is fairly CPU- and IO-intensive so whenever possible the iSeries DB2 runtime tries to reuse existing ODPs For instance a ResultSetclose() call may close the SQL cursor but leave the ODP available to be used the next time the cursor is opened This can significantly reduce the response time in running SQL statements A reusable OPD usually requires 10 to 20 times less CPU resources than a newly created ODP Therefore it is important that the applications employ programming techniques that allow the DB2 runtime to reuse ODPs

With dynamic programming interfaces such as JDBC the most efficient way to avoid full opens is to employ the so-called prepare once execute many programming paradigm Ideally an SQL statement that is executed more than once should be prepared just once mdashfor example in the class constructor mdash and then reused for the consecutive executions At the prepare time the

9

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 engine stores the prepared statement along with the associated statement name in the QZDASOINIT jobs statement cache On the first execution the ODP created for a given statement is associated with the appropriate entry in the statement cache On consecutive executions the prepared statement and the corresponding ODP can be quickly located in the statement cache and reused The code snippet below illustrates the prepare once execute many programming technique

PreparedStatement pstmt = conprepareStatement(INSERT INTO COFFEES VALUES( ))[1] hellip for (int i = 0 i lt outerNumOfLoops i++)

insertfor (int j = 0 j lt numOfLoops j++)

pstmtsetString(1 Lavaza_ + IntegertoString(j)) hellip pstmtaddBatch()

int [] updateCounts = pstmtexecuteBatch()[2]concommit()

At [1] a PreparedStatement pstmt object is instantiated for a parameterized INSERT statement The statement is prepared just once The PreparedStatement object is then repeatedly used at [2] to perform blocked insert

Block Inserts Occasionally the developer may need to initially populate a table or insert a modified result set into a temporary table The efficiency of the insert operation for a large set of records can be dramatically improved by using the executeBatch method rather than the executeUpdate method The JTOpen driver converts parameterized insert statements in an executeBatch method to a block insert statement This significantly reduces the data flow and system resources required to perform the insert The following code snippet shows how to take advantage of the executeBatch method

10

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

PreparedStatement pstmt =conprepareStatement(INSERT INTO COFFEES VALUES( ))[1]for (int j = 0 j lt numOfLoops j++) pstmtsetString(1 Lavaza_ + IntegertoString(j))pstmtsetInt(2 i)pstmtsetFloat(3 499f)pstmtsetInt(4 0)pstmtsetInt(5 0)pstmtaddBatch() [2]

int [] updateCounts = pstmtexecuteBatch() [3]

At [1] a parameterized insert statement is prepared Note that all columns must be parameterized Otherwise the executeBatch method may throw the SQL0221 Number of rows 1 not valid exception In other words the developer should not mix parameter markers with literals or special registers in the VALUE clause

At [2] the addBatch method is used to add a new record to the client record buffer

At [3] all locally buffered data is sent to the server which in turn performs a block insert

Figure 4 shows the performance data for the executeBatch and executeUpdate methods

Figure 4 executeBatch() versus executeUpdate() performance comparison

11

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

WebSphere Considerations In certain situations an application provider may decide to deploy WebSphere Application Server in an AIX partition rather than natively in i5OS At the same time the application uses DB2 UDB for iSeries as an back-end database server Typically the WebSphere Application Server running in the AIX partition uses the virtual LAN to communicate with DB2 UDB for iSeries The WebSphere applications will access the database through a remote JDBC connection For performance and functionality reasons IBM recommends to utilize in such environments the IBM Toolbox for Java JTOpen driver Most of the tips and techniques described so far in this document hold true for WebSphere applications accessing DB2 UDB for iSeries There are however certain JDBC access aspects that are specific to this multi-tier architecture Letrsquos have a closer look at some of these considerations

Connection Pooling and Statement Caching

WebSphere Application Server provides its own connection pooling and statement caching mechanism that is by default enabled so that WebSphere applications automatically enjoy the performance benefits of these two critical programming techniques See the following link to learn more about the optimal connection pool setting in WebSphere

httppublibboulderibmcomwas40051englishinforzaiz51adminhelpudat_conpoolsethtml

Extended Dynamic SQL

For non-JTA connections WebSphere Application Server uses the comibmas400accessAS400JDBCConnectionPoolDataSource class as the iSeries JDBC provider implementation This is the DataSource implementation that has been used in all previous coding examples As mentioned the class supports a range of iSeries specific properties that can be used to fine tune JDBC performance These properties can be set through the WebSphere Application Server admin console For example herersquos the procedure to enable the extended dynamic SQL support In the WebSphere Application Server admin console navigate to the Data Source configuration dialog by selecting JDBC Providers -gt iSeriesToolbox -gt Data Sources then scroll down to the Additional Properties section Select Custom Properties link The Custom Properties dialog opens Scroll down to find the Extended Dynamic property and select it Change the default value false to true save the new configuration by clicking Apply button This is illustrated in Figure 5

12

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 5 Enabling the extended dynamic SQL through WebSphere Application Server console

The WebSphere Application Server needs to be restarted for the change to take effect The similar procedure can be followed to set other iSeries Data Source properties

Changing the WebSphere Application Server default isolation level

WebSphere Application Server V5 uses the REPEATABLE_READ (RR) isolation level for all implicit (WebSphere Application Server managed) transactions With the RR isolation level the rows selected updated deleted and inserted are locked until the end of the transaction Under certain circumstances this fairly extensive locking policy may cause locking contention especially when a WebSphere application competes for database resources with other applications that run on iSeries server For example a legacy order entry application may share data with the e-business customer care application running in WebSphere The locking contention may sometimes be eliminated by lowering the isolation level used by WebSphere Although the iSeries Data Source supports the custom transactionIsolation property resetting this property on the Data Source object will not change the default isolation level used by WebSphere for the connection objects produced by that Data Source In other words WebSphere will override the Data Source isolation level setting at the time the connection is obtained by a WebSphere application object such as servlet or Enterprise Java Bean (EJB) In order to change the default WebSphere behavior one must use the resource referencing Resource referencing allows a programmer to lookup DataSource or EJB objects using alias names rather than JNDI names Additionally by creating a resource reference a programmer can change certain properties of the underlying object Specifically a DataSource reference can be used to set a different isolation level for the connections produced by this database resource Typically resource references are defined by a programmer in a application development tool such as WebSphere Studio Application Developer The method to specify a DataSource reference differs depending on whether a programmer plans to use the reference in a servlet or in an EJB Letrsquos start with outlining the configuration process for a servlet In WebSphere Studio Application Developer open the deployment descriptor editor for the web project that contains the servlet To do so double click on the webxml file under WEB-INF directory in the web project In the deployment editor dialog select the References tab and then select Resource tab located in the top of the dialog that appears Under Resource References section select the Add button Herersquos an example of a DataSource reference created for iSeries DataSource named TestJDBCDS Note that the reference changes the default isolation level to READ_COMMITTED

13

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 6 Defining a resource reference for a servlet

Once the resource reference has been defined and saved the servlet source code needs to be changed to reflect the fact that a resource reference is used to obtain a DataSource from the JNDI service Herersquos the relevant code snippet try

ctx = new InitialContext() ds = (DataSource)ctxlookup(javacompenvTestJDBCJ2C)

catch (Exception e) eprintStackTrace(out)

Now the ds DataSource object will produce connections that by default run with the isolation level of READ_COMMITTED (RC)

As mentioned the process of defining a resource reference for an EJB differs from the process that is used in the case of a servlet In WebSphere Studio Application Developer open the deployment descriptor editor for the EJB project that contains the EJB To do so double click on the ejb-jarxml file under WEB-INF directory in the project In the deployment editor dialog select the References tab In the references section on the left locate and select the EJB for which the developer wants to change the default isolation level Click the Add button The Add Reference dialog opens Click the Resource Reference radio button and then Next Define the reference following the example shown in Figure 7

14

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 7 Adding a resource reference for an EJB

When you click ldquoFinishrdquo the reference definition is added to the EJB descriptor The new definition needs to be further modified To do so click on the (+) sign next to the EJB in the References list Click the new reference TestJDBCJ2C in this example to open the properties for the reference Change WebSphere Bindings and WebSphere Extensions sections as illustrated in Figure 8

15

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 8 Defining a resource reference for an EJB

Save the modified definition and then change the EJB source code to use the reference rather than directly DataSource

TroubleshootingTroubleshooting a multi-tier application may be a bit tricky because the developer needs to deal with software components that reside in separate partitions Three tools are particularly useful for pinning down the potential problem areas bull Joblog messages for a database server job mdash Provides enough details to isolate DB2 UDB for

iSeries runtime issues bull JDBC trace utility mdash Provides granular information about the data flow between the AIX

application and the iSeries server job bull Database Monitor ndash Provides detailed SQL runtime trace

Job Log MessagesAs mentioned a DB2 client communicates with a corresponding iSeries server job This server job runs the SQL requests on behalf of the client The iSeries database server jobs are called QZDASOINIT and they run in the QUSRWRK subsystem At any given time a large number of database server jobs may be active on the server so the first step is to identify the job that serves the particular client connection The easiest method to accomplish this task is to run the following CL command from the i5OS prompt

WRKOBJLCK OBJ(DB2USER) OBJTYPE(USRPRF)

Here DB2USER is the user profile that is used to connect to the iSeries server Note that a QZDASONIT job is assigned to a client after the connection has been established so the developer needs to set a breakpoint in the client application after the database connection has been established

Once the Work with Object Locks appears key in 5 (Work with Job) next to the only QZDASOINIT job that should be listed This shows the Work with Job dialog Select option 10 to

16

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

display the job log for the database server job Now the job log can be searched for any error messages generated by the DB2 runtime

Sometimes it is also useful to include debug messages in the job log The debug messages are informational messages written to the job log about the implementation of a query They describe query implementation methods such as the use of indexes join order ODP implementation (reusable versus non-reusable) and so on The easiest way to instruct an iSeries server to include the debug messages is to set the ServerTraceCategories property on the data source object

tkcpdssetServerTraceCategories(AS400JDBCDataSourceSERVER_TRACE_DEBUG_SERVER_JOB)

A sample of the job log messages with debug messages enabled is shown below

SET TRANSACTION completeSTATEMENT NAME FOUND QZ868F0A458E13AF8C Starting optimizer debug message for query Arrival sequence access was used for file COFFEESODP created ODP not deleted 5000 rows inserted in COFFEES in DB2USER STATEMENT NAME FOUND QZ868F0A4C144BF12EBlocking used for queryCursor CRSR0001 opened606 rows fetched from cursor CRSR0001 ODP not deleted Cursor CRSR0001 closed

So the job log offers fairly detailed information on how the AIX client requests were implemented by the DB2 runtime

JDBC Trace UtilityThe JTOpen driver provides a tracing utility which can be used to collect detailed client-side traces The JDBC tracing is turned off by default It can be enabled by setting the Trace property to true Heres an example of how to switch on tracing using the setTrace method on the data source object

tkcpdssetTrace(true)

The trace can also be enabled when using the DriverManagergetConnection() method for obtaining a connection to DB2 UDB for iSeries In this case the developer could add the trace property to the connection string This approach is illustrated in the following code snippet

ClassforName(comibmas400accessAS400JDBCDriver) [1] hellip con = DriverManagergetConnection(jdbcas400teraplextrace=true

db2userdb2pwd) [2]

At [1] an instance of the JTOpen JDBC Driver is initiated Then at [2] the driver is used to obtain a connection to the iSeries server Note how the trace property has been added to the database URL See the IBM Toolbox for Java JDBC properties documentation on the iSeries Information Center Web site for a complete list of properties supported by the JTOpen driver

Although the level of details provided by the trace utility is sufficient in most troubleshooting scenarios sometimes the developer may need to collect low-level traces scoped to a certain type

17

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

of information In V5R3 the IBM Toolbox for Java (as well as the latest JTOpen) added a comprehensive detailed trace facility The following is the complete list of detailed trace parameters and their purpose

bull None or ldquordquo ndash This setting disables the detailed trace bull datastream - This category is used by Toolbox classes to log dataflow between the local host

and the remote system It is not intended for use by application classes bull diagnostic - This category is used to log object state information bull error - This category is used to log errors that cause an exception bull information - This category is used to track the flow of control through the code bull warning - This category is used to log errors that are recoverable bull conversion - This category is used by Toolbox classes to log character set conversions

between Unicode and native code pages bull proxy - This category is used by Toolbox classes to log data flow between the client and the

proxy server bull pcml - This category is used to determine how PCML interprets the data that is sent to and

from the server bull jdbc - This category is used to track JDBC calls throughout the program bull thread - This category is used to enable tracing of thread information This is useful when

debugging multi-threaded applications bull all - This category will enable all previous categories

The detailed trace can be enabled when using the DriverManagergetConnection() method for obtaining a connection to DB2 UDB for iSeries In this case the developer could add the toolbox trace property to the connection string This is illustrated in the following code sample

String dbUrl = jdbcas400pwd1toolbox trace=diagnostic con = DriverManagergetConnection(dbUrl dbUser dbPassword)

Note that currently the driverrsquos DataSource interfaces do not allow the developer to directly activate the detailed tracing However they could set the server from the command line at the time the java program is launched The example below shows how the detailed trace properties could be enabled at the command line

java -Dcomibmas400accessTracecategory=diagnostic TestJDBC

The -D switch indicates to the java interpreter that the information following it will be a system property

In case of a WebSphere application the trace property can be set through the admin console In the console select Application Servers-gt server1-gt Process Definition -gt Java Virtual Machine Figure 9 shows how to set the Generic JVM Arguments for an application server instance

18

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 9 Setting JVM arguments to enable detailed Toolbox tracing

Database Monitor

The database monitor is the ultimate tool available on DB2 UDB for iSeries to collect low-level SQL traces It is mainly used to pin down the SQL performance problems Refer to the lsquoUsing iSeries Database Monitor to Identify and Tune SQL Queriesrsquo white paper for a detailed discussion on how to collect and analyze the database monitor traces httpibmcomserversenablesiteeducationiborecordhtmldtmon

IBM DB2 JDBC Universal Driver DB2 JDBC Universal Driver is one of the new features delivered with DB2 UDB Version 8 DB2 JDBC Universal Driver has been designed to eliminate the dependency on DB2 CLI runtime modules as well as to enable direct Type 4 connectivity to DB2 UDB for iSeries and DB2 UDB for zOSreg

The pure-Java (Type 4) remote connectivity is based on the DRDA open distributed protocol for cross-platform access to DB2 DRDA defines the rules the protocols and the semantics for accessing distributed data Applications can access data in a distributed relational environment by using SQL statements The iSeries DRDA application server implementation is based on multiple connection-oriented server jobs running in the QSYSWRK subsystem A DRDA listener job (QRWTLSTN) listens for TCP connect requests on port 446 Once an application requester connects to the listener job the listener wakes up one of the QRWTSRVR prestart jobs and assigns it to a given client connection Any further communication occurs directly between the client application and the QRWTSRVR job These concepts are illustrated in Figure 10

19

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 10 Accessing DB2 UDB for iSeries with DB2 Universal Driver

The DB2 Universal Driver can be loaded in an AIX partition by installing one of the DB2 Connect for AIX products (see the Additional Information section for details) It is also a part of a DB2 Enterprise Server Edition for AIX install Specifically the developer needs three JAR files in a AIX partition to successfully connect to an iSeries server db2jccjar db2jcc_license_cisuzjar and db2jcc_license_cujar The iSeries license is contained in db2jcc_license_cisuzjar Note that this file is not a part of DB2 Client In other words a DB2 Connect license is required to use the driver in production environments The location of the JAR files needs to be added to the CLASSPATH environment variable For instance the following entry could be added to the AIX profile script

CLASSPATH=homedb2inst2sqllibjavadb2jccjarCLASSPATH=$CLASSPATHhomedb2inst2sqllibjavadb2jcc_license_cujarCLASSPATH=$CLASSPATHhomedb2inst2sqllibjavadb2jcc_license_cisuzjarexport CLASSPATH

Java Runtime 131 is a prerequisite

Additionally the developer should install the latest database group PTF (SF99503 for i5OS V5R3) on the iSeries server The Informational APAR ii13348 is keeping track of any fixes relevant to DRDA above and beyond the current database group PTF

Obtaining a Connection to DB2 UDB for iSeries When Type 4 connectivity is used the DB2 Universal Driver connects directly to the DB2 on iSeries through TCPIP Note that this is different from the legacy DB2 Type 2 JDBC driver that requires a DB2 node and remote database configurations on the client accessing iSeries The following code snippet illustrates how to use the DB2 JDBC Universal Driver to obtain a connection to DB2 UDB for iSeries

20

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

try ClassforName(comibmdb2jccDB2Driver) [1] catch(javalangClassNotFoundException e) Systemerrprint(ClassNotFoundException )Systemerrprintln(egetMessage())

try DriverManagergetConnection(jdbcdb2teraplex446TERAPLEX[2]

db2userdb2pwd) hellip catch(SQLException ex) Systemerrprintln(

SQLException + exgetMessage())

At [1] an instance of the DB2 JDBC Universal Driver is instantiated Then at [2] the driver is used to obtain a connection to the iSeries server Note the proper form of the database URL required by the driver

Considerations There are several advantages of DB2 JDBC Universal Driver bull Ease of cross-platform development mdash Consistent coding techniques and consistent error

codes and messages bull Ease of deployment mdash Pure Java (no runtime client required) and a single driver for accessing

DB2 on different platforms

The ease of use comes at a price though The iSeries JTOpen driver is optimized for accessing DB2 UDB for iSeries data and it uses native iSeries protocol to communicate with the back-end database server job This usually results in better performance and more-efficient system resources utilization For instance when using the DB2 JDBC Universal Driver to access an iSeries server the executeBatch method results in a single record insert There are also some restrictions when using DB2 Universal JDBC Driver with Type 4 connectivity

bull Support for distributed transactions (JTA) is not enabled bull Driver built-in connection pooling is not supported

Refer to Java application support in DB2 for more details on DB2 JDBC Universal Driver

21

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 Connect data access This section will explore the most important aspects of DB2 Connect ndash iSeries integration - including configuration tips and coding examples

DB2 Connect provides functionality for accessing data stored in DB2 UDB for iSeries as well as DB2 UDB for zOS and DB2 UDB for OS390reg DB2 Connect offers capabilities to access DB2 family members via several SQL interfaces gateway functions such as connection pooling and federated database functionality Many applications supporting the DB2 family of products leverage DB2 Connect as a key middleware component DB2 Connect is offered as separate AIX license products

Enterprise Edition Application Server Edition

In addition to DB2 Connect there are several other DB2 UDB Version 81 products that are supported on AIX

DB2 Universal Database Enterprise Server Edition DB2 Universal Database Workgroup Server Unlimited Edition DB2 Universal Database Workgroup Server Edition DB2 Universal Database Universal Developers Edition All Clients

The DB2 Connect Enterprise Edition functionality is also contained in DB2 Enterprise Server Edition for AIX

22

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 Connect in a nutshell In the scenario described in this paper the DB2 Connect functions contained in DB2 Enterprise Edition for AIX are utilized DB2 Connect Enterprise Edition provides support for both local and remote DB2 clients This is illustrated in Figure 11 Accessing DB2 UDB for iSeries with DB2 Connect

Figure 11 Accessing DB2 UDB for iSeries with DB2 Connect

DB2 Connect implements the Distributed Relational Database Architecturetrade (DRDAreg) to reduce the cost and complexity of accessing data stored in DB2 UDB for iSeries and other DRDA-compliant database servers DRDA defines the rules the protocols and the semantics for accessing distributed data Applications can access data in a distributed relational environment by using SQL statements In a distributed environment the system running the application and sending the SQL requests across the network is called the application requester (AR) A remote database server that executes SQL requests submitted by an application requester is known as the application server (AS) In the example shown in Figure 11 (above) DB2 Connect plays the role of an application requester while DB2 UDB for iSeries is an application server In this case DB2 Connect communicates with the iSeries database through TCPIP The iSeries DRDA application server implementation is based on multiple connection-oriented server jobs running in the QSYSWRK subsystem A DRDA listener job (QRWTLSTN) listens for TCP connect requests on port 446 Once an application requester connects to the listener job the listener wakes up one of the QRWTSRVR prestart jobs and assigns it to a given client connection Any further communication occurs directly between the client application and the QRWTSRVR job

DB2 Connect supports a wide range of programming interfaces that can be used by AIX applications to access the iSeries database Embedded SQL frac34 Both static and dynamic SQL frac34 Various programming languages (Java CC++ Cobol Fortran REXX)

DB2 Call Level Interface (DB2 CLI) ODBC JDBC frac34 DB2 JDBC Type 2 Driver frac34 DB2 JDBC Type 4 Driver (Universal JDBC Driver)

23

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Note that DB2 Connect supports access to DB2 UDB for iSeries through DB2 JDBC Universal driver However for performance and ease of maintenance reasons IBM recommends that Java applications running in AIX use native iSeries Toolbox JDBC driver See the JDBC Data Access section of this paper (above) for more details On the other hand DB2 Connect is a very efficient and robust connectivity option for AIX applications especially in the environments that are not directly supported by the native iSeries JDBC driver Here are several possible scenarios that would require DB2 Connect installed in a AIX partition

Embedded SQL interface is used to access DB2 CLI or ODBC interface is used to access DB2 A single SQL interface is needed to access multiple back end DB2 server Specific DB2 Connect functionality is needed such as distributed join or connection

pooling

Prerequisites One of the DB2 Connect products or DB2 Enterprise Server Edition for AIX V81 is needed Additionally DB2 Application Development Client is required in the AIX partition to compile DB2 applications

For maximum database server stability the developer should install the latest database group PTF (SF99503 for i5OS V5R3) on the iSeries server The Informational APAR ii13348 is keeping track of any fixes relevant to DRDA above and beyond the current database group PTF

DB2 Connect configuration The following example employs i5OS V5R3 and DB2 UDB Enterprise Server Edition for AIX Version 81 FixPak 6

Configuration steps in the iSeries partition The following process lists the necessary steps to be performed on the iSeries server 1) Verify that the TCPIP stack is working correctly It is assumed that the Virtual LAN is used to

communicate with the i5OS partition First obtain the IP address of the iSeries server or its hostname and ping the iSeries server from the AIX partition

2) Create a relational database (RDB) entry for the iSeries database in the i5OS partition If this has already been created it can be displayed by using the DSPRDBDIRE command Make sure that the RDB entry with a location of LOCAL exists on the iSeries server If it does not exist use the ADDRDBDIRE command to add the appropriate RDB entry For example the following command would add an RDB entry named TPLX For simplicity it is recommended that the TCPIP host name and RDB entry remain the same

ADDRDBDIRE RDB(TPLX) RMTLOCNAME(LOCAL)

3) Create a collection called NULLID This is necessary because the utilities shipped with DB2 Connect and DB2 UDB for AIX store their packages in the NULLID collection Since it does not exist by default in the iSeries server you must create it using the following command

CRTLIB LIB(NULLID)

4) Products that support DRDA automatically perform any necessary code page conversions at the receiving system For this to happen both systems need a translation table from their code page to the partner code page The default Coded Character Set Identifier (CCSID) on the iSeries server is 65535 Since DB2 Connect does not have a translation table for this code page the developer needs to change the individual user profiles to contain a CCSID that can be converted properly by DB2 Connect For US English this is 037 For other languages see DB2 Connect Personal Edition Quick Beginning GC09-2967 The following command changes the CCSID for an individual user profile to 037

24

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

CHGUSRPRF userid CCSID(037)

5) Verify that the default port 446 for DRDA service is being used To do this go to the Configure TCPIP menu (CFGTCP) select Configure Related Tables and then select Work with service table entries Verify that the DRDA service is set for port 446

6) The Distributed Data Management (DDM) job must be started for DRDA to work If you want the DDM job to be automatically started whenever TCPIP is started change the attributes of the DDM job using the CHGDDMTCPA command and set the Autostart server parameter to YES

7) If the system administrator chooses not to autostart the server issue the following command to start the DDM server job

STRTCPSVR SERVER(DDM)

8) Make sure that the user profiles that will be used to connect to the iSeries server exist on the server

25

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Configuration steps in the AIX partition The following steps are required for DB2 Connect to be configured in the AIX partition 1) Sign on to the AIX partition as the DB2 administrator 2) Launch Client Configuration Assistant (db2ca from the command prompt) It is assumed that

VNC or an X-Windows server are being used on the workstation so that the db2ca GUI can be properly rendered

3) From the Selected pull-down menu select the Add Database using Wizard option The Select how you want to setup a connection dialog appears Select Manually configure a connection to a database and click Next This is shown in Figure 12

Figure 12 Accessing DB2 UDB for iSeries with DB2 Connect

26

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

4) On the Select a communications protocol choose TCPIP and select The database physical resides on a host or OS400 system Then select the option Connect directly to the server as shown in Figure 13 Click Next

Figure 13 mdash Selecting communications protocol

27

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

5) On the TCPIP tab fill in the host name of the iSeries server The port number should be 446 This is shown in Figure 14 Click Next

Figure 14 mdash Specifying TCPIP communication parameters

28

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

6) On the Database tab fill in the Relational Database name Use the RDB entry name (specified in step 2) in the Configuration steps in the iSeries partition section as shown in Figure 15 Click Next

Figure 15 mdash Specifying the remote database

7) If you plan to use the ODBC applications select Register this database for ODBC as a system data source on the ODBC tab Click Next

29

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

8) On the Specify the node option dialog select OS400 from the Operating System pull-down menu This is shown in Figure 16 Click Finish

Figure 16 mdash Specifying the node options

30

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

9) The Test Connection dialog appears This allows the developer to verify that the connection works Select both CLI and JDBC check boxes You are also prompted for an iSeries user ID and password as shown in Figure 17

Figure 17 mdash Testing the connection

31

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

10) The successful connection to the database server is confirmed by the message box shown in Figure 18

Figure 18 mdash Test Connection results 11) At this time a newly configured database connection should appear in the main DB2

Configuration Assistant window It is recommended that the DB2 utilities are also bound to the iSeries database The bind process creates the necessary SQL packages on the remote database In the main Configuration Assistant window click the TPLX database entry and then select Selected-gtBindhellip

32

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

12) The Bind dialog appears Click Select All and then enter the connection information as shown in Figure 19 Click Bind The Results message box appears This allows the developer to monitor the progress of the binding process Watch for any error and warning messages

Figure 19 mdash Binding the DB2 utilities This concludes the DB2 Connect configuration steps

33

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Accessing DB2 UDB for iSeries from C embedded SQL

As mentioned earlier DB2 Connect allows developers to compile and run embedded SQL applications that access DB2 UDB for iSeries data This section covers implementation details for a C embedded SQL application called cursorsjsqc (see Appendix B for source code)

Prerequisites An embedded SQL application running in an AIX partition will use DB2 Connect services to access DB2 UDB for iSeries therefore the developer needs to make sure that all components listed in section Prerequisites on page 24 are installed The developer also needs to create a remote database connection as described in the DB2 Connect configuration section of this paper on page 24

Static SQL and SQL packages To successfully run against a DB2 UDB for iSeries database an embedded SQL application needs to be first precompiled and bound to the back-end database This process creates an SQL package on the target iSeries server The SQL package contains the access plan information for the SQL statements executed by the application The internal structure of the package as well as the method how its content is used by the SQL runtime to facilitate the access plan reuse is similar to the Extended Dynamic SQL support covered in detail in the Extended Dynamic SQL and Statement Caching section of this paper (on page 9) There are however important differences between the packages created by the extended dynamic SQL support and the packages created for embedded SQL DRDA client applications The extended dynamic SQL packages support dynamic SQL interfaces such as JDBC

that can submit ad hoc SQL statements at the run time The SQL runtime can prepare the dynamic statements and add them to the package On the other hand the DRDA packages are created at the precompile time and contain static SQL In order to add new statements to the package the application needs to be precompiled and rebound again

The extended dynamic SQL package can dynamically grow up to 500MB by allocating new space as required The DRDA packages since they are created at the precompile time have a fix size and do not grow over their life time

Simple embedded SQL application The application is based on a source code provided in the DB2 UDB samples directory typically to be found at homedb2inst1sqllibsamples The cursorsjsqc performs a join between STAFF and ORG tables located in DB2USER schema (library) on the TPLX database server (the source is provided at the end of this paper in Appendix B) The join statement retrieves the DEPTNAME column from ORG NAME column from STAFF and calculates the total compensation for an employee by adding SALARY and COMM columns in STAFF The results are sorted by department name and total compensation Here is the SELECT statement used by the application

SELECT deptname name salary + IFNULL(comm0) as compensationFROM org o staff sWHERE odeptnumb = sdeptORDER BY deptname compensation DESC

The application iterates through the selected records and prints out the data to the standard output device The sample DB2USER schema was created with the following SQL statements

db2 CONNECT TO tplx USER db2user USING mypassworddb2 CALL QSYSCREATE_SQL_SAMPLE(DB2USER)

34

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Make sure that the AIX partition is logged into with the DB2 admin user profile If the defaults were selected at the DB2 installation time this profile name is db2inst1 It is also assumed that DB2USER user exists on the iSeries server and that it has appropriate authority

There are several steps that are required to create an executable for the cursorsjsqc source code First the DB2 PRECOMPILE utility needs to be called The utility creates a bind file that is used to bind the required SQL package to the TPLX database It also converts embedded SQL statements into DB2 run-time API calls and produces a pure C source file that can be processed by an AIX C compiler

db2 CONNECT TO tplx USER db2user USING mypassworddb2 prep cursorsjsqc bindfile

Note that the connect statement is required only if the developer is not already connected to the database on an iSeries server Watch for any error or warning messages returned by the DB2 prep utility The prepare step should produce cursorsjbnd and cursorsjc files in the current directory Now the developer can invoke the bind utility to prepare the statements contained in the bind file and create the package on the target iSeries database server

db2 bind cursorsjbnd

It is assumed that Visual C++ 60 is installed and configured in the AIX partition Refer to the ldquoDeveloping and Porting C and C++ Applications on AIXrdquo redbook for more information on how to use the Visual C++ compiler httpibmcomredbooksabstractssg245674htmlOpen

Use the following commands to compile the C source generated by the precompile utility

xlc -I$INSTHOMEsqllibinclude ndashc cursorsjcxlc ndasho cursorsj cursorsjo -L$INSTHOMEsqlliblib ndashldb2

Run the program from the AIX prompt

cursorsj db2user mypassword

Distributed Join DB2 UDB Version 8 provides core federated server functionality A federated system consists of a DB2 UDB instance that operates as a federated server a database that acts as the federated database one or more data sources and clients (users and applications) that access the database and data sources Federated server permits objects stored in multiple databases to be accessed together in the same query For example a query can refer to a table that resides in DB2 UDB for iSeries and join it to a table stored in DB2 UDB for AIX Such a query would constitute so called distributed join The support for DB2 UDB for iSeries as a federated data source is provided by core federated server functionality directly implemented in DB2 UDB Enterprise Server Edition and DB2 UDB Connect Enterprise Edition All other DB2 UDB family members are also supported directly by core DB2 UDB federated server An additional software product DB2 Information Integratortrade is required to access non-DB2 UDB databases such as Oracle Sybase or Microsoftreg SQL Server Consult the following white papers for a detailed discussion on DB2 federated server support Heterogeneous data access for iSeries applications Version 2 httpibmcomserversenablesiteeducationiborecordhtmlhetdata Fundamentals of IBM DB2 Federated Server and Relational Connect httpwww7bsoftwareibmcomdmddlibrarytecharticle0206purnell0206purnellhtml

35

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Distributed Join Example In this section the steps that are required to configure DB2 UDB for iSeries as a federated data source will be illustrated Then the cursorsjsqc program will be ldquotweakedrdquo so that it executes a distributed join query that accesses data stored on an iSeries server and in the local DB2 UDB for AIX database It is assumed that the developer is familiar with the DB2 federated server concepts

Note Run the following commands from the Command Line Processor prompt Load the utility by executing the db2 command at the AIX prompt 1) First the local DB2 UDB for AIX instance needs to be enabled as a DB2 federated server

This is done by setting the database manager configuration parameter FEDERATED to YES

db2=gt update dbm cfg using FEDERATED YES

The database instance needs to be restarted for the change to take effect

NOTE A federated database is a regular database in a DB2 UDB instance that has the FEDERATED parameter enabled Therefore in this example the SAMPLE database that was created earlier is used as the federated database A new database can also be created using the CREATE DATABASE command

2) Connect to the federated database

db2=gt connect to sample

3) Use the CREATE WRAPPER statement to register a wrapper for the iSeries data source Wrappers are library routines that are used by the federated server to perform operations such as connecting to a data source and retrieving data from it The default wrapper name for DB2 UDB for iSeries is DRDA Here is the command to register the DRDA wrapper

db2=gt create wrapper drda

4) Use the CREATE SERVER statement to register a data source as a server within the federated database The server definition specifies the type and version of the data source and the wrapper used for communications with this data source For the DB2 UDB for iSeries data source the node and the database names are also needed The node and database name parameters have been configured for our TPLX database in the Configuration steps in the AIX partition section (on page 24) Use the following DB2 UDB command to lookup these parameter on the federated server

db2=gt list database directory

In this case the command produced the following output

Database alias = TPLX Database name = DCSE99E1 Node name = NDE9BF76 Database release level = a00 Comment = Directory entry type = Remote Authentication = SERVER Catalog database partition number = -1

36

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Note that the node name is set to NDE9BF76 The name was generated by the Configuration Administrator utility (db2ca)

Here is the command to register the TPLX database as a federated server

db2=gt create server tplx type db2400 version 530 wrapperdrda authorization db2user password mypassword options(nodeNDE9BF76 dbname TPLX)

The command is quite complex so make sure that the syntax is correct

5) Define the user mappings that instructs the federated server what user ID and password should be used when connecting to the iSeries data source

db2=gt create user mapping for user server tplxoptions(remote_authid db2user remote_password mypassword)

Specify the nickname for the iSeries table or view A nickname is an identifier that is used by the federated server to reference an object located at the data source The following command creates a nickname for the STAFF table located in the DB2USER schema on the TPLX database

db2=gt create nickname tplx_staff for tplxdb2userstaff

6) Test the distributed join query

db2=gt SELECT deptname name salary + COALESCE(comm0) ascompensation FROM org o tplx_staff s WHERE odeptnumb =sdept ORDER BY deptname compensation DESC

Note that the native iSeries function IFNULL has been substituted with an equivalent DB2 UDB function COALESCE COALESCE is also supported on iSeries servers For better portability IBM encourages the use of COALESCE rather than IFNULL Note also that the query runs on the federated server rather than on TPLX It accesses the ORG table in the local DB2 UDB for AIX SAMPLE database and the STAFF table that resides in TPLX The federated server performs the necessary distributed join

7) Modify the cursorsjsqc so that it executes a distributed join There are two source code modifications - Change the CONNECT TO statements Now the application needs to connect to the

federated database SAMPLE rather than to TPLX

EXEC SQL CONNECT TO SAMPLEEXEC SQL CONNECT TO SAMPLE USER userid USING passwd

- Modify the select statement so that it performs a distributed join Use the statement (shown in step 6) above Save the new source version as cursordjsqc

- Prepare bind and compile the distributed join version of the program as described in the Simple C embedded SQL application section (on page 34)

db2 prep cursordjsqc bindfiledb2 bind cursordjbndxlc -I$INSTHOMEsqllibinclude ndashc cursordjcxlc ndasho cursordj cursordjo -L$INSTHOMEsqlliblib ndashldb2

37

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

- Run the program from the AIX prompt

cursordj

Connection Pooling and Connection ConcentratorA modern Web-based application typically executes a large number of short-lived transactions Executing a transaction in this environment means establishing a database connection executing a few SQL statements and terminating this connection Creating connections to the database server is a very costly process To reduce the unnecessary workload DB2 Connect implements connection pooling and connection concentrator Connection pooling mechanism allows DB2 Connect to reuse an existing connection infrastructure for subsequent connection requests The connection concentrator is an advanced technology that allows DB2 Connect to serve a potentially very large number of clients with a limited number of database connections This is accomplished by decoupling clients from a particular database connection

Note that currently neither connection pooling nor connection concentrator support DB2 UDB for iSeries Therefore for performance reasons the author strongly recommends that the application server that obtains and drops connections very frequently implements its own database connection pooling mechanism that would assign an existing pooled database connection to a new AIX process or thread

TroubleshootingTroubleshooting a multi-tier application may be a bit tricky because the developer needs to deal with software components that reside in separate partitions The authorrsquos experience shows that two tools are particularly useful for pinning down the potential problem areas The joblog messages for a database server job usually provide enough details to isolate DB2

UDB for iSeries runtime issues The DRDA trace utility provides granular information about the data flow between the AIX

application and the iSeries server job

38

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Job Log MessagesAs mentioned earlier a DB2 client communicates with a corresponding iSeries server job This server job runs the SQL requests on behalf of the client More precisely when a DB2 client submits an SQL statement the statement is passed to a server job that in turn calls the DB2 runtime to execute the statement The results are then reformatted and marshaled to the client The iSeries DRDA server jobs are called QRWTSRVR and they run in the QUSRWRK subsystem At any given time there may be a large number of DRDA server jobs active on the system so the first step is to identify the job that serves the particular client connection The easiest method to accomplish this task is to run the following CL command from the i5OS prompt

WRKOBJLCK OBJ(DB2USER) OBJTYPE(USRPRF)

Here DB2USER is the user profile that is used to connect to the iSeries server Note that a QRWTSRVR job is assigned to a client after the connection has been established so the developer needs to set a breakpoint in the client application below the CONNECT TO statement

Once the Work with Object Locks appears key in 5 (Work with Job) next to the only QRWTSRVR job that should be listed This shows the Work with Job dialog Select option 10 to display the job log for the database server job Now the developer can search the job log for any error messages generated by the DB2 runtime

Sometimes it is also useful to include debug messages in the job log The debug messages are informational messages written to the job log about the implementation of a query They describe query implementation methods such as use of indexes join order ODP implementation (reusable versus non-reusable) and so on The easiest way to instruct the iSeries server to include the debug messages is to call the following stored procedure just after the connection to the iSeries server is established

EXEC SQL call qsysqcmdexc(STRDBGUPDPROD(YES)000000002000000)

A sample of the job log messages with debug messages enabled is shown below in Figure 20

Arrival sequence access was used for file STAFFAccess path suggestion for file STAFFQuery options used to build the OS400 query access plan Ending debug message for query ODP created Blocking used for queryCursor SQLCUR201 opened1 rows fetched from cursor SQLCUR201Row not found for SQLCUR201ODP deleted Cursor SQLCUR201 closedDESCRIBE of prepared statement STMT0201 completed

Figure 20 mdash Joblog with debug messages enabled

So the job log offers fairly detailed information on how the AIX client requests were implemented by the DB2 runtime

39

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 DRDA trace utilityThe DB2 DRDA trace utility (db2drdat) provides detailed information about the data streams exchanged between DB2 Connect and target database server The output file produced by the utility contains send and receive communications buffers TCPIP error messages and SQL Communications Area (SQLCA) information Please refer to lsquoDB2 Connect Userrsquos Guidersquo manual for in-depth discussion of the DRDA trace utility

Accessing DB2 UDB for iSeries from CLI DB2 Call Level Interface (CLI ) is based on the Microsoft Open Database Connectivity (ODBC) specification and the ISO CLI standard The DB2 CLI interface gained popularity among DB2 application providers because the developer can build an ODBC application by simply linking the application with libdb2 library on a UNIX server In other words the developer directly utilizes the DB2 ODBC driver services without a need for an ODBC driver manager Additionally in contrast to embedded SQL the developer does not need to precompile or bind DB2 CLI applications because they use packages provided with DB2 UDB The developer simply compiles and links the application

Prerequisites A DB2 CLI application running in an AIX partition will use DB2 Connect services to access DB2 UDB for iSeries therefore make sure that all components listed in Prerequisites section of this paper on page 24 are installed The developer also needs to create a remote database connection as described in the DB2 Connect configuration section of this paper on page 24

Dynamic SQL and Access Plan Caching A DB2 CLI client application uses the dynamic SQL interface and does not have the capability to utilize the extended dynamic SQL support Therefore it runs lsquopurersquo dynamic SQL statements That does not mean however that the process of parsing validating and optimizing will be repeated for every execution of a given dynamic SQL statement

The DB2 UDB for iSeries database implements an internal object called System-Wide SQL Statement Cache (SWSC) The SWSC can improve the performance of programs using dynamic SQL statements by caching the access plans in a system-wide cache When a dynamic SQL statement is submitted the SQL runtime searches the SWSC to see if this statement has been previously executed If so then DB2 retrieves and reuses the key information associated with the cached statement and thereby the processing time and the resources utilization can be significantly reduced

Simple DB2 CLI C++ ApplicationThis section covers DB2 CLI implementation details for a sample C++ program called testclicpp (the source is provided at the end of this paper in Appendix C) To compile the source with Visual C++ complier use the following command in the AIX partition

xlC ndashI$INSTHOMEsqllibinclude ndashc testclicppxlC ndasho testcli testclio ndashL$INSTHOMEsqlliblib ndashldb2

The application performs a join between STAFF and ORG tables located in DB2USER schema (library) The join statement retrieves the DEPTNAME column from ORG NAME and JOB columns from STAFF and calculates the total compensation for an employee by adding SALARY and COMM columns in STAFF The results are sorted by total compensation The selection criterion is based on the current value of the department name parameter Here is the SELECT statement used by testcli

40

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

select name job salary + coalesce(comm0) as compensationfrom org o staff swhere odeptnumb = sdeptand deptname = order by compensation desc

Figure 21 shows the software components involved in the execution of this sample application

Figure 21 How a DB2 CLI client accesses DB2 UDB on an iSeries server

Although the testcli application is fairly simple it covers some important aspects of efficient CLI programming for DB2 UDB for iSeries

Reusable Open Data Paths (ODPs)An Open Data Path (ODP) definition is an internal i5OS object that is created when certain SQL statements (such as OPEN INSERT UPDATE and DELETE) are executed for the first time in a given job (or connection) The ODP can be thought of as a runtime implementation of an access plan The access plan created at the optimization time provides a recipe or in other words a sequence of steps necessary to execute the statement The ODP on the other hand provides the executable code for all requested IO operations The process of creating new ODP objects is fairly CPU- and IO-intensive so whenever possible the iSeries DB2 runtime tries to reuse existing ODPs For instance a SQLCloseCursor() API call may close the SQL cursor but leave the ODP available to be used the next time the cursor is opened This can significantly reduce the processing and response time in running SQL statements A reusable OPD usually requires 10 to 20 times less CPU resources than a newly created ODP Therefore it is important that the applications employ programming techniques that allow the DB2 runtime to reuse ODPs

With dynamic interfaces such as CLI full opens are avoided by using a prepare once execute many programming paradigm It means that when an SQL statement is going to be executed more than once you should prepare the statement just once and then reuse the prepared

41

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

statements for consecutive executions Although DB2 UDB does try to convert literals to parameter markers so that similar statements can be reused it is a better programming practice to explicitly implement parameter markers That way the chances for reusable ODPs are quite significantly improved The code snippet in Figure 22 illustrates how to implement the prepare once execute many programming technique

Define A SELECT SQL Statementstrcpy((char ) SQLStmt select name job salary + ifnull(comm0) ascompensation )ptr = strcat( (char ) SQLStmt from org o staff s )ptr = strcat( (char ) SQLStmt where odeptnumb = sdept)ptr = strcat( (char ) SQLStmt and deptname = )ptr = strcat( (char ) SQLStmt order by compensation desc) [1]

Prepare The SQL Statementrc = SQLPrepare(ExampleStmtHandle SQLStmt SQL_NTS) [2]

Bind The Columns In The Result Data Set Returned To Application Variablesrc = SQLBindCol(ExampleStmtHandle 1 SQL_C_CHAR (SQLPOINTER)

ExampleName sizeof(ExampleName) NULL)rc = SQLBindCol(ExampleStmtHandle 2 SQL_C_CHAR (SQLPOINTER)

ExampleJob sizeof(ExampleJob) NULL)rc = SQLBindCol(ExampleStmtHandle 3 SQL_C_DOUBLE (SQLPOINTER)

ampExampleComp sizeof(ExampleComp) NULL)

for (int i = 0 i lt LOOPS i++)rc=SQLBindParameter(ExampleStmtHandle

1SQL_PARAM_INPUTSQL_C_CHARSQL_CHAR10(SQLPOINTER) currentDepartment[i8]0NULL) [3]

rc = SQLExecute(ExampleStmtHandle) [4]cout ltlt endl ltlt Current Dept ltlt currentDepartment[i8] ltlt endl Display The Results Of The SQL QueryExampleShowResults()

Figure 22 Use the prepare once execute many programming technique

The error-handling code has been removed for clarity At [1] the statement text is assigned to a variable Note that a parameter marker is used in the WHERE clause The statement is then prepared just once at [2] The current value of the parameter is bound to the prepared statement at [3] The prepared statement is executed at [4] Steps [3] and [4] are repeatedly executed in a for loop

Techniques to Further Improve DB2 CLI Performance Thus far this paper has discussed the techniques used by a sample application to tune the CLI performance However depending on the application architecture other methods of improving CLI performance may be considered

Connection PoolingCurrently the CLI application connecting through DB2 Connect to DB2 UDB for iSeries does not take advantage of the connection pooling mechanism implemented by DB2 Connect Therefore for performance reasons the author strongly recommends that the application server that obtains and drops connections very frequently implements its own database connection pooling mechanism that would assign an existing pooled database connection to a new AIX process or thread

42

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Blocking

For queries which result in returning large data blocks from the iSeries server (usually 32K of data and above) ensure that the database manager configuration parameter RQRIOBLK is set to 32767 This can be done using the Command Line Processor (CLP) as follows

db2 update database manager configuration using RQRIOBLK 32767

TroubleshootingThe experience of the author shows that two tools are particularly useful for pinning down the potential problem areas bull Joblog messages for a database server job usually provides enough details to isolate DB2

runtime issues bull CLI trace utility provides granular information about the data flow between the AIX application

and the database server job

Job Log MessagesThe process of finding and analyzing the job log for a DB2 CLI connection is identical to the process outlined for an embedded SQL application in the Job Log Message section of this paper on page 39

CLI Trace The DB2 CLIODBCJDBC trace utility provides very detailed information about the data streams exchanged between DB2 Connect and target database server Refer to the DB2 Information Center for more information on how to set up and analyze the CLI traces httppublibboulderibmcominfocenterdb2v8luwindexjsptopic=comibmdb2udbdocadc000 7959htm

43

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Trademarks

IBM eServer iSeries AIX AIX 5L i5OS WebSphere DB2 DB2 Universal Database DB2 Connect OS400 zOS OS390 Distributed Relational Database Architecture DRDA and DB2 Information Integration are trademarks or registered trademarks of International Business Machines Corporation in the United States and other countries

Java and all Java-based trademarks are trademarks of Sun Microsystems Inc in the United States other countries or both

Linux is a registered trademark of Linus Torvalds in the United States other countries or both

UNIX is a registered trademark of The Open Group in the United States and other countries

Microsoft and Windows are registered trademarks of Microsoft Corporation in the United States andor other countries

All other registered trademarks and trademarks are properties of their respective owners

IBM makes no commitment to make available any products referred to herein

References in this publication to IBM products or services do not imply that IBM intends to make them available in every country in which IBM operates

Additional Information ITSO offers a Redbook that can be helpful to those who want to learn more about i5OS AIX integration

bull AIX Integration with I5OS on the IBM eServer iSeries Server (SG24-6551)

Jarek Miszczyk is the Senior Software Engineer IBM eServer Solutions Enablement IBM Rochester

[Portions of this white paper reprinted with permission from MC Mag Online published by MC Press LLP httpwwwmcpressonlinecom]

Acknowledgments The author would like to thank the following people for their advice contributions and support on this paper

Bob Bittner IBM Rochester Jon Rush IBM Rochester Prasad Vallurupalli IBM Rochester Neil Willis IBM Rochester

44

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix A Source Listing of TestJDBCjava

package comibmiseriespwdimport javasqlimport javaxnamingimport javautilHashtableimport javautilimport javaxsqlimport comibmas400access

public class TestJDBC public static void main(javalangString[] args)

throws Exception

int numOfLoops = 5000int outerNumOfLoops = 5boolean firstExec = trueConnection conStatement sPreparedStatement psPreparedStatement pstmtdelCallableStatement cstmPreparedStatement pstmtHashtable env = new Hashtable()

envput(ContextINITIAL_CONTEXT_FACTORYcomsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env)Systemoutprintln(Deploying connection pooling data source)deployDataSource() Do the work with connection pooling onlyAS400JDBCConnectionPoolDataSource tkcpds =

(AS400JDBCConnectionPoolDataSource)ctxlookup(jdbcToolkitDataSource) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPool pool = new AS400JDBCConnectionPool(tkcpds) Adds 1 connection to the pool that can be used by theapplication (creates the physical database connections based onthe data source)poolfill(1)Systemoutprintln(nStart timing Toolkit connection pooling)long startTime = SystemcurrentTimeMillis()

for (int i = 0 i lt outerNumOfLoops i++) con = poolgetConnection()consetAutoCommit(false) deleteif ( i == 0)

long startDelete = SystemcurrentTimeMillis()cstm = cstm = conprepareCall(

CALL qsysqcmdexc(CLRPFM FILE(DB2USERCOFFEES) + 000000002800000))

cstmexecuteUpdate()cstmclose()long endDelete = SystemcurrentTimeMillis()Systemoutprintln(Delete all records +

(endDelete - startDelete) + ms elapsed)

45

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

String sqlinstrlong startInsert = SystemcurrentTimeMillis() insert

pstmt =conprepareStatement(INSERT INTO COFFEES VALUES( ))for (int j = 0 j lt numOfLoops j++) pstmtsetString(1 Kona_ + IntegertoString(i))pstmtsetInt(2 150)pstmtsetFloat(3 999f)pstmtsetInt(4 0)pstmtsetInt(5 0)pstmtaddBatch()int [] updateCounts = pstmtexecuteBatch()concommit()pstmtclose()long endInsert = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for + numOfLoops + inserts

+ (endInsert - startInsert)) selectlong startSelect = SystemcurrentTimeMillis()ps = conprepareStatement(SELECT FROM COFFEES)ResultSet rs = psexecuteQuery()rsnext()rsclose()concommit()psclose()long endSelect = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for select +

(endSelect - startSelect))consetAutoCommit(true)conclose()long endTime = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for + outerNumOfLoops +

loops + (endTime - startTime))Systemexit(0)

private static void deployDataSource()throws ExceptionString serverName = teraplex String databaseName = TERAPLEX String userName = db2user String password = db2pwd

Establish a JNDI context and bind the connection pool data sourceHashtable env = new Hashtable()envput(ContextINITIAL_CONTEXT_FACTORY

comsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPoolDataSource tkcpds = new

AS400JDBCConnectionPoolDataSource()tkcpdssetServerName(serverName) tkcpdssetDatabaseName(databaseName) tkcpdssetUser(userName) tkcpdssetPassword(password) tkcpdssetDescription(Toolkit Connection Pooling DataSource)tkcpdssetSavePasswordWhenSerialized(true)tkcpdssetExtendedDynamic(true)

46

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

tkcpdssetPackage(JDBCDS)tkcpdssetPackageCache(true)tkcpdssetPackageCriteria(select)enable the following properties as requiredcpdssetTrace(true)tkcpdssetServerTraceCategories( AS400JDBCDataSourceSERVER_TRACE_DEBUG_SERVER_JOB)

ctxrebind(jdbcToolkitDataSource tkcpds)

47

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix B mdash Source Listing of cursorsjsqc

Source File Name = cursorsjsqc Licensed Materials - Property of IBM (C) COPYRIGHT International Business Machines Corp 1995 2000 2004 All Rights Reserved US Government Users Restricted Rights - Use duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp PURPOSE This sample program demonstrates the use of a CURSOR The CURSOR is processed using static SQL EXTERNAL DEPENDENCIES - Ensure existence of database for precompile purposes - Precompile with the SQL precompiler (PREP in DB2) - Bind to a database (BIND in DB2) - Compile and link with the IBM Cset++ compiler (AIX and OS2) or the Microsoft Visual C++ compiler (Windows) or the compiler supported on your platform For more information about these samples see the README file For more information on programming in C see the - Programming in C and C++ section of the Application Development Guide For more information on building C applications see the - Building C Applications section of the Application Building Guide For more information on the SQL language see the SQL Reference

include ltstdiohgt include ltstdlibhgt include ltstringhgtinclude ltsqlhgtinclude ltsqlenvhgtinclude ltsqldahgtinclude ltsqlcahgt

int SqlInfoPrint( char struct sqlca int char )void TransRollback( void)

define EMB_SQL_CHECK( MSG_STR ) rc = SqlInfoPrint( MSG_STR ampsqlca __LINE__ __FILE__) if ( rc = 0 ) TransRollback( )

return 1

EXEC SQL INCLUDE SQLCA

int main(int argc char argv[])

EXEC SQL BEGIN DECLARE SECTIONchar dname[15]

48

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

char pname[10]double compchar userid[9]char passwd[19]

EXEC SQL END DECLARE SECTION

int rc = 0printf( Sample C program CURSORSJ n )if (argc == 1)

EXEC SQL CONNECT TO TPLXEMB_SQL_CHECK(CONNECT TO TPLX)

else if (argc == 3)

strcpy (userid argv[1])strcpy (passwd argv[2])EXEC SQL CONNECT TO TPLX USER userid USING passwdEMB_SQL_CHECK(CONNECT TO TPLX)

else

printf (nUSAGE cursor [userid passwd]nn)return 1

endif

EXEC SQL DECLARE c1 CURSOR FORselect deptname name salary + ifnull(comm0) as compensationfrom org o staff swhere odeptnumb = sdeptorder by deptname compensation desc

EXEC SQL OPEN c1EMB_SQL_CHECK(OPEN CURSOR)

printf(DEPARTMENT NAME COMPENSn)printf(-----------------------------------n)do

EXEC SQL FETCH c1 INTO dname pname compif (SQLCODE = 0) breakprintf( -1515s -1010s 72fn dname pname comp )

while ( 1 )

EXEC SQL CLOSE c1EMB_SQL_CHECK(CLOSE CURSOR)

EXEC SQL CONNECT RESETEMB_SQL_CHECK(CONNECT RESET)

exit(0)

end of program CURSORSJSQC

int SqlInfoPrint( char appMsgstruct sqlca pSqlcaint linechar file )

int rc = 0char sqlInfo[1024]char sqlInfoToken[1024]char sqlstateMsg[1024]char errorMsg[1024]

if (pSqlca-gtsqlcode = 0 ampamp pSqlca-gtsqlcode = 100)

49

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

strcpy(sqlInfo )if( pSqlca-gtsqlcode lt 0) sprintf( sqlInfoToken n---- error report ----n)

strcat( sqlInfo sqlInfoToken)else sprintf( sqlInfoToken n---- warning report ----n)

strcat( sqlInfo sqlInfoToken) endif

sprintf( sqlInfoToken app message = sn appMsg)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken line = dn line)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken file = sn file)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken SQLCODE = ldn pSqlca-gtsqlcode)strcat( sqlInfo sqlInfoToken)

get error message rc = sqlaintp( errorMsg 1024 80 pSqlca) return code is the length of the errorMsg string if( rc gt 0) sprintf( sqlInfoToken sn errorMsg)

strcat( sqlInfo sqlInfoToken)

get SQLSTATE message rc = sqlogstt( sqlstateMsg 1024 80 pSqlca-gtsqlstate)if (rc == 0) sprintf( sqlInfoToken sn sqlstateMsg)

strcat( sqlInfo sqlInfoToken)

if( pSqlca-gtsqlcode lt 0) sprintf( sqlInfoToken --- end error report ---n)

strcat( sqlInfo sqlInfoToken)printf(s sqlInfo)return 1

else sprintf( sqlInfoToken --- end warning report ---n)

strcat( sqlInfo sqlInfoToken)printf(s sqlInfo)return 0

endif endif

return 0

void TransRollback( ) struct sqlca sqlca

int rc = 0 rollback the transaction printf( nRolling back the transaction n)

EXEC SQL ROLLBACKrc = SqlInfoPrint( ROLLBACK ampsqlca __LINE__ __FILE__)if( rc == 0) printf( The transaction was rolled backn)

50

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

51

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix C mdash Source Listing of testclicpp

Include The Appropriate Header Filesinclude ltsqlclihgtinclude ltsqlcli1hgtinclude ltsqlutilhgtinclude ltsqlenvhgtinclude ltstdiohgt include ltiostreamgt include ltlocalehgt include ltstringhgtdefine SQL_SQLSTATE_SIZE 5define LOOPS 8

using namespace std

Define The CLI_Class Classclass CLI_Class

Attributespublic

SQLHANDLE EnvHandleSQLHANDLE ConHandleSQLHANDLE StmtHandleSQLRETURN rcSQLCHAR Job[6]SQLCHAR Name[10]SQLDOUBLE Comp

Operationspublic

CLI_Class()~CLI_Class()SQLRETURN ShowResults()

Constructor Destructor

SQLRETURN printError( SQLHDBC SQLHSTMT)

Define The Class ConstructorCLI_ClassCLI_Class()

setlocale( LC_ALL )

Initialize The Return Code Variablerc = SQL_SUCCESS

Allocate An Environment Handlerc = SQLAllocHandle(SQL_HANDLE_ENV SQL_NULL_HANDLE ampEnvHandle)

Allocate A Connection Handleif (rc == SQL_SUCCESS)

rc = SQLAllocHandle(SQL_HANDLE_DBC EnvHandle ampConHandle)

Define The Class DestructorCLI_Class~CLI_Class()

Free The Connection Handleif (ConHandle = NULL)

SQLFreeHandle(SQL_HANDLE_DBC ConHandle)

Free The Environment Handle

52

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

if (EnvHandle = NULL)SQLFreeHandle(SQL_HANDLE_ENV EnvHandle)

Define The ShowResults() Member FunctionSQLRETURN CLI_ClassShowResults(void)

While There Are Records In The Result Data Set Generated Retrieve And Display Themcout ltlt Name Job Compensation ltlt endlcout ltlt --------- ------ ------------ ltlt endlcoutsetf(iosleft)coutprecision(2)coutsetf(iosfixed)while (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)

rc = SQLFetch(StmtHandle)if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)

coutwidth(15)cout ltlt Name

coutwidth(10)cout ltlt Job

coutwidth(7)cout ltlt Comp ltltendl

if(rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO ampamp rc = SQL_NO_DATA)printError(ConHandle StmtHandle)

else

rc = 0SQLCloseCursor(StmtHandle)

Return The ODBC API Return Code To The Calling Functionreturn(rc)

SQLRETURN CLI_ClassprintError (SQLHDBC hdbc

SQLHSTMT hstmt)

SQLCHAR buffer[SQL_MAX_MESSAGE_LENGTH + 1]SQLCHAR sqlstate[SQL_SQLSTATE_SIZE + 1]SQLINTEGER sqlcodeSQLSMALLINT lengthSQLRETURN rcwhile ((rc = SQLError(SQL_NULL_HENV hdbc hstmt

sqlstateampsqlcodebufferSQL_MAX_MESSAGE_LENGTH + 1amplength)) == SQL_SUCCESS || rc ==

SQL_SUCCESS_WITH_INFO)

cout ltlt SQLSTATE ltlt sqlstate ltlt endlcout ltlt SQLCODE ltlt sqlcode ltlt endlcout ltlt Error msg ltlt buffer ltlt endl

53

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

cout ltlt----------------------------- ltlt endl ltlt endl

return(SQL_ERROR)

----------------------------------------------------------------- The Main Function -----------------------------------------------------------------int main()

Declare The Local Memory Variables

(SQLCHAR ) db2user SQL_NTS (SQLCHAR ) test26t SQL_NTS)

SQLRETURNSQLCHARSQLCHARSQLCHARchar

SQLCHAR

rc = SQL_SUCCESSDBName[10] = TPLXSQLStmt[255]c[10]ptrcurrentDepartment[8][15] = Head Office

New England Mid Atlantic South Atlantic Great Lakes PlainsPacificMountain

Create An Instance Of The CLI_Class ClassCLI_Class Example

Connect To iSeries Database if (ExampleConHandle = NULL)

rc = SQLConnect(ExampleConHandle DBName SQL_NTS

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)ExampleprintError(ExampleConHandle SQL_NULL_HSTMT)

return(rc)

cout ltlt Successfully connected to ltlt DBName ltlt ltlt endlrc = SQLSetConnectAttr(ExampleConHandle SQL_ATTR_AUTOCOMMIT

(SQLPOINTER) SQL_AUTOCOMMIT_OFF SQL_IS_UINTEGER) Allocate An SQL Statement Handlerc = SQLAllocHandle(SQL_HANDLE_STMT ExampleConHandle

ampExampleStmtHandle)if (rc == SQL_SUCCESS)

Define A SELECT SQL Statement

strcpy((char ) SQLStmt select name job salary + ifnull(comm0) ascompensation )

ptr = strcat( (char ) SQLStmt from org o staff s )ptr = strcat( (char ) SQLStmt where odeptnumb = sdept)ptr = strcat( (char ) SQLStmt and deptname = )ptr = strcat( (char ) SQLStmt order by compensation desc)

Prepare The SQL Statementrc = SQLPrepare(ExampleStmtHandle SQLStmt SQL_NTS)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)ExampleprintError(ExampleConHandle ExampleStmtHandle)

54

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

return(rc)

Bind The Columns In The Result Data Set Returned To Application Variables

rc = SQLBindCol(ExampleStmtHandle 1 SQL_C_CHAR (SQLPOINTER)ExampleName sizeof(ExampleName) NULL)

rc = SQLBindCol(ExampleStmtHandle 2 SQL_C_CHAR (SQLPOINTER)ExampleJob sizeof(ExampleJob) NULL)

rc = SQLBindCol(ExampleStmtHandle 3 SQL_C_DOUBLE (SQLPOINTER)ampExampleComp sizeof(ExampleComp) NULL)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO) ExampleprintError(ExampleConHandle ExampleStmtHandle)

return(rc)

while (true)

for (int i = 0 i lt LOOPS i++)

rc=SQLBindParameter(ExampleStmtHandle1SQL_PARAM_INPUTSQL_C_CHARSQL_CHAR

150(SQLPOINTER) currentDepartment[i8]0NULL)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)

ExampleprintError(ExampleConHandle ExampleStmtHandle)return(rc)

rc = SQLExecute(ExampleStmtHandle)if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)

ExampleprintError(ExampleConHandle ExampleStmtHandle)return(rc)

cout ltlt endl ltlt Current Dept ltlt currentDepartment[i8] ltlt

endl Display The Results Of The SQL QueryExampleShowResults()if(rc = 0)break

if ( i500 == 0 ampamp i gt 0 )cout ltlt Loops ltlt i ltlt ltlt endl

cout ltlt AFTER ltlt LOOPS ltlt loops Press X to exit ltlt endlcin gtgt cif (c[0] == x || c[0] == X)

break

Free The SQL Statement Handleif (ExampleStmtHandle = NULL )

SQLFreeHandle(SQL_HANDLE_STMT ExampleStmtHandle) Disconnect From The Northwind Sample Databaserc = SQLDisconnect(ExampleConHandle)

Return To The Operating Systemreturn(rc)

55

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

bound to the back-end database server The bind process creates an SQL package on the DB2 UDB for iSeries The package contains the access plans and other control structures that can be reused when the client program executes

Static SQL is the most efficient way to process SQL requests on an iSeries server

Dynamic SQL Dynamic SQL statements are parsed validated and optimized at the time an SQL application is executed The SQL statements are passed to the database manager in the form of a character string using the SQL statements PREPARE or EXECUTE IMMEDIATE The IBM Toolbox for JavaJTOpen JDBC driver uses this method if Extended Dynamic SQL support is not enabled The Dynamic SQL is also used by the dynamic SQL interfaces such as DB2 Call Level Interface (DB2 CLI) ODBC and JDBC when a client application connects to DB2 UDB for iSeries through DB2 Connect gateway Refer to DB2 Connect data access on page 22 of this paper for more details

Extended Dynamic SQL In Extended Dynamic SQL the SQL statements are dynamic However SQL packages are used to make the implementation of the dynamic SQL statements similar to that of static SQL The SQL statements are parsed validated and optimized and the resulting access plan is permanently stored in a SQL package Note that this process is dynamic and new statements can be added to the SQL package at the run time The IBM Toolbox for JavaJTOpen JDBC driver can take advantage of the Extended Dynamic SQL support

3

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

JDBC Data Access This section provides implementation tips and coding examples that illustrate how to optimize the access to your DB2 UDB for iSeries database from a AIX partition by using various JDBC drivers Currently IBM offers several AIX-enabled JDBC drivers that support DB2 UDB for iSeries

bull Type 4 drivers mdash IBM Toolbox for Java JTOpen and DB2 Universal JDBC Driver bull Type 2 driver mdash DB2 JDBC Type 2 Driver

The IBM Toolbox for Java iSeries driver has been implemented in pure Javatrade and optimized for accessing DB2 UDB for iSeries data It uses native iSeries protocol to communicate with the back-end database server job JTOpen is the open-source version of the IBM Toolbox for Java Licensed Program Product (LPP)

The DB2 Universal JDBC Driver is also a pure Java implementation It is a part of the DB2 UDB for AIX Version 8 product and it uses the Distributed Relational Database Architecture (DRDA) protocol for clientserver communications The driver is compatible with various DB2 UDB server platforms with appropriate DRDA Application Server (AS) level support and prerequisite stored procedures It also supports Type 2 connectivity when accessing DB2 UDB for Linuxreg UNIX and Windowsreg (DB2 UDB for LUW) databases

The traditional DB2 JDBC Type 2 Driver is built on top of DB2 Call Level Interface (CLI) It requires DB2 Connect functionality to access DB2 UDB for iSeries This is a legacy driver and IBM currently recommends that the DB2 Universal JDBC driver is used instead

Initial Configuration Considerations Practical experience shows that the JDBC application performance greatly depends on the programming techniques and the SQL access tuning However significant performance gains can be achieved by simply tweaking the AIX partition environment For example a virtual LAN connection to the back-end database can significantly streamline the data flow

4

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Virtual Versus Physical LAN One of the most significant benefits of installing AIX in an iSeries partition is the ability to utilize virtual LAN and virtual DASD This usually results in reduced hardware costs through improvements in data transfer performance and enhanced disk protection The performance tests conducted by the IBM eServer Solutions Enablement team showed that the Virtual 1Gb LAN delivered a data throughput similar to dedicated 1Gb Ethernet adapters (model 5706) connected via a dedicated Ethernet segment An example configuration is illustrated in Figure 2

Figure 2 VLAN vs 1 Gb Ethernet IOA configuration

Although similar performance can be expected for VLAN and 1Gb Ethernet the VLAN configuration has two advantages over the physical LAN connection

bull No additional communications gear is required bull It is a dedicated point-to-point connection so there is no interference from other devices on

the same network segment

On the other hand certain application scenarios may benefit from a physical LAN adapter dedicated to an AIX partition For instance in a three-tier application architecture clients connect to an application server running in a AIX partition The application server in turn connects to DB2 UDB for iSeries where data is stored and retrieved In this case configuring a separate physical LAN connection in a AIX partition has the following advantages

bull An unnecessary additional hop is eliminated from the network route bull Client-application server traffic does not unnecessarily saturate i5OS communications gear

5

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Tuning DB2 UDB for iSeries Access with IBM Toolbox for Java and JTOpen Driver This section covers JDBC implementation details for a sample Java program called TestJDBC (the source is provided at the end of this paper in Appendix A) The application uses the Java Naming and Directory Interface (JNDI) to obtain a database connection deletes 5000 records generates and inserts 5000 records and finally retrieves the newly inserted records from an SQL table called COFFEES The application executes in an AIX partition and accesses the DB2 UDB for iSeries through the JTOpen (or IBM Toolbox for Java) driver Figure 3 shows the software components involved in the execution of this simple application

Figure 3 JDBC client accessing DB2 UDB for iSeries

Apart from the JTOpen driver which can be downloaded from the IBM Toolbox for Java Web site you need three other JAR files to successfully compile and execute the JDBCTest application in a AIX partition

bull providerutiljar and fscontextjar mdashDownload a simple file system JNDI provider from Sun Microsystems JNDI Web site httpjavasuncomproductsjndidownloadsindexhtml

bull jdbc2_0-stdextjar mdash Copy the javaxsql package from the QIBMUserDataJava400ext IFS directory on the iSeries server

The location of the JAR files needs to be added to the CLASSPATH environment variable For instance the following entry could be added to the AIX profile script

6

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

CLASSPATH=homecodeJTOpenjt400jarCLASSPATH=$CLASSPATHhomecodefscontextproviderutiljarCLASSPATH=$CLASSPATHhomecodefscontextfscontextjarCLASSPATH=$CLASSPATHhomecodeJTOpenjdbc2_0-stdextjarexport CLASSPATH

To compile the source use the following command in the AIX partition

javac TestJDBCjava

Although the TestJDBC application is fairly simple it illustrates several important aspects of efficient JDBC programming for DB2 UDB for iSeries

Connection PoolingA JDBC connection can be obtained through either the DataSource or DriverManager object Either method involves significant overhead A fairly large amount of system resources is required to create and maintain the connection and then release it when it is no longer needed JTOpen allows a developer to establish a pool of database connections that can be shared by multiple client applications Connection pooling can improve the response time because the connection pool manager can locate and use an existing connection When the database request is completed the connection returns to the connection pool for reuse

In the JDBCTest sample JNDI was first used to register a connection pool-capable data source Heres an excerpt from the deployDataSource method of the sample application

Hashtable env = new Hashtable()envput(ContextINITIAL_CONTEXT_FACTORY

comsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env) [1]

Register an AS400JDBCConnectionPoolDataSource objectAS400JDBCConnectionPoolDataSource tkcpds = newAS400JDBCConnectionPoolDataSource() [2]tkcpdssetServerName(serverName) tkcpdssetDatabaseName(databaseName) tkcpdssetUser(userName) tkcpdssetPassword(password) tkcpdssetDescription(Toolkit Connection Pooling DataSourceobject) hellip ctxrebind(jdbcToolkitDataSource tkcpds) [3]

At [1] the initial JNDI context is created

Then at [2] an AS400JDBCConnectionPoolDataSource object is instantiated This is the JTOpen implementation of the javaxsqlConnectionPoolDataSource interface An AS400JDBCConnectionPoolDataSource object supports a number of methods that can be used to set iSeries-specific properties of the underlying DataSource object Some of these properties will be discussed in greater detail in the following sections of this paper

At [3] the data source object is bound to an arbitrary name that will be used in the main application Note that the deployDataSource method needs to be executed just once unless some of the data source properties need to be changed In that case the developer would need to rebind

7

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

The JNDI registered data source is then used in the main application to initialize the connection pool

AS400JDBCConnectionPoolDataSource tkcpds = [1](AS400JDBCConnectionPoolDataSource)ctxlookup(jdbcToolkitDataSource) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPool pool = newAS400JDBCConnectionPool(tkcpds)[2] Adds 1 connection to the pool that can be used by the application(creates the physical database connections based on the datasource)poolfill(1) [3] hellip con = poolgetConnection()[4]

At [1] the JNDI service is used to instantiate the AS400JDBCConnectionPoolDataSource

Then at [2] an AS400JDBCConnectionPool object is created This object is responsible for managing the connection pool

At [3] the connection pool is initialized with one connection

The pool object is used at [4] to obtain a database connection There are several additional things the developer should know about this code snippet

bull The advantage of using JNDI to register the data source object as opposed to just instantiating it in the main method is that in a more realistic scenario the data source would be registered just once at application deployment time Additionally the data source properties do not have to be hard-coded in the main method and can be changed at any time and then rebound without affecting the application

bull The AS400JDBCConnectionPool is a proprietary JTOpen implementation of a connection pool Specifically it does not implement the Referenceable interface and thus cannot be bound through JNDI services

bull The JTOpen AS400JDBCConnectionPoolDataSource does not support statement caching as described in the JDBC 30 specification Statement caching is implemented through SQL packages This feature is covered in the following section

Note The native iSeries JDBC driver supports both connection pooling and statement caching in a JDBC 30 compliant manner

8

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Extended Dynamic SQL and Statement Caching As mentioned the JTOpen data source object supports a number of properties that can be used to fine-tune the database performance In this section properties used to enable extended dynamic SQL support (see DB2 SQL Runtime Interfaces section above) and local statement caching will be discussed

Here is a relevant code excerpt from the deployDataSource method

AS400JDBCConnectionPoolDataSource tkcpds = new AS400JDBCConnectionPoolDataSource() hellip tkcpdssetExtendedDynamic(true)[1]tkcpdssetPackage(JDBCDS) [2]tkcpdssetPackageCache(true) [3]tkcpdssetPackageCriteria(select) [4]

At [1] the extended dynamic SQL support is enabled Note that the default is disabled for JTOpen The extended dynamic SQL functionality is often referred to as SQL package support The SQL packages are server-side repositories for SQL statements Packages contain the internal structures such as parse trees and access plans which are needed to execute SQL statements Because SQL packages are a shared resource the information built when a statement is prepared is available to all the users of the package This saves processing time especially in an environment where many users are using the same or similar statements Also because SQL packages are permanent this information is saved across job initiationtermination and IPLs In fact SQL packages can be saved and restored on other servers

At [2] the SQL package is named Note that the actual package name on the iSeries server is JDBCDSBAA The package name is generated by taking the name specified on the client and appending three letters that are an encoded set of the package configuration attributes By default an SQL package does not contain unparameterized select statements This behavior is overridden at [4] by setting the PackageCriteria property to select

At [3] the local statement cache is enabled A copy of the SQL package is cached on the AIX client This may improve application performance in a way similar to JDBC 30 statement caching Note however that local statement caching is not recommended for large SQL packages The copy of an SQL package is cached when the database connection is obtained This may cause increased network traffic as well as slow down the connection setup time

Reusable Open Data Paths (ODPs)An Open Data Path (ODP) definition is an internal i5OS object that is created when certain SQL statements (such as OPEN INSERT UPDATE and DELETE) are executed for the first time in a given job (or connection) The ODP can be thought of as a runtime implementation of an access plan The access plan created at the optimization time provides a recipe or in other words a sequence of steps necessary to execute the statement The ODP on the other hand provides the executable code for all requested IO operations The process of creating new ODP objects is fairly CPU- and IO-intensive so whenever possible the iSeries DB2 runtime tries to reuse existing ODPs For instance a ResultSetclose() call may close the SQL cursor but leave the ODP available to be used the next time the cursor is opened This can significantly reduce the response time in running SQL statements A reusable OPD usually requires 10 to 20 times less CPU resources than a newly created ODP Therefore it is important that the applications employ programming techniques that allow the DB2 runtime to reuse ODPs

With dynamic programming interfaces such as JDBC the most efficient way to avoid full opens is to employ the so-called prepare once execute many programming paradigm Ideally an SQL statement that is executed more than once should be prepared just once mdashfor example in the class constructor mdash and then reused for the consecutive executions At the prepare time the

9

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 engine stores the prepared statement along with the associated statement name in the QZDASOINIT jobs statement cache On the first execution the ODP created for a given statement is associated with the appropriate entry in the statement cache On consecutive executions the prepared statement and the corresponding ODP can be quickly located in the statement cache and reused The code snippet below illustrates the prepare once execute many programming technique

PreparedStatement pstmt = conprepareStatement(INSERT INTO COFFEES VALUES( ))[1] hellip for (int i = 0 i lt outerNumOfLoops i++)

insertfor (int j = 0 j lt numOfLoops j++)

pstmtsetString(1 Lavaza_ + IntegertoString(j)) hellip pstmtaddBatch()

int [] updateCounts = pstmtexecuteBatch()[2]concommit()

At [1] a PreparedStatement pstmt object is instantiated for a parameterized INSERT statement The statement is prepared just once The PreparedStatement object is then repeatedly used at [2] to perform blocked insert

Block Inserts Occasionally the developer may need to initially populate a table or insert a modified result set into a temporary table The efficiency of the insert operation for a large set of records can be dramatically improved by using the executeBatch method rather than the executeUpdate method The JTOpen driver converts parameterized insert statements in an executeBatch method to a block insert statement This significantly reduces the data flow and system resources required to perform the insert The following code snippet shows how to take advantage of the executeBatch method

10

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

PreparedStatement pstmt =conprepareStatement(INSERT INTO COFFEES VALUES( ))[1]for (int j = 0 j lt numOfLoops j++) pstmtsetString(1 Lavaza_ + IntegertoString(j))pstmtsetInt(2 i)pstmtsetFloat(3 499f)pstmtsetInt(4 0)pstmtsetInt(5 0)pstmtaddBatch() [2]

int [] updateCounts = pstmtexecuteBatch() [3]

At [1] a parameterized insert statement is prepared Note that all columns must be parameterized Otherwise the executeBatch method may throw the SQL0221 Number of rows 1 not valid exception In other words the developer should not mix parameter markers with literals or special registers in the VALUE clause

At [2] the addBatch method is used to add a new record to the client record buffer

At [3] all locally buffered data is sent to the server which in turn performs a block insert

Figure 4 shows the performance data for the executeBatch and executeUpdate methods

Figure 4 executeBatch() versus executeUpdate() performance comparison

11

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

WebSphere Considerations In certain situations an application provider may decide to deploy WebSphere Application Server in an AIX partition rather than natively in i5OS At the same time the application uses DB2 UDB for iSeries as an back-end database server Typically the WebSphere Application Server running in the AIX partition uses the virtual LAN to communicate with DB2 UDB for iSeries The WebSphere applications will access the database through a remote JDBC connection For performance and functionality reasons IBM recommends to utilize in such environments the IBM Toolbox for Java JTOpen driver Most of the tips and techniques described so far in this document hold true for WebSphere applications accessing DB2 UDB for iSeries There are however certain JDBC access aspects that are specific to this multi-tier architecture Letrsquos have a closer look at some of these considerations

Connection Pooling and Statement Caching

WebSphere Application Server provides its own connection pooling and statement caching mechanism that is by default enabled so that WebSphere applications automatically enjoy the performance benefits of these two critical programming techniques See the following link to learn more about the optimal connection pool setting in WebSphere

httppublibboulderibmcomwas40051englishinforzaiz51adminhelpudat_conpoolsethtml

Extended Dynamic SQL

For non-JTA connections WebSphere Application Server uses the comibmas400accessAS400JDBCConnectionPoolDataSource class as the iSeries JDBC provider implementation This is the DataSource implementation that has been used in all previous coding examples As mentioned the class supports a range of iSeries specific properties that can be used to fine tune JDBC performance These properties can be set through the WebSphere Application Server admin console For example herersquos the procedure to enable the extended dynamic SQL support In the WebSphere Application Server admin console navigate to the Data Source configuration dialog by selecting JDBC Providers -gt iSeriesToolbox -gt Data Sources then scroll down to the Additional Properties section Select Custom Properties link The Custom Properties dialog opens Scroll down to find the Extended Dynamic property and select it Change the default value false to true save the new configuration by clicking Apply button This is illustrated in Figure 5

12

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 5 Enabling the extended dynamic SQL through WebSphere Application Server console

The WebSphere Application Server needs to be restarted for the change to take effect The similar procedure can be followed to set other iSeries Data Source properties

Changing the WebSphere Application Server default isolation level

WebSphere Application Server V5 uses the REPEATABLE_READ (RR) isolation level for all implicit (WebSphere Application Server managed) transactions With the RR isolation level the rows selected updated deleted and inserted are locked until the end of the transaction Under certain circumstances this fairly extensive locking policy may cause locking contention especially when a WebSphere application competes for database resources with other applications that run on iSeries server For example a legacy order entry application may share data with the e-business customer care application running in WebSphere The locking contention may sometimes be eliminated by lowering the isolation level used by WebSphere Although the iSeries Data Source supports the custom transactionIsolation property resetting this property on the Data Source object will not change the default isolation level used by WebSphere for the connection objects produced by that Data Source In other words WebSphere will override the Data Source isolation level setting at the time the connection is obtained by a WebSphere application object such as servlet or Enterprise Java Bean (EJB) In order to change the default WebSphere behavior one must use the resource referencing Resource referencing allows a programmer to lookup DataSource or EJB objects using alias names rather than JNDI names Additionally by creating a resource reference a programmer can change certain properties of the underlying object Specifically a DataSource reference can be used to set a different isolation level for the connections produced by this database resource Typically resource references are defined by a programmer in a application development tool such as WebSphere Studio Application Developer The method to specify a DataSource reference differs depending on whether a programmer plans to use the reference in a servlet or in an EJB Letrsquos start with outlining the configuration process for a servlet In WebSphere Studio Application Developer open the deployment descriptor editor for the web project that contains the servlet To do so double click on the webxml file under WEB-INF directory in the web project In the deployment editor dialog select the References tab and then select Resource tab located in the top of the dialog that appears Under Resource References section select the Add button Herersquos an example of a DataSource reference created for iSeries DataSource named TestJDBCDS Note that the reference changes the default isolation level to READ_COMMITTED

13

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 6 Defining a resource reference for a servlet

Once the resource reference has been defined and saved the servlet source code needs to be changed to reflect the fact that a resource reference is used to obtain a DataSource from the JNDI service Herersquos the relevant code snippet try

ctx = new InitialContext() ds = (DataSource)ctxlookup(javacompenvTestJDBCJ2C)

catch (Exception e) eprintStackTrace(out)

Now the ds DataSource object will produce connections that by default run with the isolation level of READ_COMMITTED (RC)

As mentioned the process of defining a resource reference for an EJB differs from the process that is used in the case of a servlet In WebSphere Studio Application Developer open the deployment descriptor editor for the EJB project that contains the EJB To do so double click on the ejb-jarxml file under WEB-INF directory in the project In the deployment editor dialog select the References tab In the references section on the left locate and select the EJB for which the developer wants to change the default isolation level Click the Add button The Add Reference dialog opens Click the Resource Reference radio button and then Next Define the reference following the example shown in Figure 7

14

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 7 Adding a resource reference for an EJB

When you click ldquoFinishrdquo the reference definition is added to the EJB descriptor The new definition needs to be further modified To do so click on the (+) sign next to the EJB in the References list Click the new reference TestJDBCJ2C in this example to open the properties for the reference Change WebSphere Bindings and WebSphere Extensions sections as illustrated in Figure 8

15

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 8 Defining a resource reference for an EJB

Save the modified definition and then change the EJB source code to use the reference rather than directly DataSource

TroubleshootingTroubleshooting a multi-tier application may be a bit tricky because the developer needs to deal with software components that reside in separate partitions Three tools are particularly useful for pinning down the potential problem areas bull Joblog messages for a database server job mdash Provides enough details to isolate DB2 UDB for

iSeries runtime issues bull JDBC trace utility mdash Provides granular information about the data flow between the AIX

application and the iSeries server job bull Database Monitor ndash Provides detailed SQL runtime trace

Job Log MessagesAs mentioned a DB2 client communicates with a corresponding iSeries server job This server job runs the SQL requests on behalf of the client The iSeries database server jobs are called QZDASOINIT and they run in the QUSRWRK subsystem At any given time a large number of database server jobs may be active on the server so the first step is to identify the job that serves the particular client connection The easiest method to accomplish this task is to run the following CL command from the i5OS prompt

WRKOBJLCK OBJ(DB2USER) OBJTYPE(USRPRF)

Here DB2USER is the user profile that is used to connect to the iSeries server Note that a QZDASONIT job is assigned to a client after the connection has been established so the developer needs to set a breakpoint in the client application after the database connection has been established

Once the Work with Object Locks appears key in 5 (Work with Job) next to the only QZDASOINIT job that should be listed This shows the Work with Job dialog Select option 10 to

16

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

display the job log for the database server job Now the job log can be searched for any error messages generated by the DB2 runtime

Sometimes it is also useful to include debug messages in the job log The debug messages are informational messages written to the job log about the implementation of a query They describe query implementation methods such as the use of indexes join order ODP implementation (reusable versus non-reusable) and so on The easiest way to instruct an iSeries server to include the debug messages is to set the ServerTraceCategories property on the data source object

tkcpdssetServerTraceCategories(AS400JDBCDataSourceSERVER_TRACE_DEBUG_SERVER_JOB)

A sample of the job log messages with debug messages enabled is shown below

SET TRANSACTION completeSTATEMENT NAME FOUND QZ868F0A458E13AF8C Starting optimizer debug message for query Arrival sequence access was used for file COFFEESODP created ODP not deleted 5000 rows inserted in COFFEES in DB2USER STATEMENT NAME FOUND QZ868F0A4C144BF12EBlocking used for queryCursor CRSR0001 opened606 rows fetched from cursor CRSR0001 ODP not deleted Cursor CRSR0001 closed

So the job log offers fairly detailed information on how the AIX client requests were implemented by the DB2 runtime

JDBC Trace UtilityThe JTOpen driver provides a tracing utility which can be used to collect detailed client-side traces The JDBC tracing is turned off by default It can be enabled by setting the Trace property to true Heres an example of how to switch on tracing using the setTrace method on the data source object

tkcpdssetTrace(true)

The trace can also be enabled when using the DriverManagergetConnection() method for obtaining a connection to DB2 UDB for iSeries In this case the developer could add the trace property to the connection string This approach is illustrated in the following code snippet

ClassforName(comibmas400accessAS400JDBCDriver) [1] hellip con = DriverManagergetConnection(jdbcas400teraplextrace=true

db2userdb2pwd) [2]

At [1] an instance of the JTOpen JDBC Driver is initiated Then at [2] the driver is used to obtain a connection to the iSeries server Note how the trace property has been added to the database URL See the IBM Toolbox for Java JDBC properties documentation on the iSeries Information Center Web site for a complete list of properties supported by the JTOpen driver

Although the level of details provided by the trace utility is sufficient in most troubleshooting scenarios sometimes the developer may need to collect low-level traces scoped to a certain type

17

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

of information In V5R3 the IBM Toolbox for Java (as well as the latest JTOpen) added a comprehensive detailed trace facility The following is the complete list of detailed trace parameters and their purpose

bull None or ldquordquo ndash This setting disables the detailed trace bull datastream - This category is used by Toolbox classes to log dataflow between the local host

and the remote system It is not intended for use by application classes bull diagnostic - This category is used to log object state information bull error - This category is used to log errors that cause an exception bull information - This category is used to track the flow of control through the code bull warning - This category is used to log errors that are recoverable bull conversion - This category is used by Toolbox classes to log character set conversions

between Unicode and native code pages bull proxy - This category is used by Toolbox classes to log data flow between the client and the

proxy server bull pcml - This category is used to determine how PCML interprets the data that is sent to and

from the server bull jdbc - This category is used to track JDBC calls throughout the program bull thread - This category is used to enable tracing of thread information This is useful when

debugging multi-threaded applications bull all - This category will enable all previous categories

The detailed trace can be enabled when using the DriverManagergetConnection() method for obtaining a connection to DB2 UDB for iSeries In this case the developer could add the toolbox trace property to the connection string This is illustrated in the following code sample

String dbUrl = jdbcas400pwd1toolbox trace=diagnostic con = DriverManagergetConnection(dbUrl dbUser dbPassword)

Note that currently the driverrsquos DataSource interfaces do not allow the developer to directly activate the detailed tracing However they could set the server from the command line at the time the java program is launched The example below shows how the detailed trace properties could be enabled at the command line

java -Dcomibmas400accessTracecategory=diagnostic TestJDBC

The -D switch indicates to the java interpreter that the information following it will be a system property

In case of a WebSphere application the trace property can be set through the admin console In the console select Application Servers-gt server1-gt Process Definition -gt Java Virtual Machine Figure 9 shows how to set the Generic JVM Arguments for an application server instance

18

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 9 Setting JVM arguments to enable detailed Toolbox tracing

Database Monitor

The database monitor is the ultimate tool available on DB2 UDB for iSeries to collect low-level SQL traces It is mainly used to pin down the SQL performance problems Refer to the lsquoUsing iSeries Database Monitor to Identify and Tune SQL Queriesrsquo white paper for a detailed discussion on how to collect and analyze the database monitor traces httpibmcomserversenablesiteeducationiborecordhtmldtmon

IBM DB2 JDBC Universal Driver DB2 JDBC Universal Driver is one of the new features delivered with DB2 UDB Version 8 DB2 JDBC Universal Driver has been designed to eliminate the dependency on DB2 CLI runtime modules as well as to enable direct Type 4 connectivity to DB2 UDB for iSeries and DB2 UDB for zOSreg

The pure-Java (Type 4) remote connectivity is based on the DRDA open distributed protocol for cross-platform access to DB2 DRDA defines the rules the protocols and the semantics for accessing distributed data Applications can access data in a distributed relational environment by using SQL statements The iSeries DRDA application server implementation is based on multiple connection-oriented server jobs running in the QSYSWRK subsystem A DRDA listener job (QRWTLSTN) listens for TCP connect requests on port 446 Once an application requester connects to the listener job the listener wakes up one of the QRWTSRVR prestart jobs and assigns it to a given client connection Any further communication occurs directly between the client application and the QRWTSRVR job These concepts are illustrated in Figure 10

19

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 10 Accessing DB2 UDB for iSeries with DB2 Universal Driver

The DB2 Universal Driver can be loaded in an AIX partition by installing one of the DB2 Connect for AIX products (see the Additional Information section for details) It is also a part of a DB2 Enterprise Server Edition for AIX install Specifically the developer needs three JAR files in a AIX partition to successfully connect to an iSeries server db2jccjar db2jcc_license_cisuzjar and db2jcc_license_cujar The iSeries license is contained in db2jcc_license_cisuzjar Note that this file is not a part of DB2 Client In other words a DB2 Connect license is required to use the driver in production environments The location of the JAR files needs to be added to the CLASSPATH environment variable For instance the following entry could be added to the AIX profile script

CLASSPATH=homedb2inst2sqllibjavadb2jccjarCLASSPATH=$CLASSPATHhomedb2inst2sqllibjavadb2jcc_license_cujarCLASSPATH=$CLASSPATHhomedb2inst2sqllibjavadb2jcc_license_cisuzjarexport CLASSPATH

Java Runtime 131 is a prerequisite

Additionally the developer should install the latest database group PTF (SF99503 for i5OS V5R3) on the iSeries server The Informational APAR ii13348 is keeping track of any fixes relevant to DRDA above and beyond the current database group PTF

Obtaining a Connection to DB2 UDB for iSeries When Type 4 connectivity is used the DB2 Universal Driver connects directly to the DB2 on iSeries through TCPIP Note that this is different from the legacy DB2 Type 2 JDBC driver that requires a DB2 node and remote database configurations on the client accessing iSeries The following code snippet illustrates how to use the DB2 JDBC Universal Driver to obtain a connection to DB2 UDB for iSeries

20

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

try ClassforName(comibmdb2jccDB2Driver) [1] catch(javalangClassNotFoundException e) Systemerrprint(ClassNotFoundException )Systemerrprintln(egetMessage())

try DriverManagergetConnection(jdbcdb2teraplex446TERAPLEX[2]

db2userdb2pwd) hellip catch(SQLException ex) Systemerrprintln(

SQLException + exgetMessage())

At [1] an instance of the DB2 JDBC Universal Driver is instantiated Then at [2] the driver is used to obtain a connection to the iSeries server Note the proper form of the database URL required by the driver

Considerations There are several advantages of DB2 JDBC Universal Driver bull Ease of cross-platform development mdash Consistent coding techniques and consistent error

codes and messages bull Ease of deployment mdash Pure Java (no runtime client required) and a single driver for accessing

DB2 on different platforms

The ease of use comes at a price though The iSeries JTOpen driver is optimized for accessing DB2 UDB for iSeries data and it uses native iSeries protocol to communicate with the back-end database server job This usually results in better performance and more-efficient system resources utilization For instance when using the DB2 JDBC Universal Driver to access an iSeries server the executeBatch method results in a single record insert There are also some restrictions when using DB2 Universal JDBC Driver with Type 4 connectivity

bull Support for distributed transactions (JTA) is not enabled bull Driver built-in connection pooling is not supported

Refer to Java application support in DB2 for more details on DB2 JDBC Universal Driver

21

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 Connect data access This section will explore the most important aspects of DB2 Connect ndash iSeries integration - including configuration tips and coding examples

DB2 Connect provides functionality for accessing data stored in DB2 UDB for iSeries as well as DB2 UDB for zOS and DB2 UDB for OS390reg DB2 Connect offers capabilities to access DB2 family members via several SQL interfaces gateway functions such as connection pooling and federated database functionality Many applications supporting the DB2 family of products leverage DB2 Connect as a key middleware component DB2 Connect is offered as separate AIX license products

Enterprise Edition Application Server Edition

In addition to DB2 Connect there are several other DB2 UDB Version 81 products that are supported on AIX

DB2 Universal Database Enterprise Server Edition DB2 Universal Database Workgroup Server Unlimited Edition DB2 Universal Database Workgroup Server Edition DB2 Universal Database Universal Developers Edition All Clients

The DB2 Connect Enterprise Edition functionality is also contained in DB2 Enterprise Server Edition for AIX

22

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 Connect in a nutshell In the scenario described in this paper the DB2 Connect functions contained in DB2 Enterprise Edition for AIX are utilized DB2 Connect Enterprise Edition provides support for both local and remote DB2 clients This is illustrated in Figure 11 Accessing DB2 UDB for iSeries with DB2 Connect

Figure 11 Accessing DB2 UDB for iSeries with DB2 Connect

DB2 Connect implements the Distributed Relational Database Architecturetrade (DRDAreg) to reduce the cost and complexity of accessing data stored in DB2 UDB for iSeries and other DRDA-compliant database servers DRDA defines the rules the protocols and the semantics for accessing distributed data Applications can access data in a distributed relational environment by using SQL statements In a distributed environment the system running the application and sending the SQL requests across the network is called the application requester (AR) A remote database server that executes SQL requests submitted by an application requester is known as the application server (AS) In the example shown in Figure 11 (above) DB2 Connect plays the role of an application requester while DB2 UDB for iSeries is an application server In this case DB2 Connect communicates with the iSeries database through TCPIP The iSeries DRDA application server implementation is based on multiple connection-oriented server jobs running in the QSYSWRK subsystem A DRDA listener job (QRWTLSTN) listens for TCP connect requests on port 446 Once an application requester connects to the listener job the listener wakes up one of the QRWTSRVR prestart jobs and assigns it to a given client connection Any further communication occurs directly between the client application and the QRWTSRVR job

DB2 Connect supports a wide range of programming interfaces that can be used by AIX applications to access the iSeries database Embedded SQL frac34 Both static and dynamic SQL frac34 Various programming languages (Java CC++ Cobol Fortran REXX)

DB2 Call Level Interface (DB2 CLI) ODBC JDBC frac34 DB2 JDBC Type 2 Driver frac34 DB2 JDBC Type 4 Driver (Universal JDBC Driver)

23

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Note that DB2 Connect supports access to DB2 UDB for iSeries through DB2 JDBC Universal driver However for performance and ease of maintenance reasons IBM recommends that Java applications running in AIX use native iSeries Toolbox JDBC driver See the JDBC Data Access section of this paper (above) for more details On the other hand DB2 Connect is a very efficient and robust connectivity option for AIX applications especially in the environments that are not directly supported by the native iSeries JDBC driver Here are several possible scenarios that would require DB2 Connect installed in a AIX partition

Embedded SQL interface is used to access DB2 CLI or ODBC interface is used to access DB2 A single SQL interface is needed to access multiple back end DB2 server Specific DB2 Connect functionality is needed such as distributed join or connection

pooling

Prerequisites One of the DB2 Connect products or DB2 Enterprise Server Edition for AIX V81 is needed Additionally DB2 Application Development Client is required in the AIX partition to compile DB2 applications

For maximum database server stability the developer should install the latest database group PTF (SF99503 for i5OS V5R3) on the iSeries server The Informational APAR ii13348 is keeping track of any fixes relevant to DRDA above and beyond the current database group PTF

DB2 Connect configuration The following example employs i5OS V5R3 and DB2 UDB Enterprise Server Edition for AIX Version 81 FixPak 6

Configuration steps in the iSeries partition The following process lists the necessary steps to be performed on the iSeries server 1) Verify that the TCPIP stack is working correctly It is assumed that the Virtual LAN is used to

communicate with the i5OS partition First obtain the IP address of the iSeries server or its hostname and ping the iSeries server from the AIX partition

2) Create a relational database (RDB) entry for the iSeries database in the i5OS partition If this has already been created it can be displayed by using the DSPRDBDIRE command Make sure that the RDB entry with a location of LOCAL exists on the iSeries server If it does not exist use the ADDRDBDIRE command to add the appropriate RDB entry For example the following command would add an RDB entry named TPLX For simplicity it is recommended that the TCPIP host name and RDB entry remain the same

ADDRDBDIRE RDB(TPLX) RMTLOCNAME(LOCAL)

3) Create a collection called NULLID This is necessary because the utilities shipped with DB2 Connect and DB2 UDB for AIX store their packages in the NULLID collection Since it does not exist by default in the iSeries server you must create it using the following command

CRTLIB LIB(NULLID)

4) Products that support DRDA automatically perform any necessary code page conversions at the receiving system For this to happen both systems need a translation table from their code page to the partner code page The default Coded Character Set Identifier (CCSID) on the iSeries server is 65535 Since DB2 Connect does not have a translation table for this code page the developer needs to change the individual user profiles to contain a CCSID that can be converted properly by DB2 Connect For US English this is 037 For other languages see DB2 Connect Personal Edition Quick Beginning GC09-2967 The following command changes the CCSID for an individual user profile to 037

24

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

CHGUSRPRF userid CCSID(037)

5) Verify that the default port 446 for DRDA service is being used To do this go to the Configure TCPIP menu (CFGTCP) select Configure Related Tables and then select Work with service table entries Verify that the DRDA service is set for port 446

6) The Distributed Data Management (DDM) job must be started for DRDA to work If you want the DDM job to be automatically started whenever TCPIP is started change the attributes of the DDM job using the CHGDDMTCPA command and set the Autostart server parameter to YES

7) If the system administrator chooses not to autostart the server issue the following command to start the DDM server job

STRTCPSVR SERVER(DDM)

8) Make sure that the user profiles that will be used to connect to the iSeries server exist on the server

25

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Configuration steps in the AIX partition The following steps are required for DB2 Connect to be configured in the AIX partition 1) Sign on to the AIX partition as the DB2 administrator 2) Launch Client Configuration Assistant (db2ca from the command prompt) It is assumed that

VNC or an X-Windows server are being used on the workstation so that the db2ca GUI can be properly rendered

3) From the Selected pull-down menu select the Add Database using Wizard option The Select how you want to setup a connection dialog appears Select Manually configure a connection to a database and click Next This is shown in Figure 12

Figure 12 Accessing DB2 UDB for iSeries with DB2 Connect

26

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

4) On the Select a communications protocol choose TCPIP and select The database physical resides on a host or OS400 system Then select the option Connect directly to the server as shown in Figure 13 Click Next

Figure 13 mdash Selecting communications protocol

27

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

5) On the TCPIP tab fill in the host name of the iSeries server The port number should be 446 This is shown in Figure 14 Click Next

Figure 14 mdash Specifying TCPIP communication parameters

28

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

6) On the Database tab fill in the Relational Database name Use the RDB entry name (specified in step 2) in the Configuration steps in the iSeries partition section as shown in Figure 15 Click Next

Figure 15 mdash Specifying the remote database

7) If you plan to use the ODBC applications select Register this database for ODBC as a system data source on the ODBC tab Click Next

29

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

8) On the Specify the node option dialog select OS400 from the Operating System pull-down menu This is shown in Figure 16 Click Finish

Figure 16 mdash Specifying the node options

30

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

9) The Test Connection dialog appears This allows the developer to verify that the connection works Select both CLI and JDBC check boxes You are also prompted for an iSeries user ID and password as shown in Figure 17

Figure 17 mdash Testing the connection

31

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

10) The successful connection to the database server is confirmed by the message box shown in Figure 18

Figure 18 mdash Test Connection results 11) At this time a newly configured database connection should appear in the main DB2

Configuration Assistant window It is recommended that the DB2 utilities are also bound to the iSeries database The bind process creates the necessary SQL packages on the remote database In the main Configuration Assistant window click the TPLX database entry and then select Selected-gtBindhellip

32

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

12) The Bind dialog appears Click Select All and then enter the connection information as shown in Figure 19 Click Bind The Results message box appears This allows the developer to monitor the progress of the binding process Watch for any error and warning messages

Figure 19 mdash Binding the DB2 utilities This concludes the DB2 Connect configuration steps

33

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Accessing DB2 UDB for iSeries from C embedded SQL

As mentioned earlier DB2 Connect allows developers to compile and run embedded SQL applications that access DB2 UDB for iSeries data This section covers implementation details for a C embedded SQL application called cursorsjsqc (see Appendix B for source code)

Prerequisites An embedded SQL application running in an AIX partition will use DB2 Connect services to access DB2 UDB for iSeries therefore the developer needs to make sure that all components listed in section Prerequisites on page 24 are installed The developer also needs to create a remote database connection as described in the DB2 Connect configuration section of this paper on page 24

Static SQL and SQL packages To successfully run against a DB2 UDB for iSeries database an embedded SQL application needs to be first precompiled and bound to the back-end database This process creates an SQL package on the target iSeries server The SQL package contains the access plan information for the SQL statements executed by the application The internal structure of the package as well as the method how its content is used by the SQL runtime to facilitate the access plan reuse is similar to the Extended Dynamic SQL support covered in detail in the Extended Dynamic SQL and Statement Caching section of this paper (on page 9) There are however important differences between the packages created by the extended dynamic SQL support and the packages created for embedded SQL DRDA client applications The extended dynamic SQL packages support dynamic SQL interfaces such as JDBC

that can submit ad hoc SQL statements at the run time The SQL runtime can prepare the dynamic statements and add them to the package On the other hand the DRDA packages are created at the precompile time and contain static SQL In order to add new statements to the package the application needs to be precompiled and rebound again

The extended dynamic SQL package can dynamically grow up to 500MB by allocating new space as required The DRDA packages since they are created at the precompile time have a fix size and do not grow over their life time

Simple embedded SQL application The application is based on a source code provided in the DB2 UDB samples directory typically to be found at homedb2inst1sqllibsamples The cursorsjsqc performs a join between STAFF and ORG tables located in DB2USER schema (library) on the TPLX database server (the source is provided at the end of this paper in Appendix B) The join statement retrieves the DEPTNAME column from ORG NAME column from STAFF and calculates the total compensation for an employee by adding SALARY and COMM columns in STAFF The results are sorted by department name and total compensation Here is the SELECT statement used by the application

SELECT deptname name salary + IFNULL(comm0) as compensationFROM org o staff sWHERE odeptnumb = sdeptORDER BY deptname compensation DESC

The application iterates through the selected records and prints out the data to the standard output device The sample DB2USER schema was created with the following SQL statements

db2 CONNECT TO tplx USER db2user USING mypassworddb2 CALL QSYSCREATE_SQL_SAMPLE(DB2USER)

34

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Make sure that the AIX partition is logged into with the DB2 admin user profile If the defaults were selected at the DB2 installation time this profile name is db2inst1 It is also assumed that DB2USER user exists on the iSeries server and that it has appropriate authority

There are several steps that are required to create an executable for the cursorsjsqc source code First the DB2 PRECOMPILE utility needs to be called The utility creates a bind file that is used to bind the required SQL package to the TPLX database It also converts embedded SQL statements into DB2 run-time API calls and produces a pure C source file that can be processed by an AIX C compiler

db2 CONNECT TO tplx USER db2user USING mypassworddb2 prep cursorsjsqc bindfile

Note that the connect statement is required only if the developer is not already connected to the database on an iSeries server Watch for any error or warning messages returned by the DB2 prep utility The prepare step should produce cursorsjbnd and cursorsjc files in the current directory Now the developer can invoke the bind utility to prepare the statements contained in the bind file and create the package on the target iSeries database server

db2 bind cursorsjbnd

It is assumed that Visual C++ 60 is installed and configured in the AIX partition Refer to the ldquoDeveloping and Porting C and C++ Applications on AIXrdquo redbook for more information on how to use the Visual C++ compiler httpibmcomredbooksabstractssg245674htmlOpen

Use the following commands to compile the C source generated by the precompile utility

xlc -I$INSTHOMEsqllibinclude ndashc cursorsjcxlc ndasho cursorsj cursorsjo -L$INSTHOMEsqlliblib ndashldb2

Run the program from the AIX prompt

cursorsj db2user mypassword

Distributed Join DB2 UDB Version 8 provides core federated server functionality A federated system consists of a DB2 UDB instance that operates as a federated server a database that acts as the federated database one or more data sources and clients (users and applications) that access the database and data sources Federated server permits objects stored in multiple databases to be accessed together in the same query For example a query can refer to a table that resides in DB2 UDB for iSeries and join it to a table stored in DB2 UDB for AIX Such a query would constitute so called distributed join The support for DB2 UDB for iSeries as a federated data source is provided by core federated server functionality directly implemented in DB2 UDB Enterprise Server Edition and DB2 UDB Connect Enterprise Edition All other DB2 UDB family members are also supported directly by core DB2 UDB federated server An additional software product DB2 Information Integratortrade is required to access non-DB2 UDB databases such as Oracle Sybase or Microsoftreg SQL Server Consult the following white papers for a detailed discussion on DB2 federated server support Heterogeneous data access for iSeries applications Version 2 httpibmcomserversenablesiteeducationiborecordhtmlhetdata Fundamentals of IBM DB2 Federated Server and Relational Connect httpwww7bsoftwareibmcomdmddlibrarytecharticle0206purnell0206purnellhtml

35

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Distributed Join Example In this section the steps that are required to configure DB2 UDB for iSeries as a federated data source will be illustrated Then the cursorsjsqc program will be ldquotweakedrdquo so that it executes a distributed join query that accesses data stored on an iSeries server and in the local DB2 UDB for AIX database It is assumed that the developer is familiar with the DB2 federated server concepts

Note Run the following commands from the Command Line Processor prompt Load the utility by executing the db2 command at the AIX prompt 1) First the local DB2 UDB for AIX instance needs to be enabled as a DB2 federated server

This is done by setting the database manager configuration parameter FEDERATED to YES

db2=gt update dbm cfg using FEDERATED YES

The database instance needs to be restarted for the change to take effect

NOTE A federated database is a regular database in a DB2 UDB instance that has the FEDERATED parameter enabled Therefore in this example the SAMPLE database that was created earlier is used as the federated database A new database can also be created using the CREATE DATABASE command

2) Connect to the federated database

db2=gt connect to sample

3) Use the CREATE WRAPPER statement to register a wrapper for the iSeries data source Wrappers are library routines that are used by the federated server to perform operations such as connecting to a data source and retrieving data from it The default wrapper name for DB2 UDB for iSeries is DRDA Here is the command to register the DRDA wrapper

db2=gt create wrapper drda

4) Use the CREATE SERVER statement to register a data source as a server within the federated database The server definition specifies the type and version of the data source and the wrapper used for communications with this data source For the DB2 UDB for iSeries data source the node and the database names are also needed The node and database name parameters have been configured for our TPLX database in the Configuration steps in the AIX partition section (on page 24) Use the following DB2 UDB command to lookup these parameter on the federated server

db2=gt list database directory

In this case the command produced the following output

Database alias = TPLX Database name = DCSE99E1 Node name = NDE9BF76 Database release level = a00 Comment = Directory entry type = Remote Authentication = SERVER Catalog database partition number = -1

36

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Note that the node name is set to NDE9BF76 The name was generated by the Configuration Administrator utility (db2ca)

Here is the command to register the TPLX database as a federated server

db2=gt create server tplx type db2400 version 530 wrapperdrda authorization db2user password mypassword options(nodeNDE9BF76 dbname TPLX)

The command is quite complex so make sure that the syntax is correct

5) Define the user mappings that instructs the federated server what user ID and password should be used when connecting to the iSeries data source

db2=gt create user mapping for user server tplxoptions(remote_authid db2user remote_password mypassword)

Specify the nickname for the iSeries table or view A nickname is an identifier that is used by the federated server to reference an object located at the data source The following command creates a nickname for the STAFF table located in the DB2USER schema on the TPLX database

db2=gt create nickname tplx_staff for tplxdb2userstaff

6) Test the distributed join query

db2=gt SELECT deptname name salary + COALESCE(comm0) ascompensation FROM org o tplx_staff s WHERE odeptnumb =sdept ORDER BY deptname compensation DESC

Note that the native iSeries function IFNULL has been substituted with an equivalent DB2 UDB function COALESCE COALESCE is also supported on iSeries servers For better portability IBM encourages the use of COALESCE rather than IFNULL Note also that the query runs on the federated server rather than on TPLX It accesses the ORG table in the local DB2 UDB for AIX SAMPLE database and the STAFF table that resides in TPLX The federated server performs the necessary distributed join

7) Modify the cursorsjsqc so that it executes a distributed join There are two source code modifications - Change the CONNECT TO statements Now the application needs to connect to the

federated database SAMPLE rather than to TPLX

EXEC SQL CONNECT TO SAMPLEEXEC SQL CONNECT TO SAMPLE USER userid USING passwd

- Modify the select statement so that it performs a distributed join Use the statement (shown in step 6) above Save the new source version as cursordjsqc

- Prepare bind and compile the distributed join version of the program as described in the Simple C embedded SQL application section (on page 34)

db2 prep cursordjsqc bindfiledb2 bind cursordjbndxlc -I$INSTHOMEsqllibinclude ndashc cursordjcxlc ndasho cursordj cursordjo -L$INSTHOMEsqlliblib ndashldb2

37

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

- Run the program from the AIX prompt

cursordj

Connection Pooling and Connection ConcentratorA modern Web-based application typically executes a large number of short-lived transactions Executing a transaction in this environment means establishing a database connection executing a few SQL statements and terminating this connection Creating connections to the database server is a very costly process To reduce the unnecessary workload DB2 Connect implements connection pooling and connection concentrator Connection pooling mechanism allows DB2 Connect to reuse an existing connection infrastructure for subsequent connection requests The connection concentrator is an advanced technology that allows DB2 Connect to serve a potentially very large number of clients with a limited number of database connections This is accomplished by decoupling clients from a particular database connection

Note that currently neither connection pooling nor connection concentrator support DB2 UDB for iSeries Therefore for performance reasons the author strongly recommends that the application server that obtains and drops connections very frequently implements its own database connection pooling mechanism that would assign an existing pooled database connection to a new AIX process or thread

TroubleshootingTroubleshooting a multi-tier application may be a bit tricky because the developer needs to deal with software components that reside in separate partitions The authorrsquos experience shows that two tools are particularly useful for pinning down the potential problem areas The joblog messages for a database server job usually provide enough details to isolate DB2

UDB for iSeries runtime issues The DRDA trace utility provides granular information about the data flow between the AIX

application and the iSeries server job

38

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Job Log MessagesAs mentioned earlier a DB2 client communicates with a corresponding iSeries server job This server job runs the SQL requests on behalf of the client More precisely when a DB2 client submits an SQL statement the statement is passed to a server job that in turn calls the DB2 runtime to execute the statement The results are then reformatted and marshaled to the client The iSeries DRDA server jobs are called QRWTSRVR and they run in the QUSRWRK subsystem At any given time there may be a large number of DRDA server jobs active on the system so the first step is to identify the job that serves the particular client connection The easiest method to accomplish this task is to run the following CL command from the i5OS prompt

WRKOBJLCK OBJ(DB2USER) OBJTYPE(USRPRF)

Here DB2USER is the user profile that is used to connect to the iSeries server Note that a QRWTSRVR job is assigned to a client after the connection has been established so the developer needs to set a breakpoint in the client application below the CONNECT TO statement

Once the Work with Object Locks appears key in 5 (Work with Job) next to the only QRWTSRVR job that should be listed This shows the Work with Job dialog Select option 10 to display the job log for the database server job Now the developer can search the job log for any error messages generated by the DB2 runtime

Sometimes it is also useful to include debug messages in the job log The debug messages are informational messages written to the job log about the implementation of a query They describe query implementation methods such as use of indexes join order ODP implementation (reusable versus non-reusable) and so on The easiest way to instruct the iSeries server to include the debug messages is to call the following stored procedure just after the connection to the iSeries server is established

EXEC SQL call qsysqcmdexc(STRDBGUPDPROD(YES)000000002000000)

A sample of the job log messages with debug messages enabled is shown below in Figure 20

Arrival sequence access was used for file STAFFAccess path suggestion for file STAFFQuery options used to build the OS400 query access plan Ending debug message for query ODP created Blocking used for queryCursor SQLCUR201 opened1 rows fetched from cursor SQLCUR201Row not found for SQLCUR201ODP deleted Cursor SQLCUR201 closedDESCRIBE of prepared statement STMT0201 completed

Figure 20 mdash Joblog with debug messages enabled

So the job log offers fairly detailed information on how the AIX client requests were implemented by the DB2 runtime

39

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 DRDA trace utilityThe DB2 DRDA trace utility (db2drdat) provides detailed information about the data streams exchanged between DB2 Connect and target database server The output file produced by the utility contains send and receive communications buffers TCPIP error messages and SQL Communications Area (SQLCA) information Please refer to lsquoDB2 Connect Userrsquos Guidersquo manual for in-depth discussion of the DRDA trace utility

Accessing DB2 UDB for iSeries from CLI DB2 Call Level Interface (CLI ) is based on the Microsoft Open Database Connectivity (ODBC) specification and the ISO CLI standard The DB2 CLI interface gained popularity among DB2 application providers because the developer can build an ODBC application by simply linking the application with libdb2 library on a UNIX server In other words the developer directly utilizes the DB2 ODBC driver services without a need for an ODBC driver manager Additionally in contrast to embedded SQL the developer does not need to precompile or bind DB2 CLI applications because they use packages provided with DB2 UDB The developer simply compiles and links the application

Prerequisites A DB2 CLI application running in an AIX partition will use DB2 Connect services to access DB2 UDB for iSeries therefore make sure that all components listed in Prerequisites section of this paper on page 24 are installed The developer also needs to create a remote database connection as described in the DB2 Connect configuration section of this paper on page 24

Dynamic SQL and Access Plan Caching A DB2 CLI client application uses the dynamic SQL interface and does not have the capability to utilize the extended dynamic SQL support Therefore it runs lsquopurersquo dynamic SQL statements That does not mean however that the process of parsing validating and optimizing will be repeated for every execution of a given dynamic SQL statement

The DB2 UDB for iSeries database implements an internal object called System-Wide SQL Statement Cache (SWSC) The SWSC can improve the performance of programs using dynamic SQL statements by caching the access plans in a system-wide cache When a dynamic SQL statement is submitted the SQL runtime searches the SWSC to see if this statement has been previously executed If so then DB2 retrieves and reuses the key information associated with the cached statement and thereby the processing time and the resources utilization can be significantly reduced

Simple DB2 CLI C++ ApplicationThis section covers DB2 CLI implementation details for a sample C++ program called testclicpp (the source is provided at the end of this paper in Appendix C) To compile the source with Visual C++ complier use the following command in the AIX partition

xlC ndashI$INSTHOMEsqllibinclude ndashc testclicppxlC ndasho testcli testclio ndashL$INSTHOMEsqlliblib ndashldb2

The application performs a join between STAFF and ORG tables located in DB2USER schema (library) The join statement retrieves the DEPTNAME column from ORG NAME and JOB columns from STAFF and calculates the total compensation for an employee by adding SALARY and COMM columns in STAFF The results are sorted by total compensation The selection criterion is based on the current value of the department name parameter Here is the SELECT statement used by testcli

40

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

select name job salary + coalesce(comm0) as compensationfrom org o staff swhere odeptnumb = sdeptand deptname = order by compensation desc

Figure 21 shows the software components involved in the execution of this sample application

Figure 21 How a DB2 CLI client accesses DB2 UDB on an iSeries server

Although the testcli application is fairly simple it covers some important aspects of efficient CLI programming for DB2 UDB for iSeries

Reusable Open Data Paths (ODPs)An Open Data Path (ODP) definition is an internal i5OS object that is created when certain SQL statements (such as OPEN INSERT UPDATE and DELETE) are executed for the first time in a given job (or connection) The ODP can be thought of as a runtime implementation of an access plan The access plan created at the optimization time provides a recipe or in other words a sequence of steps necessary to execute the statement The ODP on the other hand provides the executable code for all requested IO operations The process of creating new ODP objects is fairly CPU- and IO-intensive so whenever possible the iSeries DB2 runtime tries to reuse existing ODPs For instance a SQLCloseCursor() API call may close the SQL cursor but leave the ODP available to be used the next time the cursor is opened This can significantly reduce the processing and response time in running SQL statements A reusable OPD usually requires 10 to 20 times less CPU resources than a newly created ODP Therefore it is important that the applications employ programming techniques that allow the DB2 runtime to reuse ODPs

With dynamic interfaces such as CLI full opens are avoided by using a prepare once execute many programming paradigm It means that when an SQL statement is going to be executed more than once you should prepare the statement just once and then reuse the prepared

41

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

statements for consecutive executions Although DB2 UDB does try to convert literals to parameter markers so that similar statements can be reused it is a better programming practice to explicitly implement parameter markers That way the chances for reusable ODPs are quite significantly improved The code snippet in Figure 22 illustrates how to implement the prepare once execute many programming technique

Define A SELECT SQL Statementstrcpy((char ) SQLStmt select name job salary + ifnull(comm0) ascompensation )ptr = strcat( (char ) SQLStmt from org o staff s )ptr = strcat( (char ) SQLStmt where odeptnumb = sdept)ptr = strcat( (char ) SQLStmt and deptname = )ptr = strcat( (char ) SQLStmt order by compensation desc) [1]

Prepare The SQL Statementrc = SQLPrepare(ExampleStmtHandle SQLStmt SQL_NTS) [2]

Bind The Columns In The Result Data Set Returned To Application Variablesrc = SQLBindCol(ExampleStmtHandle 1 SQL_C_CHAR (SQLPOINTER)

ExampleName sizeof(ExampleName) NULL)rc = SQLBindCol(ExampleStmtHandle 2 SQL_C_CHAR (SQLPOINTER)

ExampleJob sizeof(ExampleJob) NULL)rc = SQLBindCol(ExampleStmtHandle 3 SQL_C_DOUBLE (SQLPOINTER)

ampExampleComp sizeof(ExampleComp) NULL)

for (int i = 0 i lt LOOPS i++)rc=SQLBindParameter(ExampleStmtHandle

1SQL_PARAM_INPUTSQL_C_CHARSQL_CHAR10(SQLPOINTER) currentDepartment[i8]0NULL) [3]

rc = SQLExecute(ExampleStmtHandle) [4]cout ltlt endl ltlt Current Dept ltlt currentDepartment[i8] ltlt endl Display The Results Of The SQL QueryExampleShowResults()

Figure 22 Use the prepare once execute many programming technique

The error-handling code has been removed for clarity At [1] the statement text is assigned to a variable Note that a parameter marker is used in the WHERE clause The statement is then prepared just once at [2] The current value of the parameter is bound to the prepared statement at [3] The prepared statement is executed at [4] Steps [3] and [4] are repeatedly executed in a for loop

Techniques to Further Improve DB2 CLI Performance Thus far this paper has discussed the techniques used by a sample application to tune the CLI performance However depending on the application architecture other methods of improving CLI performance may be considered

Connection PoolingCurrently the CLI application connecting through DB2 Connect to DB2 UDB for iSeries does not take advantage of the connection pooling mechanism implemented by DB2 Connect Therefore for performance reasons the author strongly recommends that the application server that obtains and drops connections very frequently implements its own database connection pooling mechanism that would assign an existing pooled database connection to a new AIX process or thread

42

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Blocking

For queries which result in returning large data blocks from the iSeries server (usually 32K of data and above) ensure that the database manager configuration parameter RQRIOBLK is set to 32767 This can be done using the Command Line Processor (CLP) as follows

db2 update database manager configuration using RQRIOBLK 32767

TroubleshootingThe experience of the author shows that two tools are particularly useful for pinning down the potential problem areas bull Joblog messages for a database server job usually provides enough details to isolate DB2

runtime issues bull CLI trace utility provides granular information about the data flow between the AIX application

and the database server job

Job Log MessagesThe process of finding and analyzing the job log for a DB2 CLI connection is identical to the process outlined for an embedded SQL application in the Job Log Message section of this paper on page 39

CLI Trace The DB2 CLIODBCJDBC trace utility provides very detailed information about the data streams exchanged between DB2 Connect and target database server Refer to the DB2 Information Center for more information on how to set up and analyze the CLI traces httppublibboulderibmcominfocenterdb2v8luwindexjsptopic=comibmdb2udbdocadc000 7959htm

43

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Trademarks

IBM eServer iSeries AIX AIX 5L i5OS WebSphere DB2 DB2 Universal Database DB2 Connect OS400 zOS OS390 Distributed Relational Database Architecture DRDA and DB2 Information Integration are trademarks or registered trademarks of International Business Machines Corporation in the United States and other countries

Java and all Java-based trademarks are trademarks of Sun Microsystems Inc in the United States other countries or both

Linux is a registered trademark of Linus Torvalds in the United States other countries or both

UNIX is a registered trademark of The Open Group in the United States and other countries

Microsoft and Windows are registered trademarks of Microsoft Corporation in the United States andor other countries

All other registered trademarks and trademarks are properties of their respective owners

IBM makes no commitment to make available any products referred to herein

References in this publication to IBM products or services do not imply that IBM intends to make them available in every country in which IBM operates

Additional Information ITSO offers a Redbook that can be helpful to those who want to learn more about i5OS AIX integration

bull AIX Integration with I5OS on the IBM eServer iSeries Server (SG24-6551)

Jarek Miszczyk is the Senior Software Engineer IBM eServer Solutions Enablement IBM Rochester

[Portions of this white paper reprinted with permission from MC Mag Online published by MC Press LLP httpwwwmcpressonlinecom]

Acknowledgments The author would like to thank the following people for their advice contributions and support on this paper

Bob Bittner IBM Rochester Jon Rush IBM Rochester Prasad Vallurupalli IBM Rochester Neil Willis IBM Rochester

44

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix A Source Listing of TestJDBCjava

package comibmiseriespwdimport javasqlimport javaxnamingimport javautilHashtableimport javautilimport javaxsqlimport comibmas400access

public class TestJDBC public static void main(javalangString[] args)

throws Exception

int numOfLoops = 5000int outerNumOfLoops = 5boolean firstExec = trueConnection conStatement sPreparedStatement psPreparedStatement pstmtdelCallableStatement cstmPreparedStatement pstmtHashtable env = new Hashtable()

envput(ContextINITIAL_CONTEXT_FACTORYcomsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env)Systemoutprintln(Deploying connection pooling data source)deployDataSource() Do the work with connection pooling onlyAS400JDBCConnectionPoolDataSource tkcpds =

(AS400JDBCConnectionPoolDataSource)ctxlookup(jdbcToolkitDataSource) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPool pool = new AS400JDBCConnectionPool(tkcpds) Adds 1 connection to the pool that can be used by theapplication (creates the physical database connections based onthe data source)poolfill(1)Systemoutprintln(nStart timing Toolkit connection pooling)long startTime = SystemcurrentTimeMillis()

for (int i = 0 i lt outerNumOfLoops i++) con = poolgetConnection()consetAutoCommit(false) deleteif ( i == 0)

long startDelete = SystemcurrentTimeMillis()cstm = cstm = conprepareCall(

CALL qsysqcmdexc(CLRPFM FILE(DB2USERCOFFEES) + 000000002800000))

cstmexecuteUpdate()cstmclose()long endDelete = SystemcurrentTimeMillis()Systemoutprintln(Delete all records +

(endDelete - startDelete) + ms elapsed)

45

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

String sqlinstrlong startInsert = SystemcurrentTimeMillis() insert

pstmt =conprepareStatement(INSERT INTO COFFEES VALUES( ))for (int j = 0 j lt numOfLoops j++) pstmtsetString(1 Kona_ + IntegertoString(i))pstmtsetInt(2 150)pstmtsetFloat(3 999f)pstmtsetInt(4 0)pstmtsetInt(5 0)pstmtaddBatch()int [] updateCounts = pstmtexecuteBatch()concommit()pstmtclose()long endInsert = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for + numOfLoops + inserts

+ (endInsert - startInsert)) selectlong startSelect = SystemcurrentTimeMillis()ps = conprepareStatement(SELECT FROM COFFEES)ResultSet rs = psexecuteQuery()rsnext()rsclose()concommit()psclose()long endSelect = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for select +

(endSelect - startSelect))consetAutoCommit(true)conclose()long endTime = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for + outerNumOfLoops +

loops + (endTime - startTime))Systemexit(0)

private static void deployDataSource()throws ExceptionString serverName = teraplex String databaseName = TERAPLEX String userName = db2user String password = db2pwd

Establish a JNDI context and bind the connection pool data sourceHashtable env = new Hashtable()envput(ContextINITIAL_CONTEXT_FACTORY

comsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPoolDataSource tkcpds = new

AS400JDBCConnectionPoolDataSource()tkcpdssetServerName(serverName) tkcpdssetDatabaseName(databaseName) tkcpdssetUser(userName) tkcpdssetPassword(password) tkcpdssetDescription(Toolkit Connection Pooling DataSource)tkcpdssetSavePasswordWhenSerialized(true)tkcpdssetExtendedDynamic(true)

46

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

tkcpdssetPackage(JDBCDS)tkcpdssetPackageCache(true)tkcpdssetPackageCriteria(select)enable the following properties as requiredcpdssetTrace(true)tkcpdssetServerTraceCategories( AS400JDBCDataSourceSERVER_TRACE_DEBUG_SERVER_JOB)

ctxrebind(jdbcToolkitDataSource tkcpds)

47

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix B mdash Source Listing of cursorsjsqc

Source File Name = cursorsjsqc Licensed Materials - Property of IBM (C) COPYRIGHT International Business Machines Corp 1995 2000 2004 All Rights Reserved US Government Users Restricted Rights - Use duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp PURPOSE This sample program demonstrates the use of a CURSOR The CURSOR is processed using static SQL EXTERNAL DEPENDENCIES - Ensure existence of database for precompile purposes - Precompile with the SQL precompiler (PREP in DB2) - Bind to a database (BIND in DB2) - Compile and link with the IBM Cset++ compiler (AIX and OS2) or the Microsoft Visual C++ compiler (Windows) or the compiler supported on your platform For more information about these samples see the README file For more information on programming in C see the - Programming in C and C++ section of the Application Development Guide For more information on building C applications see the - Building C Applications section of the Application Building Guide For more information on the SQL language see the SQL Reference

include ltstdiohgt include ltstdlibhgt include ltstringhgtinclude ltsqlhgtinclude ltsqlenvhgtinclude ltsqldahgtinclude ltsqlcahgt

int SqlInfoPrint( char struct sqlca int char )void TransRollback( void)

define EMB_SQL_CHECK( MSG_STR ) rc = SqlInfoPrint( MSG_STR ampsqlca __LINE__ __FILE__) if ( rc = 0 ) TransRollback( )

return 1

EXEC SQL INCLUDE SQLCA

int main(int argc char argv[])

EXEC SQL BEGIN DECLARE SECTIONchar dname[15]

48

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

char pname[10]double compchar userid[9]char passwd[19]

EXEC SQL END DECLARE SECTION

int rc = 0printf( Sample C program CURSORSJ n )if (argc == 1)

EXEC SQL CONNECT TO TPLXEMB_SQL_CHECK(CONNECT TO TPLX)

else if (argc == 3)

strcpy (userid argv[1])strcpy (passwd argv[2])EXEC SQL CONNECT TO TPLX USER userid USING passwdEMB_SQL_CHECK(CONNECT TO TPLX)

else

printf (nUSAGE cursor [userid passwd]nn)return 1

endif

EXEC SQL DECLARE c1 CURSOR FORselect deptname name salary + ifnull(comm0) as compensationfrom org o staff swhere odeptnumb = sdeptorder by deptname compensation desc

EXEC SQL OPEN c1EMB_SQL_CHECK(OPEN CURSOR)

printf(DEPARTMENT NAME COMPENSn)printf(-----------------------------------n)do

EXEC SQL FETCH c1 INTO dname pname compif (SQLCODE = 0) breakprintf( -1515s -1010s 72fn dname pname comp )

while ( 1 )

EXEC SQL CLOSE c1EMB_SQL_CHECK(CLOSE CURSOR)

EXEC SQL CONNECT RESETEMB_SQL_CHECK(CONNECT RESET)

exit(0)

end of program CURSORSJSQC

int SqlInfoPrint( char appMsgstruct sqlca pSqlcaint linechar file )

int rc = 0char sqlInfo[1024]char sqlInfoToken[1024]char sqlstateMsg[1024]char errorMsg[1024]

if (pSqlca-gtsqlcode = 0 ampamp pSqlca-gtsqlcode = 100)

49

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

strcpy(sqlInfo )if( pSqlca-gtsqlcode lt 0) sprintf( sqlInfoToken n---- error report ----n)

strcat( sqlInfo sqlInfoToken)else sprintf( sqlInfoToken n---- warning report ----n)

strcat( sqlInfo sqlInfoToken) endif

sprintf( sqlInfoToken app message = sn appMsg)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken line = dn line)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken file = sn file)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken SQLCODE = ldn pSqlca-gtsqlcode)strcat( sqlInfo sqlInfoToken)

get error message rc = sqlaintp( errorMsg 1024 80 pSqlca) return code is the length of the errorMsg string if( rc gt 0) sprintf( sqlInfoToken sn errorMsg)

strcat( sqlInfo sqlInfoToken)

get SQLSTATE message rc = sqlogstt( sqlstateMsg 1024 80 pSqlca-gtsqlstate)if (rc == 0) sprintf( sqlInfoToken sn sqlstateMsg)

strcat( sqlInfo sqlInfoToken)

if( pSqlca-gtsqlcode lt 0) sprintf( sqlInfoToken --- end error report ---n)

strcat( sqlInfo sqlInfoToken)printf(s sqlInfo)return 1

else sprintf( sqlInfoToken --- end warning report ---n)

strcat( sqlInfo sqlInfoToken)printf(s sqlInfo)return 0

endif endif

return 0

void TransRollback( ) struct sqlca sqlca

int rc = 0 rollback the transaction printf( nRolling back the transaction n)

EXEC SQL ROLLBACKrc = SqlInfoPrint( ROLLBACK ampsqlca __LINE__ __FILE__)if( rc == 0) printf( The transaction was rolled backn)

50

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

51

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix C mdash Source Listing of testclicpp

Include The Appropriate Header Filesinclude ltsqlclihgtinclude ltsqlcli1hgtinclude ltsqlutilhgtinclude ltsqlenvhgtinclude ltstdiohgt include ltiostreamgt include ltlocalehgt include ltstringhgtdefine SQL_SQLSTATE_SIZE 5define LOOPS 8

using namespace std

Define The CLI_Class Classclass CLI_Class

Attributespublic

SQLHANDLE EnvHandleSQLHANDLE ConHandleSQLHANDLE StmtHandleSQLRETURN rcSQLCHAR Job[6]SQLCHAR Name[10]SQLDOUBLE Comp

Operationspublic

CLI_Class()~CLI_Class()SQLRETURN ShowResults()

Constructor Destructor

SQLRETURN printError( SQLHDBC SQLHSTMT)

Define The Class ConstructorCLI_ClassCLI_Class()

setlocale( LC_ALL )

Initialize The Return Code Variablerc = SQL_SUCCESS

Allocate An Environment Handlerc = SQLAllocHandle(SQL_HANDLE_ENV SQL_NULL_HANDLE ampEnvHandle)

Allocate A Connection Handleif (rc == SQL_SUCCESS)

rc = SQLAllocHandle(SQL_HANDLE_DBC EnvHandle ampConHandle)

Define The Class DestructorCLI_Class~CLI_Class()

Free The Connection Handleif (ConHandle = NULL)

SQLFreeHandle(SQL_HANDLE_DBC ConHandle)

Free The Environment Handle

52

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

if (EnvHandle = NULL)SQLFreeHandle(SQL_HANDLE_ENV EnvHandle)

Define The ShowResults() Member FunctionSQLRETURN CLI_ClassShowResults(void)

While There Are Records In The Result Data Set Generated Retrieve And Display Themcout ltlt Name Job Compensation ltlt endlcout ltlt --------- ------ ------------ ltlt endlcoutsetf(iosleft)coutprecision(2)coutsetf(iosfixed)while (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)

rc = SQLFetch(StmtHandle)if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)

coutwidth(15)cout ltlt Name

coutwidth(10)cout ltlt Job

coutwidth(7)cout ltlt Comp ltltendl

if(rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO ampamp rc = SQL_NO_DATA)printError(ConHandle StmtHandle)

else

rc = 0SQLCloseCursor(StmtHandle)

Return The ODBC API Return Code To The Calling Functionreturn(rc)

SQLRETURN CLI_ClassprintError (SQLHDBC hdbc

SQLHSTMT hstmt)

SQLCHAR buffer[SQL_MAX_MESSAGE_LENGTH + 1]SQLCHAR sqlstate[SQL_SQLSTATE_SIZE + 1]SQLINTEGER sqlcodeSQLSMALLINT lengthSQLRETURN rcwhile ((rc = SQLError(SQL_NULL_HENV hdbc hstmt

sqlstateampsqlcodebufferSQL_MAX_MESSAGE_LENGTH + 1amplength)) == SQL_SUCCESS || rc ==

SQL_SUCCESS_WITH_INFO)

cout ltlt SQLSTATE ltlt sqlstate ltlt endlcout ltlt SQLCODE ltlt sqlcode ltlt endlcout ltlt Error msg ltlt buffer ltlt endl

53

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

cout ltlt----------------------------- ltlt endl ltlt endl

return(SQL_ERROR)

----------------------------------------------------------------- The Main Function -----------------------------------------------------------------int main()

Declare The Local Memory Variables

(SQLCHAR ) db2user SQL_NTS (SQLCHAR ) test26t SQL_NTS)

SQLRETURNSQLCHARSQLCHARSQLCHARchar

SQLCHAR

rc = SQL_SUCCESSDBName[10] = TPLXSQLStmt[255]c[10]ptrcurrentDepartment[8][15] = Head Office

New England Mid Atlantic South Atlantic Great Lakes PlainsPacificMountain

Create An Instance Of The CLI_Class ClassCLI_Class Example

Connect To iSeries Database if (ExampleConHandle = NULL)

rc = SQLConnect(ExampleConHandle DBName SQL_NTS

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)ExampleprintError(ExampleConHandle SQL_NULL_HSTMT)

return(rc)

cout ltlt Successfully connected to ltlt DBName ltlt ltlt endlrc = SQLSetConnectAttr(ExampleConHandle SQL_ATTR_AUTOCOMMIT

(SQLPOINTER) SQL_AUTOCOMMIT_OFF SQL_IS_UINTEGER) Allocate An SQL Statement Handlerc = SQLAllocHandle(SQL_HANDLE_STMT ExampleConHandle

ampExampleStmtHandle)if (rc == SQL_SUCCESS)

Define A SELECT SQL Statement

strcpy((char ) SQLStmt select name job salary + ifnull(comm0) ascompensation )

ptr = strcat( (char ) SQLStmt from org o staff s )ptr = strcat( (char ) SQLStmt where odeptnumb = sdept)ptr = strcat( (char ) SQLStmt and deptname = )ptr = strcat( (char ) SQLStmt order by compensation desc)

Prepare The SQL Statementrc = SQLPrepare(ExampleStmtHandle SQLStmt SQL_NTS)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)ExampleprintError(ExampleConHandle ExampleStmtHandle)

54

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

return(rc)

Bind The Columns In The Result Data Set Returned To Application Variables

rc = SQLBindCol(ExampleStmtHandle 1 SQL_C_CHAR (SQLPOINTER)ExampleName sizeof(ExampleName) NULL)

rc = SQLBindCol(ExampleStmtHandle 2 SQL_C_CHAR (SQLPOINTER)ExampleJob sizeof(ExampleJob) NULL)

rc = SQLBindCol(ExampleStmtHandle 3 SQL_C_DOUBLE (SQLPOINTER)ampExampleComp sizeof(ExampleComp) NULL)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO) ExampleprintError(ExampleConHandle ExampleStmtHandle)

return(rc)

while (true)

for (int i = 0 i lt LOOPS i++)

rc=SQLBindParameter(ExampleStmtHandle1SQL_PARAM_INPUTSQL_C_CHARSQL_CHAR

150(SQLPOINTER) currentDepartment[i8]0NULL)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)

ExampleprintError(ExampleConHandle ExampleStmtHandle)return(rc)

rc = SQLExecute(ExampleStmtHandle)if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)

ExampleprintError(ExampleConHandle ExampleStmtHandle)return(rc)

cout ltlt endl ltlt Current Dept ltlt currentDepartment[i8] ltlt

endl Display The Results Of The SQL QueryExampleShowResults()if(rc = 0)break

if ( i500 == 0 ampamp i gt 0 )cout ltlt Loops ltlt i ltlt ltlt endl

cout ltlt AFTER ltlt LOOPS ltlt loops Press X to exit ltlt endlcin gtgt cif (c[0] == x || c[0] == X)

break

Free The SQL Statement Handleif (ExampleStmtHandle = NULL )

SQLFreeHandle(SQL_HANDLE_STMT ExampleStmtHandle) Disconnect From The Northwind Sample Databaserc = SQLDisconnect(ExampleConHandle)

Return To The Operating Systemreturn(rc)

55

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

JDBC Data Access This section provides implementation tips and coding examples that illustrate how to optimize the access to your DB2 UDB for iSeries database from a AIX partition by using various JDBC drivers Currently IBM offers several AIX-enabled JDBC drivers that support DB2 UDB for iSeries

bull Type 4 drivers mdash IBM Toolbox for Java JTOpen and DB2 Universal JDBC Driver bull Type 2 driver mdash DB2 JDBC Type 2 Driver

The IBM Toolbox for Java iSeries driver has been implemented in pure Javatrade and optimized for accessing DB2 UDB for iSeries data It uses native iSeries protocol to communicate with the back-end database server job JTOpen is the open-source version of the IBM Toolbox for Java Licensed Program Product (LPP)

The DB2 Universal JDBC Driver is also a pure Java implementation It is a part of the DB2 UDB for AIX Version 8 product and it uses the Distributed Relational Database Architecture (DRDA) protocol for clientserver communications The driver is compatible with various DB2 UDB server platforms with appropriate DRDA Application Server (AS) level support and prerequisite stored procedures It also supports Type 2 connectivity when accessing DB2 UDB for Linuxreg UNIX and Windowsreg (DB2 UDB for LUW) databases

The traditional DB2 JDBC Type 2 Driver is built on top of DB2 Call Level Interface (CLI) It requires DB2 Connect functionality to access DB2 UDB for iSeries This is a legacy driver and IBM currently recommends that the DB2 Universal JDBC driver is used instead

Initial Configuration Considerations Practical experience shows that the JDBC application performance greatly depends on the programming techniques and the SQL access tuning However significant performance gains can be achieved by simply tweaking the AIX partition environment For example a virtual LAN connection to the back-end database can significantly streamline the data flow

4

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Virtual Versus Physical LAN One of the most significant benefits of installing AIX in an iSeries partition is the ability to utilize virtual LAN and virtual DASD This usually results in reduced hardware costs through improvements in data transfer performance and enhanced disk protection The performance tests conducted by the IBM eServer Solutions Enablement team showed that the Virtual 1Gb LAN delivered a data throughput similar to dedicated 1Gb Ethernet adapters (model 5706) connected via a dedicated Ethernet segment An example configuration is illustrated in Figure 2

Figure 2 VLAN vs 1 Gb Ethernet IOA configuration

Although similar performance can be expected for VLAN and 1Gb Ethernet the VLAN configuration has two advantages over the physical LAN connection

bull No additional communications gear is required bull It is a dedicated point-to-point connection so there is no interference from other devices on

the same network segment

On the other hand certain application scenarios may benefit from a physical LAN adapter dedicated to an AIX partition For instance in a three-tier application architecture clients connect to an application server running in a AIX partition The application server in turn connects to DB2 UDB for iSeries where data is stored and retrieved In this case configuring a separate physical LAN connection in a AIX partition has the following advantages

bull An unnecessary additional hop is eliminated from the network route bull Client-application server traffic does not unnecessarily saturate i5OS communications gear

5

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Tuning DB2 UDB for iSeries Access with IBM Toolbox for Java and JTOpen Driver This section covers JDBC implementation details for a sample Java program called TestJDBC (the source is provided at the end of this paper in Appendix A) The application uses the Java Naming and Directory Interface (JNDI) to obtain a database connection deletes 5000 records generates and inserts 5000 records and finally retrieves the newly inserted records from an SQL table called COFFEES The application executes in an AIX partition and accesses the DB2 UDB for iSeries through the JTOpen (or IBM Toolbox for Java) driver Figure 3 shows the software components involved in the execution of this simple application

Figure 3 JDBC client accessing DB2 UDB for iSeries

Apart from the JTOpen driver which can be downloaded from the IBM Toolbox for Java Web site you need three other JAR files to successfully compile and execute the JDBCTest application in a AIX partition

bull providerutiljar and fscontextjar mdashDownload a simple file system JNDI provider from Sun Microsystems JNDI Web site httpjavasuncomproductsjndidownloadsindexhtml

bull jdbc2_0-stdextjar mdash Copy the javaxsql package from the QIBMUserDataJava400ext IFS directory on the iSeries server

The location of the JAR files needs to be added to the CLASSPATH environment variable For instance the following entry could be added to the AIX profile script

6

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

CLASSPATH=homecodeJTOpenjt400jarCLASSPATH=$CLASSPATHhomecodefscontextproviderutiljarCLASSPATH=$CLASSPATHhomecodefscontextfscontextjarCLASSPATH=$CLASSPATHhomecodeJTOpenjdbc2_0-stdextjarexport CLASSPATH

To compile the source use the following command in the AIX partition

javac TestJDBCjava

Although the TestJDBC application is fairly simple it illustrates several important aspects of efficient JDBC programming for DB2 UDB for iSeries

Connection PoolingA JDBC connection can be obtained through either the DataSource or DriverManager object Either method involves significant overhead A fairly large amount of system resources is required to create and maintain the connection and then release it when it is no longer needed JTOpen allows a developer to establish a pool of database connections that can be shared by multiple client applications Connection pooling can improve the response time because the connection pool manager can locate and use an existing connection When the database request is completed the connection returns to the connection pool for reuse

In the JDBCTest sample JNDI was first used to register a connection pool-capable data source Heres an excerpt from the deployDataSource method of the sample application

Hashtable env = new Hashtable()envput(ContextINITIAL_CONTEXT_FACTORY

comsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env) [1]

Register an AS400JDBCConnectionPoolDataSource objectAS400JDBCConnectionPoolDataSource tkcpds = newAS400JDBCConnectionPoolDataSource() [2]tkcpdssetServerName(serverName) tkcpdssetDatabaseName(databaseName) tkcpdssetUser(userName) tkcpdssetPassword(password) tkcpdssetDescription(Toolkit Connection Pooling DataSourceobject) hellip ctxrebind(jdbcToolkitDataSource tkcpds) [3]

At [1] the initial JNDI context is created

Then at [2] an AS400JDBCConnectionPoolDataSource object is instantiated This is the JTOpen implementation of the javaxsqlConnectionPoolDataSource interface An AS400JDBCConnectionPoolDataSource object supports a number of methods that can be used to set iSeries-specific properties of the underlying DataSource object Some of these properties will be discussed in greater detail in the following sections of this paper

At [3] the data source object is bound to an arbitrary name that will be used in the main application Note that the deployDataSource method needs to be executed just once unless some of the data source properties need to be changed In that case the developer would need to rebind

7

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

The JNDI registered data source is then used in the main application to initialize the connection pool

AS400JDBCConnectionPoolDataSource tkcpds = [1](AS400JDBCConnectionPoolDataSource)ctxlookup(jdbcToolkitDataSource) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPool pool = newAS400JDBCConnectionPool(tkcpds)[2] Adds 1 connection to the pool that can be used by the application(creates the physical database connections based on the datasource)poolfill(1) [3] hellip con = poolgetConnection()[4]

At [1] the JNDI service is used to instantiate the AS400JDBCConnectionPoolDataSource

Then at [2] an AS400JDBCConnectionPool object is created This object is responsible for managing the connection pool

At [3] the connection pool is initialized with one connection

The pool object is used at [4] to obtain a database connection There are several additional things the developer should know about this code snippet

bull The advantage of using JNDI to register the data source object as opposed to just instantiating it in the main method is that in a more realistic scenario the data source would be registered just once at application deployment time Additionally the data source properties do not have to be hard-coded in the main method and can be changed at any time and then rebound without affecting the application

bull The AS400JDBCConnectionPool is a proprietary JTOpen implementation of a connection pool Specifically it does not implement the Referenceable interface and thus cannot be bound through JNDI services

bull The JTOpen AS400JDBCConnectionPoolDataSource does not support statement caching as described in the JDBC 30 specification Statement caching is implemented through SQL packages This feature is covered in the following section

Note The native iSeries JDBC driver supports both connection pooling and statement caching in a JDBC 30 compliant manner

8

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Extended Dynamic SQL and Statement Caching As mentioned the JTOpen data source object supports a number of properties that can be used to fine-tune the database performance In this section properties used to enable extended dynamic SQL support (see DB2 SQL Runtime Interfaces section above) and local statement caching will be discussed

Here is a relevant code excerpt from the deployDataSource method

AS400JDBCConnectionPoolDataSource tkcpds = new AS400JDBCConnectionPoolDataSource() hellip tkcpdssetExtendedDynamic(true)[1]tkcpdssetPackage(JDBCDS) [2]tkcpdssetPackageCache(true) [3]tkcpdssetPackageCriteria(select) [4]

At [1] the extended dynamic SQL support is enabled Note that the default is disabled for JTOpen The extended dynamic SQL functionality is often referred to as SQL package support The SQL packages are server-side repositories for SQL statements Packages contain the internal structures such as parse trees and access plans which are needed to execute SQL statements Because SQL packages are a shared resource the information built when a statement is prepared is available to all the users of the package This saves processing time especially in an environment where many users are using the same or similar statements Also because SQL packages are permanent this information is saved across job initiationtermination and IPLs In fact SQL packages can be saved and restored on other servers

At [2] the SQL package is named Note that the actual package name on the iSeries server is JDBCDSBAA The package name is generated by taking the name specified on the client and appending three letters that are an encoded set of the package configuration attributes By default an SQL package does not contain unparameterized select statements This behavior is overridden at [4] by setting the PackageCriteria property to select

At [3] the local statement cache is enabled A copy of the SQL package is cached on the AIX client This may improve application performance in a way similar to JDBC 30 statement caching Note however that local statement caching is not recommended for large SQL packages The copy of an SQL package is cached when the database connection is obtained This may cause increased network traffic as well as slow down the connection setup time

Reusable Open Data Paths (ODPs)An Open Data Path (ODP) definition is an internal i5OS object that is created when certain SQL statements (such as OPEN INSERT UPDATE and DELETE) are executed for the first time in a given job (or connection) The ODP can be thought of as a runtime implementation of an access plan The access plan created at the optimization time provides a recipe or in other words a sequence of steps necessary to execute the statement The ODP on the other hand provides the executable code for all requested IO operations The process of creating new ODP objects is fairly CPU- and IO-intensive so whenever possible the iSeries DB2 runtime tries to reuse existing ODPs For instance a ResultSetclose() call may close the SQL cursor but leave the ODP available to be used the next time the cursor is opened This can significantly reduce the response time in running SQL statements A reusable OPD usually requires 10 to 20 times less CPU resources than a newly created ODP Therefore it is important that the applications employ programming techniques that allow the DB2 runtime to reuse ODPs

With dynamic programming interfaces such as JDBC the most efficient way to avoid full opens is to employ the so-called prepare once execute many programming paradigm Ideally an SQL statement that is executed more than once should be prepared just once mdashfor example in the class constructor mdash and then reused for the consecutive executions At the prepare time the

9

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 engine stores the prepared statement along with the associated statement name in the QZDASOINIT jobs statement cache On the first execution the ODP created for a given statement is associated with the appropriate entry in the statement cache On consecutive executions the prepared statement and the corresponding ODP can be quickly located in the statement cache and reused The code snippet below illustrates the prepare once execute many programming technique

PreparedStatement pstmt = conprepareStatement(INSERT INTO COFFEES VALUES( ))[1] hellip for (int i = 0 i lt outerNumOfLoops i++)

insertfor (int j = 0 j lt numOfLoops j++)

pstmtsetString(1 Lavaza_ + IntegertoString(j)) hellip pstmtaddBatch()

int [] updateCounts = pstmtexecuteBatch()[2]concommit()

At [1] a PreparedStatement pstmt object is instantiated for a parameterized INSERT statement The statement is prepared just once The PreparedStatement object is then repeatedly used at [2] to perform blocked insert

Block Inserts Occasionally the developer may need to initially populate a table or insert a modified result set into a temporary table The efficiency of the insert operation for a large set of records can be dramatically improved by using the executeBatch method rather than the executeUpdate method The JTOpen driver converts parameterized insert statements in an executeBatch method to a block insert statement This significantly reduces the data flow and system resources required to perform the insert The following code snippet shows how to take advantage of the executeBatch method

10

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

PreparedStatement pstmt =conprepareStatement(INSERT INTO COFFEES VALUES( ))[1]for (int j = 0 j lt numOfLoops j++) pstmtsetString(1 Lavaza_ + IntegertoString(j))pstmtsetInt(2 i)pstmtsetFloat(3 499f)pstmtsetInt(4 0)pstmtsetInt(5 0)pstmtaddBatch() [2]

int [] updateCounts = pstmtexecuteBatch() [3]

At [1] a parameterized insert statement is prepared Note that all columns must be parameterized Otherwise the executeBatch method may throw the SQL0221 Number of rows 1 not valid exception In other words the developer should not mix parameter markers with literals or special registers in the VALUE clause

At [2] the addBatch method is used to add a new record to the client record buffer

At [3] all locally buffered data is sent to the server which in turn performs a block insert

Figure 4 shows the performance data for the executeBatch and executeUpdate methods

Figure 4 executeBatch() versus executeUpdate() performance comparison

11

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

WebSphere Considerations In certain situations an application provider may decide to deploy WebSphere Application Server in an AIX partition rather than natively in i5OS At the same time the application uses DB2 UDB for iSeries as an back-end database server Typically the WebSphere Application Server running in the AIX partition uses the virtual LAN to communicate with DB2 UDB for iSeries The WebSphere applications will access the database through a remote JDBC connection For performance and functionality reasons IBM recommends to utilize in such environments the IBM Toolbox for Java JTOpen driver Most of the tips and techniques described so far in this document hold true for WebSphere applications accessing DB2 UDB for iSeries There are however certain JDBC access aspects that are specific to this multi-tier architecture Letrsquos have a closer look at some of these considerations

Connection Pooling and Statement Caching

WebSphere Application Server provides its own connection pooling and statement caching mechanism that is by default enabled so that WebSphere applications automatically enjoy the performance benefits of these two critical programming techniques See the following link to learn more about the optimal connection pool setting in WebSphere

httppublibboulderibmcomwas40051englishinforzaiz51adminhelpudat_conpoolsethtml

Extended Dynamic SQL

For non-JTA connections WebSphere Application Server uses the comibmas400accessAS400JDBCConnectionPoolDataSource class as the iSeries JDBC provider implementation This is the DataSource implementation that has been used in all previous coding examples As mentioned the class supports a range of iSeries specific properties that can be used to fine tune JDBC performance These properties can be set through the WebSphere Application Server admin console For example herersquos the procedure to enable the extended dynamic SQL support In the WebSphere Application Server admin console navigate to the Data Source configuration dialog by selecting JDBC Providers -gt iSeriesToolbox -gt Data Sources then scroll down to the Additional Properties section Select Custom Properties link The Custom Properties dialog opens Scroll down to find the Extended Dynamic property and select it Change the default value false to true save the new configuration by clicking Apply button This is illustrated in Figure 5

12

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 5 Enabling the extended dynamic SQL through WebSphere Application Server console

The WebSphere Application Server needs to be restarted for the change to take effect The similar procedure can be followed to set other iSeries Data Source properties

Changing the WebSphere Application Server default isolation level

WebSphere Application Server V5 uses the REPEATABLE_READ (RR) isolation level for all implicit (WebSphere Application Server managed) transactions With the RR isolation level the rows selected updated deleted and inserted are locked until the end of the transaction Under certain circumstances this fairly extensive locking policy may cause locking contention especially when a WebSphere application competes for database resources with other applications that run on iSeries server For example a legacy order entry application may share data with the e-business customer care application running in WebSphere The locking contention may sometimes be eliminated by lowering the isolation level used by WebSphere Although the iSeries Data Source supports the custom transactionIsolation property resetting this property on the Data Source object will not change the default isolation level used by WebSphere for the connection objects produced by that Data Source In other words WebSphere will override the Data Source isolation level setting at the time the connection is obtained by a WebSphere application object such as servlet or Enterprise Java Bean (EJB) In order to change the default WebSphere behavior one must use the resource referencing Resource referencing allows a programmer to lookup DataSource or EJB objects using alias names rather than JNDI names Additionally by creating a resource reference a programmer can change certain properties of the underlying object Specifically a DataSource reference can be used to set a different isolation level for the connections produced by this database resource Typically resource references are defined by a programmer in a application development tool such as WebSphere Studio Application Developer The method to specify a DataSource reference differs depending on whether a programmer plans to use the reference in a servlet or in an EJB Letrsquos start with outlining the configuration process for a servlet In WebSphere Studio Application Developer open the deployment descriptor editor for the web project that contains the servlet To do so double click on the webxml file under WEB-INF directory in the web project In the deployment editor dialog select the References tab and then select Resource tab located in the top of the dialog that appears Under Resource References section select the Add button Herersquos an example of a DataSource reference created for iSeries DataSource named TestJDBCDS Note that the reference changes the default isolation level to READ_COMMITTED

13

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 6 Defining a resource reference for a servlet

Once the resource reference has been defined and saved the servlet source code needs to be changed to reflect the fact that a resource reference is used to obtain a DataSource from the JNDI service Herersquos the relevant code snippet try

ctx = new InitialContext() ds = (DataSource)ctxlookup(javacompenvTestJDBCJ2C)

catch (Exception e) eprintStackTrace(out)

Now the ds DataSource object will produce connections that by default run with the isolation level of READ_COMMITTED (RC)

As mentioned the process of defining a resource reference for an EJB differs from the process that is used in the case of a servlet In WebSphere Studio Application Developer open the deployment descriptor editor for the EJB project that contains the EJB To do so double click on the ejb-jarxml file under WEB-INF directory in the project In the deployment editor dialog select the References tab In the references section on the left locate and select the EJB for which the developer wants to change the default isolation level Click the Add button The Add Reference dialog opens Click the Resource Reference radio button and then Next Define the reference following the example shown in Figure 7

14

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 7 Adding a resource reference for an EJB

When you click ldquoFinishrdquo the reference definition is added to the EJB descriptor The new definition needs to be further modified To do so click on the (+) sign next to the EJB in the References list Click the new reference TestJDBCJ2C in this example to open the properties for the reference Change WebSphere Bindings and WebSphere Extensions sections as illustrated in Figure 8

15

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 8 Defining a resource reference for an EJB

Save the modified definition and then change the EJB source code to use the reference rather than directly DataSource

TroubleshootingTroubleshooting a multi-tier application may be a bit tricky because the developer needs to deal with software components that reside in separate partitions Three tools are particularly useful for pinning down the potential problem areas bull Joblog messages for a database server job mdash Provides enough details to isolate DB2 UDB for

iSeries runtime issues bull JDBC trace utility mdash Provides granular information about the data flow between the AIX

application and the iSeries server job bull Database Monitor ndash Provides detailed SQL runtime trace

Job Log MessagesAs mentioned a DB2 client communicates with a corresponding iSeries server job This server job runs the SQL requests on behalf of the client The iSeries database server jobs are called QZDASOINIT and they run in the QUSRWRK subsystem At any given time a large number of database server jobs may be active on the server so the first step is to identify the job that serves the particular client connection The easiest method to accomplish this task is to run the following CL command from the i5OS prompt

WRKOBJLCK OBJ(DB2USER) OBJTYPE(USRPRF)

Here DB2USER is the user profile that is used to connect to the iSeries server Note that a QZDASONIT job is assigned to a client after the connection has been established so the developer needs to set a breakpoint in the client application after the database connection has been established

Once the Work with Object Locks appears key in 5 (Work with Job) next to the only QZDASOINIT job that should be listed This shows the Work with Job dialog Select option 10 to

16

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

display the job log for the database server job Now the job log can be searched for any error messages generated by the DB2 runtime

Sometimes it is also useful to include debug messages in the job log The debug messages are informational messages written to the job log about the implementation of a query They describe query implementation methods such as the use of indexes join order ODP implementation (reusable versus non-reusable) and so on The easiest way to instruct an iSeries server to include the debug messages is to set the ServerTraceCategories property on the data source object

tkcpdssetServerTraceCategories(AS400JDBCDataSourceSERVER_TRACE_DEBUG_SERVER_JOB)

A sample of the job log messages with debug messages enabled is shown below

SET TRANSACTION completeSTATEMENT NAME FOUND QZ868F0A458E13AF8C Starting optimizer debug message for query Arrival sequence access was used for file COFFEESODP created ODP not deleted 5000 rows inserted in COFFEES in DB2USER STATEMENT NAME FOUND QZ868F0A4C144BF12EBlocking used for queryCursor CRSR0001 opened606 rows fetched from cursor CRSR0001 ODP not deleted Cursor CRSR0001 closed

So the job log offers fairly detailed information on how the AIX client requests were implemented by the DB2 runtime

JDBC Trace UtilityThe JTOpen driver provides a tracing utility which can be used to collect detailed client-side traces The JDBC tracing is turned off by default It can be enabled by setting the Trace property to true Heres an example of how to switch on tracing using the setTrace method on the data source object

tkcpdssetTrace(true)

The trace can also be enabled when using the DriverManagergetConnection() method for obtaining a connection to DB2 UDB for iSeries In this case the developer could add the trace property to the connection string This approach is illustrated in the following code snippet

ClassforName(comibmas400accessAS400JDBCDriver) [1] hellip con = DriverManagergetConnection(jdbcas400teraplextrace=true

db2userdb2pwd) [2]

At [1] an instance of the JTOpen JDBC Driver is initiated Then at [2] the driver is used to obtain a connection to the iSeries server Note how the trace property has been added to the database URL See the IBM Toolbox for Java JDBC properties documentation on the iSeries Information Center Web site for a complete list of properties supported by the JTOpen driver

Although the level of details provided by the trace utility is sufficient in most troubleshooting scenarios sometimes the developer may need to collect low-level traces scoped to a certain type

17

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

of information In V5R3 the IBM Toolbox for Java (as well as the latest JTOpen) added a comprehensive detailed trace facility The following is the complete list of detailed trace parameters and their purpose

bull None or ldquordquo ndash This setting disables the detailed trace bull datastream - This category is used by Toolbox classes to log dataflow between the local host

and the remote system It is not intended for use by application classes bull diagnostic - This category is used to log object state information bull error - This category is used to log errors that cause an exception bull information - This category is used to track the flow of control through the code bull warning - This category is used to log errors that are recoverable bull conversion - This category is used by Toolbox classes to log character set conversions

between Unicode and native code pages bull proxy - This category is used by Toolbox classes to log data flow between the client and the

proxy server bull pcml - This category is used to determine how PCML interprets the data that is sent to and

from the server bull jdbc - This category is used to track JDBC calls throughout the program bull thread - This category is used to enable tracing of thread information This is useful when

debugging multi-threaded applications bull all - This category will enable all previous categories

The detailed trace can be enabled when using the DriverManagergetConnection() method for obtaining a connection to DB2 UDB for iSeries In this case the developer could add the toolbox trace property to the connection string This is illustrated in the following code sample

String dbUrl = jdbcas400pwd1toolbox trace=diagnostic con = DriverManagergetConnection(dbUrl dbUser dbPassword)

Note that currently the driverrsquos DataSource interfaces do not allow the developer to directly activate the detailed tracing However they could set the server from the command line at the time the java program is launched The example below shows how the detailed trace properties could be enabled at the command line

java -Dcomibmas400accessTracecategory=diagnostic TestJDBC

The -D switch indicates to the java interpreter that the information following it will be a system property

In case of a WebSphere application the trace property can be set through the admin console In the console select Application Servers-gt server1-gt Process Definition -gt Java Virtual Machine Figure 9 shows how to set the Generic JVM Arguments for an application server instance

18

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 9 Setting JVM arguments to enable detailed Toolbox tracing

Database Monitor

The database monitor is the ultimate tool available on DB2 UDB for iSeries to collect low-level SQL traces It is mainly used to pin down the SQL performance problems Refer to the lsquoUsing iSeries Database Monitor to Identify and Tune SQL Queriesrsquo white paper for a detailed discussion on how to collect and analyze the database monitor traces httpibmcomserversenablesiteeducationiborecordhtmldtmon

IBM DB2 JDBC Universal Driver DB2 JDBC Universal Driver is one of the new features delivered with DB2 UDB Version 8 DB2 JDBC Universal Driver has been designed to eliminate the dependency on DB2 CLI runtime modules as well as to enable direct Type 4 connectivity to DB2 UDB for iSeries and DB2 UDB for zOSreg

The pure-Java (Type 4) remote connectivity is based on the DRDA open distributed protocol for cross-platform access to DB2 DRDA defines the rules the protocols and the semantics for accessing distributed data Applications can access data in a distributed relational environment by using SQL statements The iSeries DRDA application server implementation is based on multiple connection-oriented server jobs running in the QSYSWRK subsystem A DRDA listener job (QRWTLSTN) listens for TCP connect requests on port 446 Once an application requester connects to the listener job the listener wakes up one of the QRWTSRVR prestart jobs and assigns it to a given client connection Any further communication occurs directly between the client application and the QRWTSRVR job These concepts are illustrated in Figure 10

19

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 10 Accessing DB2 UDB for iSeries with DB2 Universal Driver

The DB2 Universal Driver can be loaded in an AIX partition by installing one of the DB2 Connect for AIX products (see the Additional Information section for details) It is also a part of a DB2 Enterprise Server Edition for AIX install Specifically the developer needs three JAR files in a AIX partition to successfully connect to an iSeries server db2jccjar db2jcc_license_cisuzjar and db2jcc_license_cujar The iSeries license is contained in db2jcc_license_cisuzjar Note that this file is not a part of DB2 Client In other words a DB2 Connect license is required to use the driver in production environments The location of the JAR files needs to be added to the CLASSPATH environment variable For instance the following entry could be added to the AIX profile script

CLASSPATH=homedb2inst2sqllibjavadb2jccjarCLASSPATH=$CLASSPATHhomedb2inst2sqllibjavadb2jcc_license_cujarCLASSPATH=$CLASSPATHhomedb2inst2sqllibjavadb2jcc_license_cisuzjarexport CLASSPATH

Java Runtime 131 is a prerequisite

Additionally the developer should install the latest database group PTF (SF99503 for i5OS V5R3) on the iSeries server The Informational APAR ii13348 is keeping track of any fixes relevant to DRDA above and beyond the current database group PTF

Obtaining a Connection to DB2 UDB for iSeries When Type 4 connectivity is used the DB2 Universal Driver connects directly to the DB2 on iSeries through TCPIP Note that this is different from the legacy DB2 Type 2 JDBC driver that requires a DB2 node and remote database configurations on the client accessing iSeries The following code snippet illustrates how to use the DB2 JDBC Universal Driver to obtain a connection to DB2 UDB for iSeries

20

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

try ClassforName(comibmdb2jccDB2Driver) [1] catch(javalangClassNotFoundException e) Systemerrprint(ClassNotFoundException )Systemerrprintln(egetMessage())

try DriverManagergetConnection(jdbcdb2teraplex446TERAPLEX[2]

db2userdb2pwd) hellip catch(SQLException ex) Systemerrprintln(

SQLException + exgetMessage())

At [1] an instance of the DB2 JDBC Universal Driver is instantiated Then at [2] the driver is used to obtain a connection to the iSeries server Note the proper form of the database URL required by the driver

Considerations There are several advantages of DB2 JDBC Universal Driver bull Ease of cross-platform development mdash Consistent coding techniques and consistent error

codes and messages bull Ease of deployment mdash Pure Java (no runtime client required) and a single driver for accessing

DB2 on different platforms

The ease of use comes at a price though The iSeries JTOpen driver is optimized for accessing DB2 UDB for iSeries data and it uses native iSeries protocol to communicate with the back-end database server job This usually results in better performance and more-efficient system resources utilization For instance when using the DB2 JDBC Universal Driver to access an iSeries server the executeBatch method results in a single record insert There are also some restrictions when using DB2 Universal JDBC Driver with Type 4 connectivity

bull Support for distributed transactions (JTA) is not enabled bull Driver built-in connection pooling is not supported

Refer to Java application support in DB2 for more details on DB2 JDBC Universal Driver

21

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 Connect data access This section will explore the most important aspects of DB2 Connect ndash iSeries integration - including configuration tips and coding examples

DB2 Connect provides functionality for accessing data stored in DB2 UDB for iSeries as well as DB2 UDB for zOS and DB2 UDB for OS390reg DB2 Connect offers capabilities to access DB2 family members via several SQL interfaces gateway functions such as connection pooling and federated database functionality Many applications supporting the DB2 family of products leverage DB2 Connect as a key middleware component DB2 Connect is offered as separate AIX license products

Enterprise Edition Application Server Edition

In addition to DB2 Connect there are several other DB2 UDB Version 81 products that are supported on AIX

DB2 Universal Database Enterprise Server Edition DB2 Universal Database Workgroup Server Unlimited Edition DB2 Universal Database Workgroup Server Edition DB2 Universal Database Universal Developers Edition All Clients

The DB2 Connect Enterprise Edition functionality is also contained in DB2 Enterprise Server Edition for AIX

22

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 Connect in a nutshell In the scenario described in this paper the DB2 Connect functions contained in DB2 Enterprise Edition for AIX are utilized DB2 Connect Enterprise Edition provides support for both local and remote DB2 clients This is illustrated in Figure 11 Accessing DB2 UDB for iSeries with DB2 Connect

Figure 11 Accessing DB2 UDB for iSeries with DB2 Connect

DB2 Connect implements the Distributed Relational Database Architecturetrade (DRDAreg) to reduce the cost and complexity of accessing data stored in DB2 UDB for iSeries and other DRDA-compliant database servers DRDA defines the rules the protocols and the semantics for accessing distributed data Applications can access data in a distributed relational environment by using SQL statements In a distributed environment the system running the application and sending the SQL requests across the network is called the application requester (AR) A remote database server that executes SQL requests submitted by an application requester is known as the application server (AS) In the example shown in Figure 11 (above) DB2 Connect plays the role of an application requester while DB2 UDB for iSeries is an application server In this case DB2 Connect communicates with the iSeries database through TCPIP The iSeries DRDA application server implementation is based on multiple connection-oriented server jobs running in the QSYSWRK subsystem A DRDA listener job (QRWTLSTN) listens for TCP connect requests on port 446 Once an application requester connects to the listener job the listener wakes up one of the QRWTSRVR prestart jobs and assigns it to a given client connection Any further communication occurs directly between the client application and the QRWTSRVR job

DB2 Connect supports a wide range of programming interfaces that can be used by AIX applications to access the iSeries database Embedded SQL frac34 Both static and dynamic SQL frac34 Various programming languages (Java CC++ Cobol Fortran REXX)

DB2 Call Level Interface (DB2 CLI) ODBC JDBC frac34 DB2 JDBC Type 2 Driver frac34 DB2 JDBC Type 4 Driver (Universal JDBC Driver)

23

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Note that DB2 Connect supports access to DB2 UDB for iSeries through DB2 JDBC Universal driver However for performance and ease of maintenance reasons IBM recommends that Java applications running in AIX use native iSeries Toolbox JDBC driver See the JDBC Data Access section of this paper (above) for more details On the other hand DB2 Connect is a very efficient and robust connectivity option for AIX applications especially in the environments that are not directly supported by the native iSeries JDBC driver Here are several possible scenarios that would require DB2 Connect installed in a AIX partition

Embedded SQL interface is used to access DB2 CLI or ODBC interface is used to access DB2 A single SQL interface is needed to access multiple back end DB2 server Specific DB2 Connect functionality is needed such as distributed join or connection

pooling

Prerequisites One of the DB2 Connect products or DB2 Enterprise Server Edition for AIX V81 is needed Additionally DB2 Application Development Client is required in the AIX partition to compile DB2 applications

For maximum database server stability the developer should install the latest database group PTF (SF99503 for i5OS V5R3) on the iSeries server The Informational APAR ii13348 is keeping track of any fixes relevant to DRDA above and beyond the current database group PTF

DB2 Connect configuration The following example employs i5OS V5R3 and DB2 UDB Enterprise Server Edition for AIX Version 81 FixPak 6

Configuration steps in the iSeries partition The following process lists the necessary steps to be performed on the iSeries server 1) Verify that the TCPIP stack is working correctly It is assumed that the Virtual LAN is used to

communicate with the i5OS partition First obtain the IP address of the iSeries server or its hostname and ping the iSeries server from the AIX partition

2) Create a relational database (RDB) entry for the iSeries database in the i5OS partition If this has already been created it can be displayed by using the DSPRDBDIRE command Make sure that the RDB entry with a location of LOCAL exists on the iSeries server If it does not exist use the ADDRDBDIRE command to add the appropriate RDB entry For example the following command would add an RDB entry named TPLX For simplicity it is recommended that the TCPIP host name and RDB entry remain the same

ADDRDBDIRE RDB(TPLX) RMTLOCNAME(LOCAL)

3) Create a collection called NULLID This is necessary because the utilities shipped with DB2 Connect and DB2 UDB for AIX store their packages in the NULLID collection Since it does not exist by default in the iSeries server you must create it using the following command

CRTLIB LIB(NULLID)

4) Products that support DRDA automatically perform any necessary code page conversions at the receiving system For this to happen both systems need a translation table from their code page to the partner code page The default Coded Character Set Identifier (CCSID) on the iSeries server is 65535 Since DB2 Connect does not have a translation table for this code page the developer needs to change the individual user profiles to contain a CCSID that can be converted properly by DB2 Connect For US English this is 037 For other languages see DB2 Connect Personal Edition Quick Beginning GC09-2967 The following command changes the CCSID for an individual user profile to 037

24

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

CHGUSRPRF userid CCSID(037)

5) Verify that the default port 446 for DRDA service is being used To do this go to the Configure TCPIP menu (CFGTCP) select Configure Related Tables and then select Work with service table entries Verify that the DRDA service is set for port 446

6) The Distributed Data Management (DDM) job must be started for DRDA to work If you want the DDM job to be automatically started whenever TCPIP is started change the attributes of the DDM job using the CHGDDMTCPA command and set the Autostart server parameter to YES

7) If the system administrator chooses not to autostart the server issue the following command to start the DDM server job

STRTCPSVR SERVER(DDM)

8) Make sure that the user profiles that will be used to connect to the iSeries server exist on the server

25

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Configuration steps in the AIX partition The following steps are required for DB2 Connect to be configured in the AIX partition 1) Sign on to the AIX partition as the DB2 administrator 2) Launch Client Configuration Assistant (db2ca from the command prompt) It is assumed that

VNC or an X-Windows server are being used on the workstation so that the db2ca GUI can be properly rendered

3) From the Selected pull-down menu select the Add Database using Wizard option The Select how you want to setup a connection dialog appears Select Manually configure a connection to a database and click Next This is shown in Figure 12

Figure 12 Accessing DB2 UDB for iSeries with DB2 Connect

26

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

4) On the Select a communications protocol choose TCPIP and select The database physical resides on a host or OS400 system Then select the option Connect directly to the server as shown in Figure 13 Click Next

Figure 13 mdash Selecting communications protocol

27

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

5) On the TCPIP tab fill in the host name of the iSeries server The port number should be 446 This is shown in Figure 14 Click Next

Figure 14 mdash Specifying TCPIP communication parameters

28

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

6) On the Database tab fill in the Relational Database name Use the RDB entry name (specified in step 2) in the Configuration steps in the iSeries partition section as shown in Figure 15 Click Next

Figure 15 mdash Specifying the remote database

7) If you plan to use the ODBC applications select Register this database for ODBC as a system data source on the ODBC tab Click Next

29

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

8) On the Specify the node option dialog select OS400 from the Operating System pull-down menu This is shown in Figure 16 Click Finish

Figure 16 mdash Specifying the node options

30

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

9) The Test Connection dialog appears This allows the developer to verify that the connection works Select both CLI and JDBC check boxes You are also prompted for an iSeries user ID and password as shown in Figure 17

Figure 17 mdash Testing the connection

31

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

10) The successful connection to the database server is confirmed by the message box shown in Figure 18

Figure 18 mdash Test Connection results 11) At this time a newly configured database connection should appear in the main DB2

Configuration Assistant window It is recommended that the DB2 utilities are also bound to the iSeries database The bind process creates the necessary SQL packages on the remote database In the main Configuration Assistant window click the TPLX database entry and then select Selected-gtBindhellip

32

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

12) The Bind dialog appears Click Select All and then enter the connection information as shown in Figure 19 Click Bind The Results message box appears This allows the developer to monitor the progress of the binding process Watch for any error and warning messages

Figure 19 mdash Binding the DB2 utilities This concludes the DB2 Connect configuration steps

33

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Accessing DB2 UDB for iSeries from C embedded SQL

As mentioned earlier DB2 Connect allows developers to compile and run embedded SQL applications that access DB2 UDB for iSeries data This section covers implementation details for a C embedded SQL application called cursorsjsqc (see Appendix B for source code)

Prerequisites An embedded SQL application running in an AIX partition will use DB2 Connect services to access DB2 UDB for iSeries therefore the developer needs to make sure that all components listed in section Prerequisites on page 24 are installed The developer also needs to create a remote database connection as described in the DB2 Connect configuration section of this paper on page 24

Static SQL and SQL packages To successfully run against a DB2 UDB for iSeries database an embedded SQL application needs to be first precompiled and bound to the back-end database This process creates an SQL package on the target iSeries server The SQL package contains the access plan information for the SQL statements executed by the application The internal structure of the package as well as the method how its content is used by the SQL runtime to facilitate the access plan reuse is similar to the Extended Dynamic SQL support covered in detail in the Extended Dynamic SQL and Statement Caching section of this paper (on page 9) There are however important differences between the packages created by the extended dynamic SQL support and the packages created for embedded SQL DRDA client applications The extended dynamic SQL packages support dynamic SQL interfaces such as JDBC

that can submit ad hoc SQL statements at the run time The SQL runtime can prepare the dynamic statements and add them to the package On the other hand the DRDA packages are created at the precompile time and contain static SQL In order to add new statements to the package the application needs to be precompiled and rebound again

The extended dynamic SQL package can dynamically grow up to 500MB by allocating new space as required The DRDA packages since they are created at the precompile time have a fix size and do not grow over their life time

Simple embedded SQL application The application is based on a source code provided in the DB2 UDB samples directory typically to be found at homedb2inst1sqllibsamples The cursorsjsqc performs a join between STAFF and ORG tables located in DB2USER schema (library) on the TPLX database server (the source is provided at the end of this paper in Appendix B) The join statement retrieves the DEPTNAME column from ORG NAME column from STAFF and calculates the total compensation for an employee by adding SALARY and COMM columns in STAFF The results are sorted by department name and total compensation Here is the SELECT statement used by the application

SELECT deptname name salary + IFNULL(comm0) as compensationFROM org o staff sWHERE odeptnumb = sdeptORDER BY deptname compensation DESC

The application iterates through the selected records and prints out the data to the standard output device The sample DB2USER schema was created with the following SQL statements

db2 CONNECT TO tplx USER db2user USING mypassworddb2 CALL QSYSCREATE_SQL_SAMPLE(DB2USER)

34

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Make sure that the AIX partition is logged into with the DB2 admin user profile If the defaults were selected at the DB2 installation time this profile name is db2inst1 It is also assumed that DB2USER user exists on the iSeries server and that it has appropriate authority

There are several steps that are required to create an executable for the cursorsjsqc source code First the DB2 PRECOMPILE utility needs to be called The utility creates a bind file that is used to bind the required SQL package to the TPLX database It also converts embedded SQL statements into DB2 run-time API calls and produces a pure C source file that can be processed by an AIX C compiler

db2 CONNECT TO tplx USER db2user USING mypassworddb2 prep cursorsjsqc bindfile

Note that the connect statement is required only if the developer is not already connected to the database on an iSeries server Watch for any error or warning messages returned by the DB2 prep utility The prepare step should produce cursorsjbnd and cursorsjc files in the current directory Now the developer can invoke the bind utility to prepare the statements contained in the bind file and create the package on the target iSeries database server

db2 bind cursorsjbnd

It is assumed that Visual C++ 60 is installed and configured in the AIX partition Refer to the ldquoDeveloping and Porting C and C++ Applications on AIXrdquo redbook for more information on how to use the Visual C++ compiler httpibmcomredbooksabstractssg245674htmlOpen

Use the following commands to compile the C source generated by the precompile utility

xlc -I$INSTHOMEsqllibinclude ndashc cursorsjcxlc ndasho cursorsj cursorsjo -L$INSTHOMEsqlliblib ndashldb2

Run the program from the AIX prompt

cursorsj db2user mypassword

Distributed Join DB2 UDB Version 8 provides core federated server functionality A federated system consists of a DB2 UDB instance that operates as a federated server a database that acts as the federated database one or more data sources and clients (users and applications) that access the database and data sources Federated server permits objects stored in multiple databases to be accessed together in the same query For example a query can refer to a table that resides in DB2 UDB for iSeries and join it to a table stored in DB2 UDB for AIX Such a query would constitute so called distributed join The support for DB2 UDB for iSeries as a federated data source is provided by core federated server functionality directly implemented in DB2 UDB Enterprise Server Edition and DB2 UDB Connect Enterprise Edition All other DB2 UDB family members are also supported directly by core DB2 UDB federated server An additional software product DB2 Information Integratortrade is required to access non-DB2 UDB databases such as Oracle Sybase or Microsoftreg SQL Server Consult the following white papers for a detailed discussion on DB2 federated server support Heterogeneous data access for iSeries applications Version 2 httpibmcomserversenablesiteeducationiborecordhtmlhetdata Fundamentals of IBM DB2 Federated Server and Relational Connect httpwww7bsoftwareibmcomdmddlibrarytecharticle0206purnell0206purnellhtml

35

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Distributed Join Example In this section the steps that are required to configure DB2 UDB for iSeries as a federated data source will be illustrated Then the cursorsjsqc program will be ldquotweakedrdquo so that it executes a distributed join query that accesses data stored on an iSeries server and in the local DB2 UDB for AIX database It is assumed that the developer is familiar with the DB2 federated server concepts

Note Run the following commands from the Command Line Processor prompt Load the utility by executing the db2 command at the AIX prompt 1) First the local DB2 UDB for AIX instance needs to be enabled as a DB2 federated server

This is done by setting the database manager configuration parameter FEDERATED to YES

db2=gt update dbm cfg using FEDERATED YES

The database instance needs to be restarted for the change to take effect

NOTE A federated database is a regular database in a DB2 UDB instance that has the FEDERATED parameter enabled Therefore in this example the SAMPLE database that was created earlier is used as the federated database A new database can also be created using the CREATE DATABASE command

2) Connect to the federated database

db2=gt connect to sample

3) Use the CREATE WRAPPER statement to register a wrapper for the iSeries data source Wrappers are library routines that are used by the federated server to perform operations such as connecting to a data source and retrieving data from it The default wrapper name for DB2 UDB for iSeries is DRDA Here is the command to register the DRDA wrapper

db2=gt create wrapper drda

4) Use the CREATE SERVER statement to register a data source as a server within the federated database The server definition specifies the type and version of the data source and the wrapper used for communications with this data source For the DB2 UDB for iSeries data source the node and the database names are also needed The node and database name parameters have been configured for our TPLX database in the Configuration steps in the AIX partition section (on page 24) Use the following DB2 UDB command to lookup these parameter on the federated server

db2=gt list database directory

In this case the command produced the following output

Database alias = TPLX Database name = DCSE99E1 Node name = NDE9BF76 Database release level = a00 Comment = Directory entry type = Remote Authentication = SERVER Catalog database partition number = -1

36

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Note that the node name is set to NDE9BF76 The name was generated by the Configuration Administrator utility (db2ca)

Here is the command to register the TPLX database as a federated server

db2=gt create server tplx type db2400 version 530 wrapperdrda authorization db2user password mypassword options(nodeNDE9BF76 dbname TPLX)

The command is quite complex so make sure that the syntax is correct

5) Define the user mappings that instructs the federated server what user ID and password should be used when connecting to the iSeries data source

db2=gt create user mapping for user server tplxoptions(remote_authid db2user remote_password mypassword)

Specify the nickname for the iSeries table or view A nickname is an identifier that is used by the federated server to reference an object located at the data source The following command creates a nickname for the STAFF table located in the DB2USER schema on the TPLX database

db2=gt create nickname tplx_staff for tplxdb2userstaff

6) Test the distributed join query

db2=gt SELECT deptname name salary + COALESCE(comm0) ascompensation FROM org o tplx_staff s WHERE odeptnumb =sdept ORDER BY deptname compensation DESC

Note that the native iSeries function IFNULL has been substituted with an equivalent DB2 UDB function COALESCE COALESCE is also supported on iSeries servers For better portability IBM encourages the use of COALESCE rather than IFNULL Note also that the query runs on the federated server rather than on TPLX It accesses the ORG table in the local DB2 UDB for AIX SAMPLE database and the STAFF table that resides in TPLX The federated server performs the necessary distributed join

7) Modify the cursorsjsqc so that it executes a distributed join There are two source code modifications - Change the CONNECT TO statements Now the application needs to connect to the

federated database SAMPLE rather than to TPLX

EXEC SQL CONNECT TO SAMPLEEXEC SQL CONNECT TO SAMPLE USER userid USING passwd

- Modify the select statement so that it performs a distributed join Use the statement (shown in step 6) above Save the new source version as cursordjsqc

- Prepare bind and compile the distributed join version of the program as described in the Simple C embedded SQL application section (on page 34)

db2 prep cursordjsqc bindfiledb2 bind cursordjbndxlc -I$INSTHOMEsqllibinclude ndashc cursordjcxlc ndasho cursordj cursordjo -L$INSTHOMEsqlliblib ndashldb2

37

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

- Run the program from the AIX prompt

cursordj

Connection Pooling and Connection ConcentratorA modern Web-based application typically executes a large number of short-lived transactions Executing a transaction in this environment means establishing a database connection executing a few SQL statements and terminating this connection Creating connections to the database server is a very costly process To reduce the unnecessary workload DB2 Connect implements connection pooling and connection concentrator Connection pooling mechanism allows DB2 Connect to reuse an existing connection infrastructure for subsequent connection requests The connection concentrator is an advanced technology that allows DB2 Connect to serve a potentially very large number of clients with a limited number of database connections This is accomplished by decoupling clients from a particular database connection

Note that currently neither connection pooling nor connection concentrator support DB2 UDB for iSeries Therefore for performance reasons the author strongly recommends that the application server that obtains and drops connections very frequently implements its own database connection pooling mechanism that would assign an existing pooled database connection to a new AIX process or thread

TroubleshootingTroubleshooting a multi-tier application may be a bit tricky because the developer needs to deal with software components that reside in separate partitions The authorrsquos experience shows that two tools are particularly useful for pinning down the potential problem areas The joblog messages for a database server job usually provide enough details to isolate DB2

UDB for iSeries runtime issues The DRDA trace utility provides granular information about the data flow between the AIX

application and the iSeries server job

38

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Job Log MessagesAs mentioned earlier a DB2 client communicates with a corresponding iSeries server job This server job runs the SQL requests on behalf of the client More precisely when a DB2 client submits an SQL statement the statement is passed to a server job that in turn calls the DB2 runtime to execute the statement The results are then reformatted and marshaled to the client The iSeries DRDA server jobs are called QRWTSRVR and they run in the QUSRWRK subsystem At any given time there may be a large number of DRDA server jobs active on the system so the first step is to identify the job that serves the particular client connection The easiest method to accomplish this task is to run the following CL command from the i5OS prompt

WRKOBJLCK OBJ(DB2USER) OBJTYPE(USRPRF)

Here DB2USER is the user profile that is used to connect to the iSeries server Note that a QRWTSRVR job is assigned to a client after the connection has been established so the developer needs to set a breakpoint in the client application below the CONNECT TO statement

Once the Work with Object Locks appears key in 5 (Work with Job) next to the only QRWTSRVR job that should be listed This shows the Work with Job dialog Select option 10 to display the job log for the database server job Now the developer can search the job log for any error messages generated by the DB2 runtime

Sometimes it is also useful to include debug messages in the job log The debug messages are informational messages written to the job log about the implementation of a query They describe query implementation methods such as use of indexes join order ODP implementation (reusable versus non-reusable) and so on The easiest way to instruct the iSeries server to include the debug messages is to call the following stored procedure just after the connection to the iSeries server is established

EXEC SQL call qsysqcmdexc(STRDBGUPDPROD(YES)000000002000000)

A sample of the job log messages with debug messages enabled is shown below in Figure 20

Arrival sequence access was used for file STAFFAccess path suggestion for file STAFFQuery options used to build the OS400 query access plan Ending debug message for query ODP created Blocking used for queryCursor SQLCUR201 opened1 rows fetched from cursor SQLCUR201Row not found for SQLCUR201ODP deleted Cursor SQLCUR201 closedDESCRIBE of prepared statement STMT0201 completed

Figure 20 mdash Joblog with debug messages enabled

So the job log offers fairly detailed information on how the AIX client requests were implemented by the DB2 runtime

39

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 DRDA trace utilityThe DB2 DRDA trace utility (db2drdat) provides detailed information about the data streams exchanged between DB2 Connect and target database server The output file produced by the utility contains send and receive communications buffers TCPIP error messages and SQL Communications Area (SQLCA) information Please refer to lsquoDB2 Connect Userrsquos Guidersquo manual for in-depth discussion of the DRDA trace utility

Accessing DB2 UDB for iSeries from CLI DB2 Call Level Interface (CLI ) is based on the Microsoft Open Database Connectivity (ODBC) specification and the ISO CLI standard The DB2 CLI interface gained popularity among DB2 application providers because the developer can build an ODBC application by simply linking the application with libdb2 library on a UNIX server In other words the developer directly utilizes the DB2 ODBC driver services without a need for an ODBC driver manager Additionally in contrast to embedded SQL the developer does not need to precompile or bind DB2 CLI applications because they use packages provided with DB2 UDB The developer simply compiles and links the application

Prerequisites A DB2 CLI application running in an AIX partition will use DB2 Connect services to access DB2 UDB for iSeries therefore make sure that all components listed in Prerequisites section of this paper on page 24 are installed The developer also needs to create a remote database connection as described in the DB2 Connect configuration section of this paper on page 24

Dynamic SQL and Access Plan Caching A DB2 CLI client application uses the dynamic SQL interface and does not have the capability to utilize the extended dynamic SQL support Therefore it runs lsquopurersquo dynamic SQL statements That does not mean however that the process of parsing validating and optimizing will be repeated for every execution of a given dynamic SQL statement

The DB2 UDB for iSeries database implements an internal object called System-Wide SQL Statement Cache (SWSC) The SWSC can improve the performance of programs using dynamic SQL statements by caching the access plans in a system-wide cache When a dynamic SQL statement is submitted the SQL runtime searches the SWSC to see if this statement has been previously executed If so then DB2 retrieves and reuses the key information associated with the cached statement and thereby the processing time and the resources utilization can be significantly reduced

Simple DB2 CLI C++ ApplicationThis section covers DB2 CLI implementation details for a sample C++ program called testclicpp (the source is provided at the end of this paper in Appendix C) To compile the source with Visual C++ complier use the following command in the AIX partition

xlC ndashI$INSTHOMEsqllibinclude ndashc testclicppxlC ndasho testcli testclio ndashL$INSTHOMEsqlliblib ndashldb2

The application performs a join between STAFF and ORG tables located in DB2USER schema (library) The join statement retrieves the DEPTNAME column from ORG NAME and JOB columns from STAFF and calculates the total compensation for an employee by adding SALARY and COMM columns in STAFF The results are sorted by total compensation The selection criterion is based on the current value of the department name parameter Here is the SELECT statement used by testcli

40

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

select name job salary + coalesce(comm0) as compensationfrom org o staff swhere odeptnumb = sdeptand deptname = order by compensation desc

Figure 21 shows the software components involved in the execution of this sample application

Figure 21 How a DB2 CLI client accesses DB2 UDB on an iSeries server

Although the testcli application is fairly simple it covers some important aspects of efficient CLI programming for DB2 UDB for iSeries

Reusable Open Data Paths (ODPs)An Open Data Path (ODP) definition is an internal i5OS object that is created when certain SQL statements (such as OPEN INSERT UPDATE and DELETE) are executed for the first time in a given job (or connection) The ODP can be thought of as a runtime implementation of an access plan The access plan created at the optimization time provides a recipe or in other words a sequence of steps necessary to execute the statement The ODP on the other hand provides the executable code for all requested IO operations The process of creating new ODP objects is fairly CPU- and IO-intensive so whenever possible the iSeries DB2 runtime tries to reuse existing ODPs For instance a SQLCloseCursor() API call may close the SQL cursor but leave the ODP available to be used the next time the cursor is opened This can significantly reduce the processing and response time in running SQL statements A reusable OPD usually requires 10 to 20 times less CPU resources than a newly created ODP Therefore it is important that the applications employ programming techniques that allow the DB2 runtime to reuse ODPs

With dynamic interfaces such as CLI full opens are avoided by using a prepare once execute many programming paradigm It means that when an SQL statement is going to be executed more than once you should prepare the statement just once and then reuse the prepared

41

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

statements for consecutive executions Although DB2 UDB does try to convert literals to parameter markers so that similar statements can be reused it is a better programming practice to explicitly implement parameter markers That way the chances for reusable ODPs are quite significantly improved The code snippet in Figure 22 illustrates how to implement the prepare once execute many programming technique

Define A SELECT SQL Statementstrcpy((char ) SQLStmt select name job salary + ifnull(comm0) ascompensation )ptr = strcat( (char ) SQLStmt from org o staff s )ptr = strcat( (char ) SQLStmt where odeptnumb = sdept)ptr = strcat( (char ) SQLStmt and deptname = )ptr = strcat( (char ) SQLStmt order by compensation desc) [1]

Prepare The SQL Statementrc = SQLPrepare(ExampleStmtHandle SQLStmt SQL_NTS) [2]

Bind The Columns In The Result Data Set Returned To Application Variablesrc = SQLBindCol(ExampleStmtHandle 1 SQL_C_CHAR (SQLPOINTER)

ExampleName sizeof(ExampleName) NULL)rc = SQLBindCol(ExampleStmtHandle 2 SQL_C_CHAR (SQLPOINTER)

ExampleJob sizeof(ExampleJob) NULL)rc = SQLBindCol(ExampleStmtHandle 3 SQL_C_DOUBLE (SQLPOINTER)

ampExampleComp sizeof(ExampleComp) NULL)

for (int i = 0 i lt LOOPS i++)rc=SQLBindParameter(ExampleStmtHandle

1SQL_PARAM_INPUTSQL_C_CHARSQL_CHAR10(SQLPOINTER) currentDepartment[i8]0NULL) [3]

rc = SQLExecute(ExampleStmtHandle) [4]cout ltlt endl ltlt Current Dept ltlt currentDepartment[i8] ltlt endl Display The Results Of The SQL QueryExampleShowResults()

Figure 22 Use the prepare once execute many programming technique

The error-handling code has been removed for clarity At [1] the statement text is assigned to a variable Note that a parameter marker is used in the WHERE clause The statement is then prepared just once at [2] The current value of the parameter is bound to the prepared statement at [3] The prepared statement is executed at [4] Steps [3] and [4] are repeatedly executed in a for loop

Techniques to Further Improve DB2 CLI Performance Thus far this paper has discussed the techniques used by a sample application to tune the CLI performance However depending on the application architecture other methods of improving CLI performance may be considered

Connection PoolingCurrently the CLI application connecting through DB2 Connect to DB2 UDB for iSeries does not take advantage of the connection pooling mechanism implemented by DB2 Connect Therefore for performance reasons the author strongly recommends that the application server that obtains and drops connections very frequently implements its own database connection pooling mechanism that would assign an existing pooled database connection to a new AIX process or thread

42

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Blocking

For queries which result in returning large data blocks from the iSeries server (usually 32K of data and above) ensure that the database manager configuration parameter RQRIOBLK is set to 32767 This can be done using the Command Line Processor (CLP) as follows

db2 update database manager configuration using RQRIOBLK 32767

TroubleshootingThe experience of the author shows that two tools are particularly useful for pinning down the potential problem areas bull Joblog messages for a database server job usually provides enough details to isolate DB2

runtime issues bull CLI trace utility provides granular information about the data flow between the AIX application

and the database server job

Job Log MessagesThe process of finding and analyzing the job log for a DB2 CLI connection is identical to the process outlined for an embedded SQL application in the Job Log Message section of this paper on page 39

CLI Trace The DB2 CLIODBCJDBC trace utility provides very detailed information about the data streams exchanged between DB2 Connect and target database server Refer to the DB2 Information Center for more information on how to set up and analyze the CLI traces httppublibboulderibmcominfocenterdb2v8luwindexjsptopic=comibmdb2udbdocadc000 7959htm

43

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Trademarks

IBM eServer iSeries AIX AIX 5L i5OS WebSphere DB2 DB2 Universal Database DB2 Connect OS400 zOS OS390 Distributed Relational Database Architecture DRDA and DB2 Information Integration are trademarks or registered trademarks of International Business Machines Corporation in the United States and other countries

Java and all Java-based trademarks are trademarks of Sun Microsystems Inc in the United States other countries or both

Linux is a registered trademark of Linus Torvalds in the United States other countries or both

UNIX is a registered trademark of The Open Group in the United States and other countries

Microsoft and Windows are registered trademarks of Microsoft Corporation in the United States andor other countries

All other registered trademarks and trademarks are properties of their respective owners

IBM makes no commitment to make available any products referred to herein

References in this publication to IBM products or services do not imply that IBM intends to make them available in every country in which IBM operates

Additional Information ITSO offers a Redbook that can be helpful to those who want to learn more about i5OS AIX integration

bull AIX Integration with I5OS on the IBM eServer iSeries Server (SG24-6551)

Jarek Miszczyk is the Senior Software Engineer IBM eServer Solutions Enablement IBM Rochester

[Portions of this white paper reprinted with permission from MC Mag Online published by MC Press LLP httpwwwmcpressonlinecom]

Acknowledgments The author would like to thank the following people for their advice contributions and support on this paper

Bob Bittner IBM Rochester Jon Rush IBM Rochester Prasad Vallurupalli IBM Rochester Neil Willis IBM Rochester

44

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix A Source Listing of TestJDBCjava

package comibmiseriespwdimport javasqlimport javaxnamingimport javautilHashtableimport javautilimport javaxsqlimport comibmas400access

public class TestJDBC public static void main(javalangString[] args)

throws Exception

int numOfLoops = 5000int outerNumOfLoops = 5boolean firstExec = trueConnection conStatement sPreparedStatement psPreparedStatement pstmtdelCallableStatement cstmPreparedStatement pstmtHashtable env = new Hashtable()

envput(ContextINITIAL_CONTEXT_FACTORYcomsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env)Systemoutprintln(Deploying connection pooling data source)deployDataSource() Do the work with connection pooling onlyAS400JDBCConnectionPoolDataSource tkcpds =

(AS400JDBCConnectionPoolDataSource)ctxlookup(jdbcToolkitDataSource) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPool pool = new AS400JDBCConnectionPool(tkcpds) Adds 1 connection to the pool that can be used by theapplication (creates the physical database connections based onthe data source)poolfill(1)Systemoutprintln(nStart timing Toolkit connection pooling)long startTime = SystemcurrentTimeMillis()

for (int i = 0 i lt outerNumOfLoops i++) con = poolgetConnection()consetAutoCommit(false) deleteif ( i == 0)

long startDelete = SystemcurrentTimeMillis()cstm = cstm = conprepareCall(

CALL qsysqcmdexc(CLRPFM FILE(DB2USERCOFFEES) + 000000002800000))

cstmexecuteUpdate()cstmclose()long endDelete = SystemcurrentTimeMillis()Systemoutprintln(Delete all records +

(endDelete - startDelete) + ms elapsed)

45

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

String sqlinstrlong startInsert = SystemcurrentTimeMillis() insert

pstmt =conprepareStatement(INSERT INTO COFFEES VALUES( ))for (int j = 0 j lt numOfLoops j++) pstmtsetString(1 Kona_ + IntegertoString(i))pstmtsetInt(2 150)pstmtsetFloat(3 999f)pstmtsetInt(4 0)pstmtsetInt(5 0)pstmtaddBatch()int [] updateCounts = pstmtexecuteBatch()concommit()pstmtclose()long endInsert = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for + numOfLoops + inserts

+ (endInsert - startInsert)) selectlong startSelect = SystemcurrentTimeMillis()ps = conprepareStatement(SELECT FROM COFFEES)ResultSet rs = psexecuteQuery()rsnext()rsclose()concommit()psclose()long endSelect = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for select +

(endSelect - startSelect))consetAutoCommit(true)conclose()long endTime = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for + outerNumOfLoops +

loops + (endTime - startTime))Systemexit(0)

private static void deployDataSource()throws ExceptionString serverName = teraplex String databaseName = TERAPLEX String userName = db2user String password = db2pwd

Establish a JNDI context and bind the connection pool data sourceHashtable env = new Hashtable()envput(ContextINITIAL_CONTEXT_FACTORY

comsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPoolDataSource tkcpds = new

AS400JDBCConnectionPoolDataSource()tkcpdssetServerName(serverName) tkcpdssetDatabaseName(databaseName) tkcpdssetUser(userName) tkcpdssetPassword(password) tkcpdssetDescription(Toolkit Connection Pooling DataSource)tkcpdssetSavePasswordWhenSerialized(true)tkcpdssetExtendedDynamic(true)

46

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

tkcpdssetPackage(JDBCDS)tkcpdssetPackageCache(true)tkcpdssetPackageCriteria(select)enable the following properties as requiredcpdssetTrace(true)tkcpdssetServerTraceCategories( AS400JDBCDataSourceSERVER_TRACE_DEBUG_SERVER_JOB)

ctxrebind(jdbcToolkitDataSource tkcpds)

47

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix B mdash Source Listing of cursorsjsqc

Source File Name = cursorsjsqc Licensed Materials - Property of IBM (C) COPYRIGHT International Business Machines Corp 1995 2000 2004 All Rights Reserved US Government Users Restricted Rights - Use duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp PURPOSE This sample program demonstrates the use of a CURSOR The CURSOR is processed using static SQL EXTERNAL DEPENDENCIES - Ensure existence of database for precompile purposes - Precompile with the SQL precompiler (PREP in DB2) - Bind to a database (BIND in DB2) - Compile and link with the IBM Cset++ compiler (AIX and OS2) or the Microsoft Visual C++ compiler (Windows) or the compiler supported on your platform For more information about these samples see the README file For more information on programming in C see the - Programming in C and C++ section of the Application Development Guide For more information on building C applications see the - Building C Applications section of the Application Building Guide For more information on the SQL language see the SQL Reference

include ltstdiohgt include ltstdlibhgt include ltstringhgtinclude ltsqlhgtinclude ltsqlenvhgtinclude ltsqldahgtinclude ltsqlcahgt

int SqlInfoPrint( char struct sqlca int char )void TransRollback( void)

define EMB_SQL_CHECK( MSG_STR ) rc = SqlInfoPrint( MSG_STR ampsqlca __LINE__ __FILE__) if ( rc = 0 ) TransRollback( )

return 1

EXEC SQL INCLUDE SQLCA

int main(int argc char argv[])

EXEC SQL BEGIN DECLARE SECTIONchar dname[15]

48

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

char pname[10]double compchar userid[9]char passwd[19]

EXEC SQL END DECLARE SECTION

int rc = 0printf( Sample C program CURSORSJ n )if (argc == 1)

EXEC SQL CONNECT TO TPLXEMB_SQL_CHECK(CONNECT TO TPLX)

else if (argc == 3)

strcpy (userid argv[1])strcpy (passwd argv[2])EXEC SQL CONNECT TO TPLX USER userid USING passwdEMB_SQL_CHECK(CONNECT TO TPLX)

else

printf (nUSAGE cursor [userid passwd]nn)return 1

endif

EXEC SQL DECLARE c1 CURSOR FORselect deptname name salary + ifnull(comm0) as compensationfrom org o staff swhere odeptnumb = sdeptorder by deptname compensation desc

EXEC SQL OPEN c1EMB_SQL_CHECK(OPEN CURSOR)

printf(DEPARTMENT NAME COMPENSn)printf(-----------------------------------n)do

EXEC SQL FETCH c1 INTO dname pname compif (SQLCODE = 0) breakprintf( -1515s -1010s 72fn dname pname comp )

while ( 1 )

EXEC SQL CLOSE c1EMB_SQL_CHECK(CLOSE CURSOR)

EXEC SQL CONNECT RESETEMB_SQL_CHECK(CONNECT RESET)

exit(0)

end of program CURSORSJSQC

int SqlInfoPrint( char appMsgstruct sqlca pSqlcaint linechar file )

int rc = 0char sqlInfo[1024]char sqlInfoToken[1024]char sqlstateMsg[1024]char errorMsg[1024]

if (pSqlca-gtsqlcode = 0 ampamp pSqlca-gtsqlcode = 100)

49

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

strcpy(sqlInfo )if( pSqlca-gtsqlcode lt 0) sprintf( sqlInfoToken n---- error report ----n)

strcat( sqlInfo sqlInfoToken)else sprintf( sqlInfoToken n---- warning report ----n)

strcat( sqlInfo sqlInfoToken) endif

sprintf( sqlInfoToken app message = sn appMsg)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken line = dn line)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken file = sn file)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken SQLCODE = ldn pSqlca-gtsqlcode)strcat( sqlInfo sqlInfoToken)

get error message rc = sqlaintp( errorMsg 1024 80 pSqlca) return code is the length of the errorMsg string if( rc gt 0) sprintf( sqlInfoToken sn errorMsg)

strcat( sqlInfo sqlInfoToken)

get SQLSTATE message rc = sqlogstt( sqlstateMsg 1024 80 pSqlca-gtsqlstate)if (rc == 0) sprintf( sqlInfoToken sn sqlstateMsg)

strcat( sqlInfo sqlInfoToken)

if( pSqlca-gtsqlcode lt 0) sprintf( sqlInfoToken --- end error report ---n)

strcat( sqlInfo sqlInfoToken)printf(s sqlInfo)return 1

else sprintf( sqlInfoToken --- end warning report ---n)

strcat( sqlInfo sqlInfoToken)printf(s sqlInfo)return 0

endif endif

return 0

void TransRollback( ) struct sqlca sqlca

int rc = 0 rollback the transaction printf( nRolling back the transaction n)

EXEC SQL ROLLBACKrc = SqlInfoPrint( ROLLBACK ampsqlca __LINE__ __FILE__)if( rc == 0) printf( The transaction was rolled backn)

50

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

51

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix C mdash Source Listing of testclicpp

Include The Appropriate Header Filesinclude ltsqlclihgtinclude ltsqlcli1hgtinclude ltsqlutilhgtinclude ltsqlenvhgtinclude ltstdiohgt include ltiostreamgt include ltlocalehgt include ltstringhgtdefine SQL_SQLSTATE_SIZE 5define LOOPS 8

using namespace std

Define The CLI_Class Classclass CLI_Class

Attributespublic

SQLHANDLE EnvHandleSQLHANDLE ConHandleSQLHANDLE StmtHandleSQLRETURN rcSQLCHAR Job[6]SQLCHAR Name[10]SQLDOUBLE Comp

Operationspublic

CLI_Class()~CLI_Class()SQLRETURN ShowResults()

Constructor Destructor

SQLRETURN printError( SQLHDBC SQLHSTMT)

Define The Class ConstructorCLI_ClassCLI_Class()

setlocale( LC_ALL )

Initialize The Return Code Variablerc = SQL_SUCCESS

Allocate An Environment Handlerc = SQLAllocHandle(SQL_HANDLE_ENV SQL_NULL_HANDLE ampEnvHandle)

Allocate A Connection Handleif (rc == SQL_SUCCESS)

rc = SQLAllocHandle(SQL_HANDLE_DBC EnvHandle ampConHandle)

Define The Class DestructorCLI_Class~CLI_Class()

Free The Connection Handleif (ConHandle = NULL)

SQLFreeHandle(SQL_HANDLE_DBC ConHandle)

Free The Environment Handle

52

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

if (EnvHandle = NULL)SQLFreeHandle(SQL_HANDLE_ENV EnvHandle)

Define The ShowResults() Member FunctionSQLRETURN CLI_ClassShowResults(void)

While There Are Records In The Result Data Set Generated Retrieve And Display Themcout ltlt Name Job Compensation ltlt endlcout ltlt --------- ------ ------------ ltlt endlcoutsetf(iosleft)coutprecision(2)coutsetf(iosfixed)while (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)

rc = SQLFetch(StmtHandle)if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)

coutwidth(15)cout ltlt Name

coutwidth(10)cout ltlt Job

coutwidth(7)cout ltlt Comp ltltendl

if(rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO ampamp rc = SQL_NO_DATA)printError(ConHandle StmtHandle)

else

rc = 0SQLCloseCursor(StmtHandle)

Return The ODBC API Return Code To The Calling Functionreturn(rc)

SQLRETURN CLI_ClassprintError (SQLHDBC hdbc

SQLHSTMT hstmt)

SQLCHAR buffer[SQL_MAX_MESSAGE_LENGTH + 1]SQLCHAR sqlstate[SQL_SQLSTATE_SIZE + 1]SQLINTEGER sqlcodeSQLSMALLINT lengthSQLRETURN rcwhile ((rc = SQLError(SQL_NULL_HENV hdbc hstmt

sqlstateampsqlcodebufferSQL_MAX_MESSAGE_LENGTH + 1amplength)) == SQL_SUCCESS || rc ==

SQL_SUCCESS_WITH_INFO)

cout ltlt SQLSTATE ltlt sqlstate ltlt endlcout ltlt SQLCODE ltlt sqlcode ltlt endlcout ltlt Error msg ltlt buffer ltlt endl

53

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

cout ltlt----------------------------- ltlt endl ltlt endl

return(SQL_ERROR)

----------------------------------------------------------------- The Main Function -----------------------------------------------------------------int main()

Declare The Local Memory Variables

(SQLCHAR ) db2user SQL_NTS (SQLCHAR ) test26t SQL_NTS)

SQLRETURNSQLCHARSQLCHARSQLCHARchar

SQLCHAR

rc = SQL_SUCCESSDBName[10] = TPLXSQLStmt[255]c[10]ptrcurrentDepartment[8][15] = Head Office

New England Mid Atlantic South Atlantic Great Lakes PlainsPacificMountain

Create An Instance Of The CLI_Class ClassCLI_Class Example

Connect To iSeries Database if (ExampleConHandle = NULL)

rc = SQLConnect(ExampleConHandle DBName SQL_NTS

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)ExampleprintError(ExampleConHandle SQL_NULL_HSTMT)

return(rc)

cout ltlt Successfully connected to ltlt DBName ltlt ltlt endlrc = SQLSetConnectAttr(ExampleConHandle SQL_ATTR_AUTOCOMMIT

(SQLPOINTER) SQL_AUTOCOMMIT_OFF SQL_IS_UINTEGER) Allocate An SQL Statement Handlerc = SQLAllocHandle(SQL_HANDLE_STMT ExampleConHandle

ampExampleStmtHandle)if (rc == SQL_SUCCESS)

Define A SELECT SQL Statement

strcpy((char ) SQLStmt select name job salary + ifnull(comm0) ascompensation )

ptr = strcat( (char ) SQLStmt from org o staff s )ptr = strcat( (char ) SQLStmt where odeptnumb = sdept)ptr = strcat( (char ) SQLStmt and deptname = )ptr = strcat( (char ) SQLStmt order by compensation desc)

Prepare The SQL Statementrc = SQLPrepare(ExampleStmtHandle SQLStmt SQL_NTS)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)ExampleprintError(ExampleConHandle ExampleStmtHandle)

54

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

return(rc)

Bind The Columns In The Result Data Set Returned To Application Variables

rc = SQLBindCol(ExampleStmtHandle 1 SQL_C_CHAR (SQLPOINTER)ExampleName sizeof(ExampleName) NULL)

rc = SQLBindCol(ExampleStmtHandle 2 SQL_C_CHAR (SQLPOINTER)ExampleJob sizeof(ExampleJob) NULL)

rc = SQLBindCol(ExampleStmtHandle 3 SQL_C_DOUBLE (SQLPOINTER)ampExampleComp sizeof(ExampleComp) NULL)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO) ExampleprintError(ExampleConHandle ExampleStmtHandle)

return(rc)

while (true)

for (int i = 0 i lt LOOPS i++)

rc=SQLBindParameter(ExampleStmtHandle1SQL_PARAM_INPUTSQL_C_CHARSQL_CHAR

150(SQLPOINTER) currentDepartment[i8]0NULL)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)

ExampleprintError(ExampleConHandle ExampleStmtHandle)return(rc)

rc = SQLExecute(ExampleStmtHandle)if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)

ExampleprintError(ExampleConHandle ExampleStmtHandle)return(rc)

cout ltlt endl ltlt Current Dept ltlt currentDepartment[i8] ltlt

endl Display The Results Of The SQL QueryExampleShowResults()if(rc = 0)break

if ( i500 == 0 ampamp i gt 0 )cout ltlt Loops ltlt i ltlt ltlt endl

cout ltlt AFTER ltlt LOOPS ltlt loops Press X to exit ltlt endlcin gtgt cif (c[0] == x || c[0] == X)

break

Free The SQL Statement Handleif (ExampleStmtHandle = NULL )

SQLFreeHandle(SQL_HANDLE_STMT ExampleStmtHandle) Disconnect From The Northwind Sample Databaserc = SQLDisconnect(ExampleConHandle)

Return To The Operating Systemreturn(rc)

55

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Virtual Versus Physical LAN One of the most significant benefits of installing AIX in an iSeries partition is the ability to utilize virtual LAN and virtual DASD This usually results in reduced hardware costs through improvements in data transfer performance and enhanced disk protection The performance tests conducted by the IBM eServer Solutions Enablement team showed that the Virtual 1Gb LAN delivered a data throughput similar to dedicated 1Gb Ethernet adapters (model 5706) connected via a dedicated Ethernet segment An example configuration is illustrated in Figure 2

Figure 2 VLAN vs 1 Gb Ethernet IOA configuration

Although similar performance can be expected for VLAN and 1Gb Ethernet the VLAN configuration has two advantages over the physical LAN connection

bull No additional communications gear is required bull It is a dedicated point-to-point connection so there is no interference from other devices on

the same network segment

On the other hand certain application scenarios may benefit from a physical LAN adapter dedicated to an AIX partition For instance in a three-tier application architecture clients connect to an application server running in a AIX partition The application server in turn connects to DB2 UDB for iSeries where data is stored and retrieved In this case configuring a separate physical LAN connection in a AIX partition has the following advantages

bull An unnecessary additional hop is eliminated from the network route bull Client-application server traffic does not unnecessarily saturate i5OS communications gear

5

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Tuning DB2 UDB for iSeries Access with IBM Toolbox for Java and JTOpen Driver This section covers JDBC implementation details for a sample Java program called TestJDBC (the source is provided at the end of this paper in Appendix A) The application uses the Java Naming and Directory Interface (JNDI) to obtain a database connection deletes 5000 records generates and inserts 5000 records and finally retrieves the newly inserted records from an SQL table called COFFEES The application executes in an AIX partition and accesses the DB2 UDB for iSeries through the JTOpen (or IBM Toolbox for Java) driver Figure 3 shows the software components involved in the execution of this simple application

Figure 3 JDBC client accessing DB2 UDB for iSeries

Apart from the JTOpen driver which can be downloaded from the IBM Toolbox for Java Web site you need three other JAR files to successfully compile and execute the JDBCTest application in a AIX partition

bull providerutiljar and fscontextjar mdashDownload a simple file system JNDI provider from Sun Microsystems JNDI Web site httpjavasuncomproductsjndidownloadsindexhtml

bull jdbc2_0-stdextjar mdash Copy the javaxsql package from the QIBMUserDataJava400ext IFS directory on the iSeries server

The location of the JAR files needs to be added to the CLASSPATH environment variable For instance the following entry could be added to the AIX profile script

6

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

CLASSPATH=homecodeJTOpenjt400jarCLASSPATH=$CLASSPATHhomecodefscontextproviderutiljarCLASSPATH=$CLASSPATHhomecodefscontextfscontextjarCLASSPATH=$CLASSPATHhomecodeJTOpenjdbc2_0-stdextjarexport CLASSPATH

To compile the source use the following command in the AIX partition

javac TestJDBCjava

Although the TestJDBC application is fairly simple it illustrates several important aspects of efficient JDBC programming for DB2 UDB for iSeries

Connection PoolingA JDBC connection can be obtained through either the DataSource or DriverManager object Either method involves significant overhead A fairly large amount of system resources is required to create and maintain the connection and then release it when it is no longer needed JTOpen allows a developer to establish a pool of database connections that can be shared by multiple client applications Connection pooling can improve the response time because the connection pool manager can locate and use an existing connection When the database request is completed the connection returns to the connection pool for reuse

In the JDBCTest sample JNDI was first used to register a connection pool-capable data source Heres an excerpt from the deployDataSource method of the sample application

Hashtable env = new Hashtable()envput(ContextINITIAL_CONTEXT_FACTORY

comsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env) [1]

Register an AS400JDBCConnectionPoolDataSource objectAS400JDBCConnectionPoolDataSource tkcpds = newAS400JDBCConnectionPoolDataSource() [2]tkcpdssetServerName(serverName) tkcpdssetDatabaseName(databaseName) tkcpdssetUser(userName) tkcpdssetPassword(password) tkcpdssetDescription(Toolkit Connection Pooling DataSourceobject) hellip ctxrebind(jdbcToolkitDataSource tkcpds) [3]

At [1] the initial JNDI context is created

Then at [2] an AS400JDBCConnectionPoolDataSource object is instantiated This is the JTOpen implementation of the javaxsqlConnectionPoolDataSource interface An AS400JDBCConnectionPoolDataSource object supports a number of methods that can be used to set iSeries-specific properties of the underlying DataSource object Some of these properties will be discussed in greater detail in the following sections of this paper

At [3] the data source object is bound to an arbitrary name that will be used in the main application Note that the deployDataSource method needs to be executed just once unless some of the data source properties need to be changed In that case the developer would need to rebind

7

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

The JNDI registered data source is then used in the main application to initialize the connection pool

AS400JDBCConnectionPoolDataSource tkcpds = [1](AS400JDBCConnectionPoolDataSource)ctxlookup(jdbcToolkitDataSource) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPool pool = newAS400JDBCConnectionPool(tkcpds)[2] Adds 1 connection to the pool that can be used by the application(creates the physical database connections based on the datasource)poolfill(1) [3] hellip con = poolgetConnection()[4]

At [1] the JNDI service is used to instantiate the AS400JDBCConnectionPoolDataSource

Then at [2] an AS400JDBCConnectionPool object is created This object is responsible for managing the connection pool

At [3] the connection pool is initialized with one connection

The pool object is used at [4] to obtain a database connection There are several additional things the developer should know about this code snippet

bull The advantage of using JNDI to register the data source object as opposed to just instantiating it in the main method is that in a more realistic scenario the data source would be registered just once at application deployment time Additionally the data source properties do not have to be hard-coded in the main method and can be changed at any time and then rebound without affecting the application

bull The AS400JDBCConnectionPool is a proprietary JTOpen implementation of a connection pool Specifically it does not implement the Referenceable interface and thus cannot be bound through JNDI services

bull The JTOpen AS400JDBCConnectionPoolDataSource does not support statement caching as described in the JDBC 30 specification Statement caching is implemented through SQL packages This feature is covered in the following section

Note The native iSeries JDBC driver supports both connection pooling and statement caching in a JDBC 30 compliant manner

8

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Extended Dynamic SQL and Statement Caching As mentioned the JTOpen data source object supports a number of properties that can be used to fine-tune the database performance In this section properties used to enable extended dynamic SQL support (see DB2 SQL Runtime Interfaces section above) and local statement caching will be discussed

Here is a relevant code excerpt from the deployDataSource method

AS400JDBCConnectionPoolDataSource tkcpds = new AS400JDBCConnectionPoolDataSource() hellip tkcpdssetExtendedDynamic(true)[1]tkcpdssetPackage(JDBCDS) [2]tkcpdssetPackageCache(true) [3]tkcpdssetPackageCriteria(select) [4]

At [1] the extended dynamic SQL support is enabled Note that the default is disabled for JTOpen The extended dynamic SQL functionality is often referred to as SQL package support The SQL packages are server-side repositories for SQL statements Packages contain the internal structures such as parse trees and access plans which are needed to execute SQL statements Because SQL packages are a shared resource the information built when a statement is prepared is available to all the users of the package This saves processing time especially in an environment where many users are using the same or similar statements Also because SQL packages are permanent this information is saved across job initiationtermination and IPLs In fact SQL packages can be saved and restored on other servers

At [2] the SQL package is named Note that the actual package name on the iSeries server is JDBCDSBAA The package name is generated by taking the name specified on the client and appending three letters that are an encoded set of the package configuration attributes By default an SQL package does not contain unparameterized select statements This behavior is overridden at [4] by setting the PackageCriteria property to select

At [3] the local statement cache is enabled A copy of the SQL package is cached on the AIX client This may improve application performance in a way similar to JDBC 30 statement caching Note however that local statement caching is not recommended for large SQL packages The copy of an SQL package is cached when the database connection is obtained This may cause increased network traffic as well as slow down the connection setup time

Reusable Open Data Paths (ODPs)An Open Data Path (ODP) definition is an internal i5OS object that is created when certain SQL statements (such as OPEN INSERT UPDATE and DELETE) are executed for the first time in a given job (or connection) The ODP can be thought of as a runtime implementation of an access plan The access plan created at the optimization time provides a recipe or in other words a sequence of steps necessary to execute the statement The ODP on the other hand provides the executable code for all requested IO operations The process of creating new ODP objects is fairly CPU- and IO-intensive so whenever possible the iSeries DB2 runtime tries to reuse existing ODPs For instance a ResultSetclose() call may close the SQL cursor but leave the ODP available to be used the next time the cursor is opened This can significantly reduce the response time in running SQL statements A reusable OPD usually requires 10 to 20 times less CPU resources than a newly created ODP Therefore it is important that the applications employ programming techniques that allow the DB2 runtime to reuse ODPs

With dynamic programming interfaces such as JDBC the most efficient way to avoid full opens is to employ the so-called prepare once execute many programming paradigm Ideally an SQL statement that is executed more than once should be prepared just once mdashfor example in the class constructor mdash and then reused for the consecutive executions At the prepare time the

9

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 engine stores the prepared statement along with the associated statement name in the QZDASOINIT jobs statement cache On the first execution the ODP created for a given statement is associated with the appropriate entry in the statement cache On consecutive executions the prepared statement and the corresponding ODP can be quickly located in the statement cache and reused The code snippet below illustrates the prepare once execute many programming technique

PreparedStatement pstmt = conprepareStatement(INSERT INTO COFFEES VALUES( ))[1] hellip for (int i = 0 i lt outerNumOfLoops i++)

insertfor (int j = 0 j lt numOfLoops j++)

pstmtsetString(1 Lavaza_ + IntegertoString(j)) hellip pstmtaddBatch()

int [] updateCounts = pstmtexecuteBatch()[2]concommit()

At [1] a PreparedStatement pstmt object is instantiated for a parameterized INSERT statement The statement is prepared just once The PreparedStatement object is then repeatedly used at [2] to perform blocked insert

Block Inserts Occasionally the developer may need to initially populate a table or insert a modified result set into a temporary table The efficiency of the insert operation for a large set of records can be dramatically improved by using the executeBatch method rather than the executeUpdate method The JTOpen driver converts parameterized insert statements in an executeBatch method to a block insert statement This significantly reduces the data flow and system resources required to perform the insert The following code snippet shows how to take advantage of the executeBatch method

10

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

PreparedStatement pstmt =conprepareStatement(INSERT INTO COFFEES VALUES( ))[1]for (int j = 0 j lt numOfLoops j++) pstmtsetString(1 Lavaza_ + IntegertoString(j))pstmtsetInt(2 i)pstmtsetFloat(3 499f)pstmtsetInt(4 0)pstmtsetInt(5 0)pstmtaddBatch() [2]

int [] updateCounts = pstmtexecuteBatch() [3]

At [1] a parameterized insert statement is prepared Note that all columns must be parameterized Otherwise the executeBatch method may throw the SQL0221 Number of rows 1 not valid exception In other words the developer should not mix parameter markers with literals or special registers in the VALUE clause

At [2] the addBatch method is used to add a new record to the client record buffer

At [3] all locally buffered data is sent to the server which in turn performs a block insert

Figure 4 shows the performance data for the executeBatch and executeUpdate methods

Figure 4 executeBatch() versus executeUpdate() performance comparison

11

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

WebSphere Considerations In certain situations an application provider may decide to deploy WebSphere Application Server in an AIX partition rather than natively in i5OS At the same time the application uses DB2 UDB for iSeries as an back-end database server Typically the WebSphere Application Server running in the AIX partition uses the virtual LAN to communicate with DB2 UDB for iSeries The WebSphere applications will access the database through a remote JDBC connection For performance and functionality reasons IBM recommends to utilize in such environments the IBM Toolbox for Java JTOpen driver Most of the tips and techniques described so far in this document hold true for WebSphere applications accessing DB2 UDB for iSeries There are however certain JDBC access aspects that are specific to this multi-tier architecture Letrsquos have a closer look at some of these considerations

Connection Pooling and Statement Caching

WebSphere Application Server provides its own connection pooling and statement caching mechanism that is by default enabled so that WebSphere applications automatically enjoy the performance benefits of these two critical programming techniques See the following link to learn more about the optimal connection pool setting in WebSphere

httppublibboulderibmcomwas40051englishinforzaiz51adminhelpudat_conpoolsethtml

Extended Dynamic SQL

For non-JTA connections WebSphere Application Server uses the comibmas400accessAS400JDBCConnectionPoolDataSource class as the iSeries JDBC provider implementation This is the DataSource implementation that has been used in all previous coding examples As mentioned the class supports a range of iSeries specific properties that can be used to fine tune JDBC performance These properties can be set through the WebSphere Application Server admin console For example herersquos the procedure to enable the extended dynamic SQL support In the WebSphere Application Server admin console navigate to the Data Source configuration dialog by selecting JDBC Providers -gt iSeriesToolbox -gt Data Sources then scroll down to the Additional Properties section Select Custom Properties link The Custom Properties dialog opens Scroll down to find the Extended Dynamic property and select it Change the default value false to true save the new configuration by clicking Apply button This is illustrated in Figure 5

12

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 5 Enabling the extended dynamic SQL through WebSphere Application Server console

The WebSphere Application Server needs to be restarted for the change to take effect The similar procedure can be followed to set other iSeries Data Source properties

Changing the WebSphere Application Server default isolation level

WebSphere Application Server V5 uses the REPEATABLE_READ (RR) isolation level for all implicit (WebSphere Application Server managed) transactions With the RR isolation level the rows selected updated deleted and inserted are locked until the end of the transaction Under certain circumstances this fairly extensive locking policy may cause locking contention especially when a WebSphere application competes for database resources with other applications that run on iSeries server For example a legacy order entry application may share data with the e-business customer care application running in WebSphere The locking contention may sometimes be eliminated by lowering the isolation level used by WebSphere Although the iSeries Data Source supports the custom transactionIsolation property resetting this property on the Data Source object will not change the default isolation level used by WebSphere for the connection objects produced by that Data Source In other words WebSphere will override the Data Source isolation level setting at the time the connection is obtained by a WebSphere application object such as servlet or Enterprise Java Bean (EJB) In order to change the default WebSphere behavior one must use the resource referencing Resource referencing allows a programmer to lookup DataSource or EJB objects using alias names rather than JNDI names Additionally by creating a resource reference a programmer can change certain properties of the underlying object Specifically a DataSource reference can be used to set a different isolation level for the connections produced by this database resource Typically resource references are defined by a programmer in a application development tool such as WebSphere Studio Application Developer The method to specify a DataSource reference differs depending on whether a programmer plans to use the reference in a servlet or in an EJB Letrsquos start with outlining the configuration process for a servlet In WebSphere Studio Application Developer open the deployment descriptor editor for the web project that contains the servlet To do so double click on the webxml file under WEB-INF directory in the web project In the deployment editor dialog select the References tab and then select Resource tab located in the top of the dialog that appears Under Resource References section select the Add button Herersquos an example of a DataSource reference created for iSeries DataSource named TestJDBCDS Note that the reference changes the default isolation level to READ_COMMITTED

13

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 6 Defining a resource reference for a servlet

Once the resource reference has been defined and saved the servlet source code needs to be changed to reflect the fact that a resource reference is used to obtain a DataSource from the JNDI service Herersquos the relevant code snippet try

ctx = new InitialContext() ds = (DataSource)ctxlookup(javacompenvTestJDBCJ2C)

catch (Exception e) eprintStackTrace(out)

Now the ds DataSource object will produce connections that by default run with the isolation level of READ_COMMITTED (RC)

As mentioned the process of defining a resource reference for an EJB differs from the process that is used in the case of a servlet In WebSphere Studio Application Developer open the deployment descriptor editor for the EJB project that contains the EJB To do so double click on the ejb-jarxml file under WEB-INF directory in the project In the deployment editor dialog select the References tab In the references section on the left locate and select the EJB for which the developer wants to change the default isolation level Click the Add button The Add Reference dialog opens Click the Resource Reference radio button and then Next Define the reference following the example shown in Figure 7

14

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 7 Adding a resource reference for an EJB

When you click ldquoFinishrdquo the reference definition is added to the EJB descriptor The new definition needs to be further modified To do so click on the (+) sign next to the EJB in the References list Click the new reference TestJDBCJ2C in this example to open the properties for the reference Change WebSphere Bindings and WebSphere Extensions sections as illustrated in Figure 8

15

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 8 Defining a resource reference for an EJB

Save the modified definition and then change the EJB source code to use the reference rather than directly DataSource

TroubleshootingTroubleshooting a multi-tier application may be a bit tricky because the developer needs to deal with software components that reside in separate partitions Three tools are particularly useful for pinning down the potential problem areas bull Joblog messages for a database server job mdash Provides enough details to isolate DB2 UDB for

iSeries runtime issues bull JDBC trace utility mdash Provides granular information about the data flow between the AIX

application and the iSeries server job bull Database Monitor ndash Provides detailed SQL runtime trace

Job Log MessagesAs mentioned a DB2 client communicates with a corresponding iSeries server job This server job runs the SQL requests on behalf of the client The iSeries database server jobs are called QZDASOINIT and they run in the QUSRWRK subsystem At any given time a large number of database server jobs may be active on the server so the first step is to identify the job that serves the particular client connection The easiest method to accomplish this task is to run the following CL command from the i5OS prompt

WRKOBJLCK OBJ(DB2USER) OBJTYPE(USRPRF)

Here DB2USER is the user profile that is used to connect to the iSeries server Note that a QZDASONIT job is assigned to a client after the connection has been established so the developer needs to set a breakpoint in the client application after the database connection has been established

Once the Work with Object Locks appears key in 5 (Work with Job) next to the only QZDASOINIT job that should be listed This shows the Work with Job dialog Select option 10 to

16

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

display the job log for the database server job Now the job log can be searched for any error messages generated by the DB2 runtime

Sometimes it is also useful to include debug messages in the job log The debug messages are informational messages written to the job log about the implementation of a query They describe query implementation methods such as the use of indexes join order ODP implementation (reusable versus non-reusable) and so on The easiest way to instruct an iSeries server to include the debug messages is to set the ServerTraceCategories property on the data source object

tkcpdssetServerTraceCategories(AS400JDBCDataSourceSERVER_TRACE_DEBUG_SERVER_JOB)

A sample of the job log messages with debug messages enabled is shown below

SET TRANSACTION completeSTATEMENT NAME FOUND QZ868F0A458E13AF8C Starting optimizer debug message for query Arrival sequence access was used for file COFFEESODP created ODP not deleted 5000 rows inserted in COFFEES in DB2USER STATEMENT NAME FOUND QZ868F0A4C144BF12EBlocking used for queryCursor CRSR0001 opened606 rows fetched from cursor CRSR0001 ODP not deleted Cursor CRSR0001 closed

So the job log offers fairly detailed information on how the AIX client requests were implemented by the DB2 runtime

JDBC Trace UtilityThe JTOpen driver provides a tracing utility which can be used to collect detailed client-side traces The JDBC tracing is turned off by default It can be enabled by setting the Trace property to true Heres an example of how to switch on tracing using the setTrace method on the data source object

tkcpdssetTrace(true)

The trace can also be enabled when using the DriverManagergetConnection() method for obtaining a connection to DB2 UDB for iSeries In this case the developer could add the trace property to the connection string This approach is illustrated in the following code snippet

ClassforName(comibmas400accessAS400JDBCDriver) [1] hellip con = DriverManagergetConnection(jdbcas400teraplextrace=true

db2userdb2pwd) [2]

At [1] an instance of the JTOpen JDBC Driver is initiated Then at [2] the driver is used to obtain a connection to the iSeries server Note how the trace property has been added to the database URL See the IBM Toolbox for Java JDBC properties documentation on the iSeries Information Center Web site for a complete list of properties supported by the JTOpen driver

Although the level of details provided by the trace utility is sufficient in most troubleshooting scenarios sometimes the developer may need to collect low-level traces scoped to a certain type

17

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

of information In V5R3 the IBM Toolbox for Java (as well as the latest JTOpen) added a comprehensive detailed trace facility The following is the complete list of detailed trace parameters and their purpose

bull None or ldquordquo ndash This setting disables the detailed trace bull datastream - This category is used by Toolbox classes to log dataflow between the local host

and the remote system It is not intended for use by application classes bull diagnostic - This category is used to log object state information bull error - This category is used to log errors that cause an exception bull information - This category is used to track the flow of control through the code bull warning - This category is used to log errors that are recoverable bull conversion - This category is used by Toolbox classes to log character set conversions

between Unicode and native code pages bull proxy - This category is used by Toolbox classes to log data flow between the client and the

proxy server bull pcml - This category is used to determine how PCML interprets the data that is sent to and

from the server bull jdbc - This category is used to track JDBC calls throughout the program bull thread - This category is used to enable tracing of thread information This is useful when

debugging multi-threaded applications bull all - This category will enable all previous categories

The detailed trace can be enabled when using the DriverManagergetConnection() method for obtaining a connection to DB2 UDB for iSeries In this case the developer could add the toolbox trace property to the connection string This is illustrated in the following code sample

String dbUrl = jdbcas400pwd1toolbox trace=diagnostic con = DriverManagergetConnection(dbUrl dbUser dbPassword)

Note that currently the driverrsquos DataSource interfaces do not allow the developer to directly activate the detailed tracing However they could set the server from the command line at the time the java program is launched The example below shows how the detailed trace properties could be enabled at the command line

java -Dcomibmas400accessTracecategory=diagnostic TestJDBC

The -D switch indicates to the java interpreter that the information following it will be a system property

In case of a WebSphere application the trace property can be set through the admin console In the console select Application Servers-gt server1-gt Process Definition -gt Java Virtual Machine Figure 9 shows how to set the Generic JVM Arguments for an application server instance

18

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 9 Setting JVM arguments to enable detailed Toolbox tracing

Database Monitor

The database monitor is the ultimate tool available on DB2 UDB for iSeries to collect low-level SQL traces It is mainly used to pin down the SQL performance problems Refer to the lsquoUsing iSeries Database Monitor to Identify and Tune SQL Queriesrsquo white paper for a detailed discussion on how to collect and analyze the database monitor traces httpibmcomserversenablesiteeducationiborecordhtmldtmon

IBM DB2 JDBC Universal Driver DB2 JDBC Universal Driver is one of the new features delivered with DB2 UDB Version 8 DB2 JDBC Universal Driver has been designed to eliminate the dependency on DB2 CLI runtime modules as well as to enable direct Type 4 connectivity to DB2 UDB for iSeries and DB2 UDB for zOSreg

The pure-Java (Type 4) remote connectivity is based on the DRDA open distributed protocol for cross-platform access to DB2 DRDA defines the rules the protocols and the semantics for accessing distributed data Applications can access data in a distributed relational environment by using SQL statements The iSeries DRDA application server implementation is based on multiple connection-oriented server jobs running in the QSYSWRK subsystem A DRDA listener job (QRWTLSTN) listens for TCP connect requests on port 446 Once an application requester connects to the listener job the listener wakes up one of the QRWTSRVR prestart jobs and assigns it to a given client connection Any further communication occurs directly between the client application and the QRWTSRVR job These concepts are illustrated in Figure 10

19

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 10 Accessing DB2 UDB for iSeries with DB2 Universal Driver

The DB2 Universal Driver can be loaded in an AIX partition by installing one of the DB2 Connect for AIX products (see the Additional Information section for details) It is also a part of a DB2 Enterprise Server Edition for AIX install Specifically the developer needs three JAR files in a AIX partition to successfully connect to an iSeries server db2jccjar db2jcc_license_cisuzjar and db2jcc_license_cujar The iSeries license is contained in db2jcc_license_cisuzjar Note that this file is not a part of DB2 Client In other words a DB2 Connect license is required to use the driver in production environments The location of the JAR files needs to be added to the CLASSPATH environment variable For instance the following entry could be added to the AIX profile script

CLASSPATH=homedb2inst2sqllibjavadb2jccjarCLASSPATH=$CLASSPATHhomedb2inst2sqllibjavadb2jcc_license_cujarCLASSPATH=$CLASSPATHhomedb2inst2sqllibjavadb2jcc_license_cisuzjarexport CLASSPATH

Java Runtime 131 is a prerequisite

Additionally the developer should install the latest database group PTF (SF99503 for i5OS V5R3) on the iSeries server The Informational APAR ii13348 is keeping track of any fixes relevant to DRDA above and beyond the current database group PTF

Obtaining a Connection to DB2 UDB for iSeries When Type 4 connectivity is used the DB2 Universal Driver connects directly to the DB2 on iSeries through TCPIP Note that this is different from the legacy DB2 Type 2 JDBC driver that requires a DB2 node and remote database configurations on the client accessing iSeries The following code snippet illustrates how to use the DB2 JDBC Universal Driver to obtain a connection to DB2 UDB for iSeries

20

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

try ClassforName(comibmdb2jccDB2Driver) [1] catch(javalangClassNotFoundException e) Systemerrprint(ClassNotFoundException )Systemerrprintln(egetMessage())

try DriverManagergetConnection(jdbcdb2teraplex446TERAPLEX[2]

db2userdb2pwd) hellip catch(SQLException ex) Systemerrprintln(

SQLException + exgetMessage())

At [1] an instance of the DB2 JDBC Universal Driver is instantiated Then at [2] the driver is used to obtain a connection to the iSeries server Note the proper form of the database URL required by the driver

Considerations There are several advantages of DB2 JDBC Universal Driver bull Ease of cross-platform development mdash Consistent coding techniques and consistent error

codes and messages bull Ease of deployment mdash Pure Java (no runtime client required) and a single driver for accessing

DB2 on different platforms

The ease of use comes at a price though The iSeries JTOpen driver is optimized for accessing DB2 UDB for iSeries data and it uses native iSeries protocol to communicate with the back-end database server job This usually results in better performance and more-efficient system resources utilization For instance when using the DB2 JDBC Universal Driver to access an iSeries server the executeBatch method results in a single record insert There are also some restrictions when using DB2 Universal JDBC Driver with Type 4 connectivity

bull Support for distributed transactions (JTA) is not enabled bull Driver built-in connection pooling is not supported

Refer to Java application support in DB2 for more details on DB2 JDBC Universal Driver

21

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 Connect data access This section will explore the most important aspects of DB2 Connect ndash iSeries integration - including configuration tips and coding examples

DB2 Connect provides functionality for accessing data stored in DB2 UDB for iSeries as well as DB2 UDB for zOS and DB2 UDB for OS390reg DB2 Connect offers capabilities to access DB2 family members via several SQL interfaces gateway functions such as connection pooling and federated database functionality Many applications supporting the DB2 family of products leverage DB2 Connect as a key middleware component DB2 Connect is offered as separate AIX license products

Enterprise Edition Application Server Edition

In addition to DB2 Connect there are several other DB2 UDB Version 81 products that are supported on AIX

DB2 Universal Database Enterprise Server Edition DB2 Universal Database Workgroup Server Unlimited Edition DB2 Universal Database Workgroup Server Edition DB2 Universal Database Universal Developers Edition All Clients

The DB2 Connect Enterprise Edition functionality is also contained in DB2 Enterprise Server Edition for AIX

22

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 Connect in a nutshell In the scenario described in this paper the DB2 Connect functions contained in DB2 Enterprise Edition for AIX are utilized DB2 Connect Enterprise Edition provides support for both local and remote DB2 clients This is illustrated in Figure 11 Accessing DB2 UDB for iSeries with DB2 Connect

Figure 11 Accessing DB2 UDB for iSeries with DB2 Connect

DB2 Connect implements the Distributed Relational Database Architecturetrade (DRDAreg) to reduce the cost and complexity of accessing data stored in DB2 UDB for iSeries and other DRDA-compliant database servers DRDA defines the rules the protocols and the semantics for accessing distributed data Applications can access data in a distributed relational environment by using SQL statements In a distributed environment the system running the application and sending the SQL requests across the network is called the application requester (AR) A remote database server that executes SQL requests submitted by an application requester is known as the application server (AS) In the example shown in Figure 11 (above) DB2 Connect plays the role of an application requester while DB2 UDB for iSeries is an application server In this case DB2 Connect communicates with the iSeries database through TCPIP The iSeries DRDA application server implementation is based on multiple connection-oriented server jobs running in the QSYSWRK subsystem A DRDA listener job (QRWTLSTN) listens for TCP connect requests on port 446 Once an application requester connects to the listener job the listener wakes up one of the QRWTSRVR prestart jobs and assigns it to a given client connection Any further communication occurs directly between the client application and the QRWTSRVR job

DB2 Connect supports a wide range of programming interfaces that can be used by AIX applications to access the iSeries database Embedded SQL frac34 Both static and dynamic SQL frac34 Various programming languages (Java CC++ Cobol Fortran REXX)

DB2 Call Level Interface (DB2 CLI) ODBC JDBC frac34 DB2 JDBC Type 2 Driver frac34 DB2 JDBC Type 4 Driver (Universal JDBC Driver)

23

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Note that DB2 Connect supports access to DB2 UDB for iSeries through DB2 JDBC Universal driver However for performance and ease of maintenance reasons IBM recommends that Java applications running in AIX use native iSeries Toolbox JDBC driver See the JDBC Data Access section of this paper (above) for more details On the other hand DB2 Connect is a very efficient and robust connectivity option for AIX applications especially in the environments that are not directly supported by the native iSeries JDBC driver Here are several possible scenarios that would require DB2 Connect installed in a AIX partition

Embedded SQL interface is used to access DB2 CLI or ODBC interface is used to access DB2 A single SQL interface is needed to access multiple back end DB2 server Specific DB2 Connect functionality is needed such as distributed join or connection

pooling

Prerequisites One of the DB2 Connect products or DB2 Enterprise Server Edition for AIX V81 is needed Additionally DB2 Application Development Client is required in the AIX partition to compile DB2 applications

For maximum database server stability the developer should install the latest database group PTF (SF99503 for i5OS V5R3) on the iSeries server The Informational APAR ii13348 is keeping track of any fixes relevant to DRDA above and beyond the current database group PTF

DB2 Connect configuration The following example employs i5OS V5R3 and DB2 UDB Enterprise Server Edition for AIX Version 81 FixPak 6

Configuration steps in the iSeries partition The following process lists the necessary steps to be performed on the iSeries server 1) Verify that the TCPIP stack is working correctly It is assumed that the Virtual LAN is used to

communicate with the i5OS partition First obtain the IP address of the iSeries server or its hostname and ping the iSeries server from the AIX partition

2) Create a relational database (RDB) entry for the iSeries database in the i5OS partition If this has already been created it can be displayed by using the DSPRDBDIRE command Make sure that the RDB entry with a location of LOCAL exists on the iSeries server If it does not exist use the ADDRDBDIRE command to add the appropriate RDB entry For example the following command would add an RDB entry named TPLX For simplicity it is recommended that the TCPIP host name and RDB entry remain the same

ADDRDBDIRE RDB(TPLX) RMTLOCNAME(LOCAL)

3) Create a collection called NULLID This is necessary because the utilities shipped with DB2 Connect and DB2 UDB for AIX store their packages in the NULLID collection Since it does not exist by default in the iSeries server you must create it using the following command

CRTLIB LIB(NULLID)

4) Products that support DRDA automatically perform any necessary code page conversions at the receiving system For this to happen both systems need a translation table from their code page to the partner code page The default Coded Character Set Identifier (CCSID) on the iSeries server is 65535 Since DB2 Connect does not have a translation table for this code page the developer needs to change the individual user profiles to contain a CCSID that can be converted properly by DB2 Connect For US English this is 037 For other languages see DB2 Connect Personal Edition Quick Beginning GC09-2967 The following command changes the CCSID for an individual user profile to 037

24

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

CHGUSRPRF userid CCSID(037)

5) Verify that the default port 446 for DRDA service is being used To do this go to the Configure TCPIP menu (CFGTCP) select Configure Related Tables and then select Work with service table entries Verify that the DRDA service is set for port 446

6) The Distributed Data Management (DDM) job must be started for DRDA to work If you want the DDM job to be automatically started whenever TCPIP is started change the attributes of the DDM job using the CHGDDMTCPA command and set the Autostart server parameter to YES

7) If the system administrator chooses not to autostart the server issue the following command to start the DDM server job

STRTCPSVR SERVER(DDM)

8) Make sure that the user profiles that will be used to connect to the iSeries server exist on the server

25

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Configuration steps in the AIX partition The following steps are required for DB2 Connect to be configured in the AIX partition 1) Sign on to the AIX partition as the DB2 administrator 2) Launch Client Configuration Assistant (db2ca from the command prompt) It is assumed that

VNC or an X-Windows server are being used on the workstation so that the db2ca GUI can be properly rendered

3) From the Selected pull-down menu select the Add Database using Wizard option The Select how you want to setup a connection dialog appears Select Manually configure a connection to a database and click Next This is shown in Figure 12

Figure 12 Accessing DB2 UDB for iSeries with DB2 Connect

26

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

4) On the Select a communications protocol choose TCPIP and select The database physical resides on a host or OS400 system Then select the option Connect directly to the server as shown in Figure 13 Click Next

Figure 13 mdash Selecting communications protocol

27

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

5) On the TCPIP tab fill in the host name of the iSeries server The port number should be 446 This is shown in Figure 14 Click Next

Figure 14 mdash Specifying TCPIP communication parameters

28

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

6) On the Database tab fill in the Relational Database name Use the RDB entry name (specified in step 2) in the Configuration steps in the iSeries partition section as shown in Figure 15 Click Next

Figure 15 mdash Specifying the remote database

7) If you plan to use the ODBC applications select Register this database for ODBC as a system data source on the ODBC tab Click Next

29

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

8) On the Specify the node option dialog select OS400 from the Operating System pull-down menu This is shown in Figure 16 Click Finish

Figure 16 mdash Specifying the node options

30

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

9) The Test Connection dialog appears This allows the developer to verify that the connection works Select both CLI and JDBC check boxes You are also prompted for an iSeries user ID and password as shown in Figure 17

Figure 17 mdash Testing the connection

31

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

10) The successful connection to the database server is confirmed by the message box shown in Figure 18

Figure 18 mdash Test Connection results 11) At this time a newly configured database connection should appear in the main DB2

Configuration Assistant window It is recommended that the DB2 utilities are also bound to the iSeries database The bind process creates the necessary SQL packages on the remote database In the main Configuration Assistant window click the TPLX database entry and then select Selected-gtBindhellip

32

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

12) The Bind dialog appears Click Select All and then enter the connection information as shown in Figure 19 Click Bind The Results message box appears This allows the developer to monitor the progress of the binding process Watch for any error and warning messages

Figure 19 mdash Binding the DB2 utilities This concludes the DB2 Connect configuration steps

33

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Accessing DB2 UDB for iSeries from C embedded SQL

As mentioned earlier DB2 Connect allows developers to compile and run embedded SQL applications that access DB2 UDB for iSeries data This section covers implementation details for a C embedded SQL application called cursorsjsqc (see Appendix B for source code)

Prerequisites An embedded SQL application running in an AIX partition will use DB2 Connect services to access DB2 UDB for iSeries therefore the developer needs to make sure that all components listed in section Prerequisites on page 24 are installed The developer also needs to create a remote database connection as described in the DB2 Connect configuration section of this paper on page 24

Static SQL and SQL packages To successfully run against a DB2 UDB for iSeries database an embedded SQL application needs to be first precompiled and bound to the back-end database This process creates an SQL package on the target iSeries server The SQL package contains the access plan information for the SQL statements executed by the application The internal structure of the package as well as the method how its content is used by the SQL runtime to facilitate the access plan reuse is similar to the Extended Dynamic SQL support covered in detail in the Extended Dynamic SQL and Statement Caching section of this paper (on page 9) There are however important differences between the packages created by the extended dynamic SQL support and the packages created for embedded SQL DRDA client applications The extended dynamic SQL packages support dynamic SQL interfaces such as JDBC

that can submit ad hoc SQL statements at the run time The SQL runtime can prepare the dynamic statements and add them to the package On the other hand the DRDA packages are created at the precompile time and contain static SQL In order to add new statements to the package the application needs to be precompiled and rebound again

The extended dynamic SQL package can dynamically grow up to 500MB by allocating new space as required The DRDA packages since they are created at the precompile time have a fix size and do not grow over their life time

Simple embedded SQL application The application is based on a source code provided in the DB2 UDB samples directory typically to be found at homedb2inst1sqllibsamples The cursorsjsqc performs a join between STAFF and ORG tables located in DB2USER schema (library) on the TPLX database server (the source is provided at the end of this paper in Appendix B) The join statement retrieves the DEPTNAME column from ORG NAME column from STAFF and calculates the total compensation for an employee by adding SALARY and COMM columns in STAFF The results are sorted by department name and total compensation Here is the SELECT statement used by the application

SELECT deptname name salary + IFNULL(comm0) as compensationFROM org o staff sWHERE odeptnumb = sdeptORDER BY deptname compensation DESC

The application iterates through the selected records and prints out the data to the standard output device The sample DB2USER schema was created with the following SQL statements

db2 CONNECT TO tplx USER db2user USING mypassworddb2 CALL QSYSCREATE_SQL_SAMPLE(DB2USER)

34

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Make sure that the AIX partition is logged into with the DB2 admin user profile If the defaults were selected at the DB2 installation time this profile name is db2inst1 It is also assumed that DB2USER user exists on the iSeries server and that it has appropriate authority

There are several steps that are required to create an executable for the cursorsjsqc source code First the DB2 PRECOMPILE utility needs to be called The utility creates a bind file that is used to bind the required SQL package to the TPLX database It also converts embedded SQL statements into DB2 run-time API calls and produces a pure C source file that can be processed by an AIX C compiler

db2 CONNECT TO tplx USER db2user USING mypassworddb2 prep cursorsjsqc bindfile

Note that the connect statement is required only if the developer is not already connected to the database on an iSeries server Watch for any error or warning messages returned by the DB2 prep utility The prepare step should produce cursorsjbnd and cursorsjc files in the current directory Now the developer can invoke the bind utility to prepare the statements contained in the bind file and create the package on the target iSeries database server

db2 bind cursorsjbnd

It is assumed that Visual C++ 60 is installed and configured in the AIX partition Refer to the ldquoDeveloping and Porting C and C++ Applications on AIXrdquo redbook for more information on how to use the Visual C++ compiler httpibmcomredbooksabstractssg245674htmlOpen

Use the following commands to compile the C source generated by the precompile utility

xlc -I$INSTHOMEsqllibinclude ndashc cursorsjcxlc ndasho cursorsj cursorsjo -L$INSTHOMEsqlliblib ndashldb2

Run the program from the AIX prompt

cursorsj db2user mypassword

Distributed Join DB2 UDB Version 8 provides core federated server functionality A federated system consists of a DB2 UDB instance that operates as a federated server a database that acts as the federated database one or more data sources and clients (users and applications) that access the database and data sources Federated server permits objects stored in multiple databases to be accessed together in the same query For example a query can refer to a table that resides in DB2 UDB for iSeries and join it to a table stored in DB2 UDB for AIX Such a query would constitute so called distributed join The support for DB2 UDB for iSeries as a federated data source is provided by core federated server functionality directly implemented in DB2 UDB Enterprise Server Edition and DB2 UDB Connect Enterprise Edition All other DB2 UDB family members are also supported directly by core DB2 UDB federated server An additional software product DB2 Information Integratortrade is required to access non-DB2 UDB databases such as Oracle Sybase or Microsoftreg SQL Server Consult the following white papers for a detailed discussion on DB2 federated server support Heterogeneous data access for iSeries applications Version 2 httpibmcomserversenablesiteeducationiborecordhtmlhetdata Fundamentals of IBM DB2 Federated Server and Relational Connect httpwww7bsoftwareibmcomdmddlibrarytecharticle0206purnell0206purnellhtml

35

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Distributed Join Example In this section the steps that are required to configure DB2 UDB for iSeries as a federated data source will be illustrated Then the cursorsjsqc program will be ldquotweakedrdquo so that it executes a distributed join query that accesses data stored on an iSeries server and in the local DB2 UDB for AIX database It is assumed that the developer is familiar with the DB2 federated server concepts

Note Run the following commands from the Command Line Processor prompt Load the utility by executing the db2 command at the AIX prompt 1) First the local DB2 UDB for AIX instance needs to be enabled as a DB2 federated server

This is done by setting the database manager configuration parameter FEDERATED to YES

db2=gt update dbm cfg using FEDERATED YES

The database instance needs to be restarted for the change to take effect

NOTE A federated database is a regular database in a DB2 UDB instance that has the FEDERATED parameter enabled Therefore in this example the SAMPLE database that was created earlier is used as the federated database A new database can also be created using the CREATE DATABASE command

2) Connect to the federated database

db2=gt connect to sample

3) Use the CREATE WRAPPER statement to register a wrapper for the iSeries data source Wrappers are library routines that are used by the federated server to perform operations such as connecting to a data source and retrieving data from it The default wrapper name for DB2 UDB for iSeries is DRDA Here is the command to register the DRDA wrapper

db2=gt create wrapper drda

4) Use the CREATE SERVER statement to register a data source as a server within the federated database The server definition specifies the type and version of the data source and the wrapper used for communications with this data source For the DB2 UDB for iSeries data source the node and the database names are also needed The node and database name parameters have been configured for our TPLX database in the Configuration steps in the AIX partition section (on page 24) Use the following DB2 UDB command to lookup these parameter on the federated server

db2=gt list database directory

In this case the command produced the following output

Database alias = TPLX Database name = DCSE99E1 Node name = NDE9BF76 Database release level = a00 Comment = Directory entry type = Remote Authentication = SERVER Catalog database partition number = -1

36

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Note that the node name is set to NDE9BF76 The name was generated by the Configuration Administrator utility (db2ca)

Here is the command to register the TPLX database as a federated server

db2=gt create server tplx type db2400 version 530 wrapperdrda authorization db2user password mypassword options(nodeNDE9BF76 dbname TPLX)

The command is quite complex so make sure that the syntax is correct

5) Define the user mappings that instructs the federated server what user ID and password should be used when connecting to the iSeries data source

db2=gt create user mapping for user server tplxoptions(remote_authid db2user remote_password mypassword)

Specify the nickname for the iSeries table or view A nickname is an identifier that is used by the federated server to reference an object located at the data source The following command creates a nickname for the STAFF table located in the DB2USER schema on the TPLX database

db2=gt create nickname tplx_staff for tplxdb2userstaff

6) Test the distributed join query

db2=gt SELECT deptname name salary + COALESCE(comm0) ascompensation FROM org o tplx_staff s WHERE odeptnumb =sdept ORDER BY deptname compensation DESC

Note that the native iSeries function IFNULL has been substituted with an equivalent DB2 UDB function COALESCE COALESCE is also supported on iSeries servers For better portability IBM encourages the use of COALESCE rather than IFNULL Note also that the query runs on the federated server rather than on TPLX It accesses the ORG table in the local DB2 UDB for AIX SAMPLE database and the STAFF table that resides in TPLX The federated server performs the necessary distributed join

7) Modify the cursorsjsqc so that it executes a distributed join There are two source code modifications - Change the CONNECT TO statements Now the application needs to connect to the

federated database SAMPLE rather than to TPLX

EXEC SQL CONNECT TO SAMPLEEXEC SQL CONNECT TO SAMPLE USER userid USING passwd

- Modify the select statement so that it performs a distributed join Use the statement (shown in step 6) above Save the new source version as cursordjsqc

- Prepare bind and compile the distributed join version of the program as described in the Simple C embedded SQL application section (on page 34)

db2 prep cursordjsqc bindfiledb2 bind cursordjbndxlc -I$INSTHOMEsqllibinclude ndashc cursordjcxlc ndasho cursordj cursordjo -L$INSTHOMEsqlliblib ndashldb2

37

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

- Run the program from the AIX prompt

cursordj

Connection Pooling and Connection ConcentratorA modern Web-based application typically executes a large number of short-lived transactions Executing a transaction in this environment means establishing a database connection executing a few SQL statements and terminating this connection Creating connections to the database server is a very costly process To reduce the unnecessary workload DB2 Connect implements connection pooling and connection concentrator Connection pooling mechanism allows DB2 Connect to reuse an existing connection infrastructure for subsequent connection requests The connection concentrator is an advanced technology that allows DB2 Connect to serve a potentially very large number of clients with a limited number of database connections This is accomplished by decoupling clients from a particular database connection

Note that currently neither connection pooling nor connection concentrator support DB2 UDB for iSeries Therefore for performance reasons the author strongly recommends that the application server that obtains and drops connections very frequently implements its own database connection pooling mechanism that would assign an existing pooled database connection to a new AIX process or thread

TroubleshootingTroubleshooting a multi-tier application may be a bit tricky because the developer needs to deal with software components that reside in separate partitions The authorrsquos experience shows that two tools are particularly useful for pinning down the potential problem areas The joblog messages for a database server job usually provide enough details to isolate DB2

UDB for iSeries runtime issues The DRDA trace utility provides granular information about the data flow between the AIX

application and the iSeries server job

38

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Job Log MessagesAs mentioned earlier a DB2 client communicates with a corresponding iSeries server job This server job runs the SQL requests on behalf of the client More precisely when a DB2 client submits an SQL statement the statement is passed to a server job that in turn calls the DB2 runtime to execute the statement The results are then reformatted and marshaled to the client The iSeries DRDA server jobs are called QRWTSRVR and they run in the QUSRWRK subsystem At any given time there may be a large number of DRDA server jobs active on the system so the first step is to identify the job that serves the particular client connection The easiest method to accomplish this task is to run the following CL command from the i5OS prompt

WRKOBJLCK OBJ(DB2USER) OBJTYPE(USRPRF)

Here DB2USER is the user profile that is used to connect to the iSeries server Note that a QRWTSRVR job is assigned to a client after the connection has been established so the developer needs to set a breakpoint in the client application below the CONNECT TO statement

Once the Work with Object Locks appears key in 5 (Work with Job) next to the only QRWTSRVR job that should be listed This shows the Work with Job dialog Select option 10 to display the job log for the database server job Now the developer can search the job log for any error messages generated by the DB2 runtime

Sometimes it is also useful to include debug messages in the job log The debug messages are informational messages written to the job log about the implementation of a query They describe query implementation methods such as use of indexes join order ODP implementation (reusable versus non-reusable) and so on The easiest way to instruct the iSeries server to include the debug messages is to call the following stored procedure just after the connection to the iSeries server is established

EXEC SQL call qsysqcmdexc(STRDBGUPDPROD(YES)000000002000000)

A sample of the job log messages with debug messages enabled is shown below in Figure 20

Arrival sequence access was used for file STAFFAccess path suggestion for file STAFFQuery options used to build the OS400 query access plan Ending debug message for query ODP created Blocking used for queryCursor SQLCUR201 opened1 rows fetched from cursor SQLCUR201Row not found for SQLCUR201ODP deleted Cursor SQLCUR201 closedDESCRIBE of prepared statement STMT0201 completed

Figure 20 mdash Joblog with debug messages enabled

So the job log offers fairly detailed information on how the AIX client requests were implemented by the DB2 runtime

39

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 DRDA trace utilityThe DB2 DRDA trace utility (db2drdat) provides detailed information about the data streams exchanged between DB2 Connect and target database server The output file produced by the utility contains send and receive communications buffers TCPIP error messages and SQL Communications Area (SQLCA) information Please refer to lsquoDB2 Connect Userrsquos Guidersquo manual for in-depth discussion of the DRDA trace utility

Accessing DB2 UDB for iSeries from CLI DB2 Call Level Interface (CLI ) is based on the Microsoft Open Database Connectivity (ODBC) specification and the ISO CLI standard The DB2 CLI interface gained popularity among DB2 application providers because the developer can build an ODBC application by simply linking the application with libdb2 library on a UNIX server In other words the developer directly utilizes the DB2 ODBC driver services without a need for an ODBC driver manager Additionally in contrast to embedded SQL the developer does not need to precompile or bind DB2 CLI applications because they use packages provided with DB2 UDB The developer simply compiles and links the application

Prerequisites A DB2 CLI application running in an AIX partition will use DB2 Connect services to access DB2 UDB for iSeries therefore make sure that all components listed in Prerequisites section of this paper on page 24 are installed The developer also needs to create a remote database connection as described in the DB2 Connect configuration section of this paper on page 24

Dynamic SQL and Access Plan Caching A DB2 CLI client application uses the dynamic SQL interface and does not have the capability to utilize the extended dynamic SQL support Therefore it runs lsquopurersquo dynamic SQL statements That does not mean however that the process of parsing validating and optimizing will be repeated for every execution of a given dynamic SQL statement

The DB2 UDB for iSeries database implements an internal object called System-Wide SQL Statement Cache (SWSC) The SWSC can improve the performance of programs using dynamic SQL statements by caching the access plans in a system-wide cache When a dynamic SQL statement is submitted the SQL runtime searches the SWSC to see if this statement has been previously executed If so then DB2 retrieves and reuses the key information associated with the cached statement and thereby the processing time and the resources utilization can be significantly reduced

Simple DB2 CLI C++ ApplicationThis section covers DB2 CLI implementation details for a sample C++ program called testclicpp (the source is provided at the end of this paper in Appendix C) To compile the source with Visual C++ complier use the following command in the AIX partition

xlC ndashI$INSTHOMEsqllibinclude ndashc testclicppxlC ndasho testcli testclio ndashL$INSTHOMEsqlliblib ndashldb2

The application performs a join between STAFF and ORG tables located in DB2USER schema (library) The join statement retrieves the DEPTNAME column from ORG NAME and JOB columns from STAFF and calculates the total compensation for an employee by adding SALARY and COMM columns in STAFF The results are sorted by total compensation The selection criterion is based on the current value of the department name parameter Here is the SELECT statement used by testcli

40

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

select name job salary + coalesce(comm0) as compensationfrom org o staff swhere odeptnumb = sdeptand deptname = order by compensation desc

Figure 21 shows the software components involved in the execution of this sample application

Figure 21 How a DB2 CLI client accesses DB2 UDB on an iSeries server

Although the testcli application is fairly simple it covers some important aspects of efficient CLI programming for DB2 UDB for iSeries

Reusable Open Data Paths (ODPs)An Open Data Path (ODP) definition is an internal i5OS object that is created when certain SQL statements (such as OPEN INSERT UPDATE and DELETE) are executed for the first time in a given job (or connection) The ODP can be thought of as a runtime implementation of an access plan The access plan created at the optimization time provides a recipe or in other words a sequence of steps necessary to execute the statement The ODP on the other hand provides the executable code for all requested IO operations The process of creating new ODP objects is fairly CPU- and IO-intensive so whenever possible the iSeries DB2 runtime tries to reuse existing ODPs For instance a SQLCloseCursor() API call may close the SQL cursor but leave the ODP available to be used the next time the cursor is opened This can significantly reduce the processing and response time in running SQL statements A reusable OPD usually requires 10 to 20 times less CPU resources than a newly created ODP Therefore it is important that the applications employ programming techniques that allow the DB2 runtime to reuse ODPs

With dynamic interfaces such as CLI full opens are avoided by using a prepare once execute many programming paradigm It means that when an SQL statement is going to be executed more than once you should prepare the statement just once and then reuse the prepared

41

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

statements for consecutive executions Although DB2 UDB does try to convert literals to parameter markers so that similar statements can be reused it is a better programming practice to explicitly implement parameter markers That way the chances for reusable ODPs are quite significantly improved The code snippet in Figure 22 illustrates how to implement the prepare once execute many programming technique

Define A SELECT SQL Statementstrcpy((char ) SQLStmt select name job salary + ifnull(comm0) ascompensation )ptr = strcat( (char ) SQLStmt from org o staff s )ptr = strcat( (char ) SQLStmt where odeptnumb = sdept)ptr = strcat( (char ) SQLStmt and deptname = )ptr = strcat( (char ) SQLStmt order by compensation desc) [1]

Prepare The SQL Statementrc = SQLPrepare(ExampleStmtHandle SQLStmt SQL_NTS) [2]

Bind The Columns In The Result Data Set Returned To Application Variablesrc = SQLBindCol(ExampleStmtHandle 1 SQL_C_CHAR (SQLPOINTER)

ExampleName sizeof(ExampleName) NULL)rc = SQLBindCol(ExampleStmtHandle 2 SQL_C_CHAR (SQLPOINTER)

ExampleJob sizeof(ExampleJob) NULL)rc = SQLBindCol(ExampleStmtHandle 3 SQL_C_DOUBLE (SQLPOINTER)

ampExampleComp sizeof(ExampleComp) NULL)

for (int i = 0 i lt LOOPS i++)rc=SQLBindParameter(ExampleStmtHandle

1SQL_PARAM_INPUTSQL_C_CHARSQL_CHAR10(SQLPOINTER) currentDepartment[i8]0NULL) [3]

rc = SQLExecute(ExampleStmtHandle) [4]cout ltlt endl ltlt Current Dept ltlt currentDepartment[i8] ltlt endl Display The Results Of The SQL QueryExampleShowResults()

Figure 22 Use the prepare once execute many programming technique

The error-handling code has been removed for clarity At [1] the statement text is assigned to a variable Note that a parameter marker is used in the WHERE clause The statement is then prepared just once at [2] The current value of the parameter is bound to the prepared statement at [3] The prepared statement is executed at [4] Steps [3] and [4] are repeatedly executed in a for loop

Techniques to Further Improve DB2 CLI Performance Thus far this paper has discussed the techniques used by a sample application to tune the CLI performance However depending on the application architecture other methods of improving CLI performance may be considered

Connection PoolingCurrently the CLI application connecting through DB2 Connect to DB2 UDB for iSeries does not take advantage of the connection pooling mechanism implemented by DB2 Connect Therefore for performance reasons the author strongly recommends that the application server that obtains and drops connections very frequently implements its own database connection pooling mechanism that would assign an existing pooled database connection to a new AIX process or thread

42

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Blocking

For queries which result in returning large data blocks from the iSeries server (usually 32K of data and above) ensure that the database manager configuration parameter RQRIOBLK is set to 32767 This can be done using the Command Line Processor (CLP) as follows

db2 update database manager configuration using RQRIOBLK 32767

TroubleshootingThe experience of the author shows that two tools are particularly useful for pinning down the potential problem areas bull Joblog messages for a database server job usually provides enough details to isolate DB2

runtime issues bull CLI trace utility provides granular information about the data flow between the AIX application

and the database server job

Job Log MessagesThe process of finding and analyzing the job log for a DB2 CLI connection is identical to the process outlined for an embedded SQL application in the Job Log Message section of this paper on page 39

CLI Trace The DB2 CLIODBCJDBC trace utility provides very detailed information about the data streams exchanged between DB2 Connect and target database server Refer to the DB2 Information Center for more information on how to set up and analyze the CLI traces httppublibboulderibmcominfocenterdb2v8luwindexjsptopic=comibmdb2udbdocadc000 7959htm

43

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Trademarks

IBM eServer iSeries AIX AIX 5L i5OS WebSphere DB2 DB2 Universal Database DB2 Connect OS400 zOS OS390 Distributed Relational Database Architecture DRDA and DB2 Information Integration are trademarks or registered trademarks of International Business Machines Corporation in the United States and other countries

Java and all Java-based trademarks are trademarks of Sun Microsystems Inc in the United States other countries or both

Linux is a registered trademark of Linus Torvalds in the United States other countries or both

UNIX is a registered trademark of The Open Group in the United States and other countries

Microsoft and Windows are registered trademarks of Microsoft Corporation in the United States andor other countries

All other registered trademarks and trademarks are properties of their respective owners

IBM makes no commitment to make available any products referred to herein

References in this publication to IBM products or services do not imply that IBM intends to make them available in every country in which IBM operates

Additional Information ITSO offers a Redbook that can be helpful to those who want to learn more about i5OS AIX integration

bull AIX Integration with I5OS on the IBM eServer iSeries Server (SG24-6551)

Jarek Miszczyk is the Senior Software Engineer IBM eServer Solutions Enablement IBM Rochester

[Portions of this white paper reprinted with permission from MC Mag Online published by MC Press LLP httpwwwmcpressonlinecom]

Acknowledgments The author would like to thank the following people for their advice contributions and support on this paper

Bob Bittner IBM Rochester Jon Rush IBM Rochester Prasad Vallurupalli IBM Rochester Neil Willis IBM Rochester

44

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix A Source Listing of TestJDBCjava

package comibmiseriespwdimport javasqlimport javaxnamingimport javautilHashtableimport javautilimport javaxsqlimport comibmas400access

public class TestJDBC public static void main(javalangString[] args)

throws Exception

int numOfLoops = 5000int outerNumOfLoops = 5boolean firstExec = trueConnection conStatement sPreparedStatement psPreparedStatement pstmtdelCallableStatement cstmPreparedStatement pstmtHashtable env = new Hashtable()

envput(ContextINITIAL_CONTEXT_FACTORYcomsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env)Systemoutprintln(Deploying connection pooling data source)deployDataSource() Do the work with connection pooling onlyAS400JDBCConnectionPoolDataSource tkcpds =

(AS400JDBCConnectionPoolDataSource)ctxlookup(jdbcToolkitDataSource) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPool pool = new AS400JDBCConnectionPool(tkcpds) Adds 1 connection to the pool that can be used by theapplication (creates the physical database connections based onthe data source)poolfill(1)Systemoutprintln(nStart timing Toolkit connection pooling)long startTime = SystemcurrentTimeMillis()

for (int i = 0 i lt outerNumOfLoops i++) con = poolgetConnection()consetAutoCommit(false) deleteif ( i == 0)

long startDelete = SystemcurrentTimeMillis()cstm = cstm = conprepareCall(

CALL qsysqcmdexc(CLRPFM FILE(DB2USERCOFFEES) + 000000002800000))

cstmexecuteUpdate()cstmclose()long endDelete = SystemcurrentTimeMillis()Systemoutprintln(Delete all records +

(endDelete - startDelete) + ms elapsed)

45

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

String sqlinstrlong startInsert = SystemcurrentTimeMillis() insert

pstmt =conprepareStatement(INSERT INTO COFFEES VALUES( ))for (int j = 0 j lt numOfLoops j++) pstmtsetString(1 Kona_ + IntegertoString(i))pstmtsetInt(2 150)pstmtsetFloat(3 999f)pstmtsetInt(4 0)pstmtsetInt(5 0)pstmtaddBatch()int [] updateCounts = pstmtexecuteBatch()concommit()pstmtclose()long endInsert = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for + numOfLoops + inserts

+ (endInsert - startInsert)) selectlong startSelect = SystemcurrentTimeMillis()ps = conprepareStatement(SELECT FROM COFFEES)ResultSet rs = psexecuteQuery()rsnext()rsclose()concommit()psclose()long endSelect = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for select +

(endSelect - startSelect))consetAutoCommit(true)conclose()long endTime = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for + outerNumOfLoops +

loops + (endTime - startTime))Systemexit(0)

private static void deployDataSource()throws ExceptionString serverName = teraplex String databaseName = TERAPLEX String userName = db2user String password = db2pwd

Establish a JNDI context and bind the connection pool data sourceHashtable env = new Hashtable()envput(ContextINITIAL_CONTEXT_FACTORY

comsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPoolDataSource tkcpds = new

AS400JDBCConnectionPoolDataSource()tkcpdssetServerName(serverName) tkcpdssetDatabaseName(databaseName) tkcpdssetUser(userName) tkcpdssetPassword(password) tkcpdssetDescription(Toolkit Connection Pooling DataSource)tkcpdssetSavePasswordWhenSerialized(true)tkcpdssetExtendedDynamic(true)

46

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

tkcpdssetPackage(JDBCDS)tkcpdssetPackageCache(true)tkcpdssetPackageCriteria(select)enable the following properties as requiredcpdssetTrace(true)tkcpdssetServerTraceCategories( AS400JDBCDataSourceSERVER_TRACE_DEBUG_SERVER_JOB)

ctxrebind(jdbcToolkitDataSource tkcpds)

47

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix B mdash Source Listing of cursorsjsqc

Source File Name = cursorsjsqc Licensed Materials - Property of IBM (C) COPYRIGHT International Business Machines Corp 1995 2000 2004 All Rights Reserved US Government Users Restricted Rights - Use duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp PURPOSE This sample program demonstrates the use of a CURSOR The CURSOR is processed using static SQL EXTERNAL DEPENDENCIES - Ensure existence of database for precompile purposes - Precompile with the SQL precompiler (PREP in DB2) - Bind to a database (BIND in DB2) - Compile and link with the IBM Cset++ compiler (AIX and OS2) or the Microsoft Visual C++ compiler (Windows) or the compiler supported on your platform For more information about these samples see the README file For more information on programming in C see the - Programming in C and C++ section of the Application Development Guide For more information on building C applications see the - Building C Applications section of the Application Building Guide For more information on the SQL language see the SQL Reference

include ltstdiohgt include ltstdlibhgt include ltstringhgtinclude ltsqlhgtinclude ltsqlenvhgtinclude ltsqldahgtinclude ltsqlcahgt

int SqlInfoPrint( char struct sqlca int char )void TransRollback( void)

define EMB_SQL_CHECK( MSG_STR ) rc = SqlInfoPrint( MSG_STR ampsqlca __LINE__ __FILE__) if ( rc = 0 ) TransRollback( )

return 1

EXEC SQL INCLUDE SQLCA

int main(int argc char argv[])

EXEC SQL BEGIN DECLARE SECTIONchar dname[15]

48

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

char pname[10]double compchar userid[9]char passwd[19]

EXEC SQL END DECLARE SECTION

int rc = 0printf( Sample C program CURSORSJ n )if (argc == 1)

EXEC SQL CONNECT TO TPLXEMB_SQL_CHECK(CONNECT TO TPLX)

else if (argc == 3)

strcpy (userid argv[1])strcpy (passwd argv[2])EXEC SQL CONNECT TO TPLX USER userid USING passwdEMB_SQL_CHECK(CONNECT TO TPLX)

else

printf (nUSAGE cursor [userid passwd]nn)return 1

endif

EXEC SQL DECLARE c1 CURSOR FORselect deptname name salary + ifnull(comm0) as compensationfrom org o staff swhere odeptnumb = sdeptorder by deptname compensation desc

EXEC SQL OPEN c1EMB_SQL_CHECK(OPEN CURSOR)

printf(DEPARTMENT NAME COMPENSn)printf(-----------------------------------n)do

EXEC SQL FETCH c1 INTO dname pname compif (SQLCODE = 0) breakprintf( -1515s -1010s 72fn dname pname comp )

while ( 1 )

EXEC SQL CLOSE c1EMB_SQL_CHECK(CLOSE CURSOR)

EXEC SQL CONNECT RESETEMB_SQL_CHECK(CONNECT RESET)

exit(0)

end of program CURSORSJSQC

int SqlInfoPrint( char appMsgstruct sqlca pSqlcaint linechar file )

int rc = 0char sqlInfo[1024]char sqlInfoToken[1024]char sqlstateMsg[1024]char errorMsg[1024]

if (pSqlca-gtsqlcode = 0 ampamp pSqlca-gtsqlcode = 100)

49

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

strcpy(sqlInfo )if( pSqlca-gtsqlcode lt 0) sprintf( sqlInfoToken n---- error report ----n)

strcat( sqlInfo sqlInfoToken)else sprintf( sqlInfoToken n---- warning report ----n)

strcat( sqlInfo sqlInfoToken) endif

sprintf( sqlInfoToken app message = sn appMsg)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken line = dn line)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken file = sn file)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken SQLCODE = ldn pSqlca-gtsqlcode)strcat( sqlInfo sqlInfoToken)

get error message rc = sqlaintp( errorMsg 1024 80 pSqlca) return code is the length of the errorMsg string if( rc gt 0) sprintf( sqlInfoToken sn errorMsg)

strcat( sqlInfo sqlInfoToken)

get SQLSTATE message rc = sqlogstt( sqlstateMsg 1024 80 pSqlca-gtsqlstate)if (rc == 0) sprintf( sqlInfoToken sn sqlstateMsg)

strcat( sqlInfo sqlInfoToken)

if( pSqlca-gtsqlcode lt 0) sprintf( sqlInfoToken --- end error report ---n)

strcat( sqlInfo sqlInfoToken)printf(s sqlInfo)return 1

else sprintf( sqlInfoToken --- end warning report ---n)

strcat( sqlInfo sqlInfoToken)printf(s sqlInfo)return 0

endif endif

return 0

void TransRollback( ) struct sqlca sqlca

int rc = 0 rollback the transaction printf( nRolling back the transaction n)

EXEC SQL ROLLBACKrc = SqlInfoPrint( ROLLBACK ampsqlca __LINE__ __FILE__)if( rc == 0) printf( The transaction was rolled backn)

50

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

51

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix C mdash Source Listing of testclicpp

Include The Appropriate Header Filesinclude ltsqlclihgtinclude ltsqlcli1hgtinclude ltsqlutilhgtinclude ltsqlenvhgtinclude ltstdiohgt include ltiostreamgt include ltlocalehgt include ltstringhgtdefine SQL_SQLSTATE_SIZE 5define LOOPS 8

using namespace std

Define The CLI_Class Classclass CLI_Class

Attributespublic

SQLHANDLE EnvHandleSQLHANDLE ConHandleSQLHANDLE StmtHandleSQLRETURN rcSQLCHAR Job[6]SQLCHAR Name[10]SQLDOUBLE Comp

Operationspublic

CLI_Class()~CLI_Class()SQLRETURN ShowResults()

Constructor Destructor

SQLRETURN printError( SQLHDBC SQLHSTMT)

Define The Class ConstructorCLI_ClassCLI_Class()

setlocale( LC_ALL )

Initialize The Return Code Variablerc = SQL_SUCCESS

Allocate An Environment Handlerc = SQLAllocHandle(SQL_HANDLE_ENV SQL_NULL_HANDLE ampEnvHandle)

Allocate A Connection Handleif (rc == SQL_SUCCESS)

rc = SQLAllocHandle(SQL_HANDLE_DBC EnvHandle ampConHandle)

Define The Class DestructorCLI_Class~CLI_Class()

Free The Connection Handleif (ConHandle = NULL)

SQLFreeHandle(SQL_HANDLE_DBC ConHandle)

Free The Environment Handle

52

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

if (EnvHandle = NULL)SQLFreeHandle(SQL_HANDLE_ENV EnvHandle)

Define The ShowResults() Member FunctionSQLRETURN CLI_ClassShowResults(void)

While There Are Records In The Result Data Set Generated Retrieve And Display Themcout ltlt Name Job Compensation ltlt endlcout ltlt --------- ------ ------------ ltlt endlcoutsetf(iosleft)coutprecision(2)coutsetf(iosfixed)while (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)

rc = SQLFetch(StmtHandle)if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)

coutwidth(15)cout ltlt Name

coutwidth(10)cout ltlt Job

coutwidth(7)cout ltlt Comp ltltendl

if(rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO ampamp rc = SQL_NO_DATA)printError(ConHandle StmtHandle)

else

rc = 0SQLCloseCursor(StmtHandle)

Return The ODBC API Return Code To The Calling Functionreturn(rc)

SQLRETURN CLI_ClassprintError (SQLHDBC hdbc

SQLHSTMT hstmt)

SQLCHAR buffer[SQL_MAX_MESSAGE_LENGTH + 1]SQLCHAR sqlstate[SQL_SQLSTATE_SIZE + 1]SQLINTEGER sqlcodeSQLSMALLINT lengthSQLRETURN rcwhile ((rc = SQLError(SQL_NULL_HENV hdbc hstmt

sqlstateampsqlcodebufferSQL_MAX_MESSAGE_LENGTH + 1amplength)) == SQL_SUCCESS || rc ==

SQL_SUCCESS_WITH_INFO)

cout ltlt SQLSTATE ltlt sqlstate ltlt endlcout ltlt SQLCODE ltlt sqlcode ltlt endlcout ltlt Error msg ltlt buffer ltlt endl

53

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

cout ltlt----------------------------- ltlt endl ltlt endl

return(SQL_ERROR)

----------------------------------------------------------------- The Main Function -----------------------------------------------------------------int main()

Declare The Local Memory Variables

(SQLCHAR ) db2user SQL_NTS (SQLCHAR ) test26t SQL_NTS)

SQLRETURNSQLCHARSQLCHARSQLCHARchar

SQLCHAR

rc = SQL_SUCCESSDBName[10] = TPLXSQLStmt[255]c[10]ptrcurrentDepartment[8][15] = Head Office

New England Mid Atlantic South Atlantic Great Lakes PlainsPacificMountain

Create An Instance Of The CLI_Class ClassCLI_Class Example

Connect To iSeries Database if (ExampleConHandle = NULL)

rc = SQLConnect(ExampleConHandle DBName SQL_NTS

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)ExampleprintError(ExampleConHandle SQL_NULL_HSTMT)

return(rc)

cout ltlt Successfully connected to ltlt DBName ltlt ltlt endlrc = SQLSetConnectAttr(ExampleConHandle SQL_ATTR_AUTOCOMMIT

(SQLPOINTER) SQL_AUTOCOMMIT_OFF SQL_IS_UINTEGER) Allocate An SQL Statement Handlerc = SQLAllocHandle(SQL_HANDLE_STMT ExampleConHandle

ampExampleStmtHandle)if (rc == SQL_SUCCESS)

Define A SELECT SQL Statement

strcpy((char ) SQLStmt select name job salary + ifnull(comm0) ascompensation )

ptr = strcat( (char ) SQLStmt from org o staff s )ptr = strcat( (char ) SQLStmt where odeptnumb = sdept)ptr = strcat( (char ) SQLStmt and deptname = )ptr = strcat( (char ) SQLStmt order by compensation desc)

Prepare The SQL Statementrc = SQLPrepare(ExampleStmtHandle SQLStmt SQL_NTS)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)ExampleprintError(ExampleConHandle ExampleStmtHandle)

54

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

return(rc)

Bind The Columns In The Result Data Set Returned To Application Variables

rc = SQLBindCol(ExampleStmtHandle 1 SQL_C_CHAR (SQLPOINTER)ExampleName sizeof(ExampleName) NULL)

rc = SQLBindCol(ExampleStmtHandle 2 SQL_C_CHAR (SQLPOINTER)ExampleJob sizeof(ExampleJob) NULL)

rc = SQLBindCol(ExampleStmtHandle 3 SQL_C_DOUBLE (SQLPOINTER)ampExampleComp sizeof(ExampleComp) NULL)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO) ExampleprintError(ExampleConHandle ExampleStmtHandle)

return(rc)

while (true)

for (int i = 0 i lt LOOPS i++)

rc=SQLBindParameter(ExampleStmtHandle1SQL_PARAM_INPUTSQL_C_CHARSQL_CHAR

150(SQLPOINTER) currentDepartment[i8]0NULL)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)

ExampleprintError(ExampleConHandle ExampleStmtHandle)return(rc)

rc = SQLExecute(ExampleStmtHandle)if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)

ExampleprintError(ExampleConHandle ExampleStmtHandle)return(rc)

cout ltlt endl ltlt Current Dept ltlt currentDepartment[i8] ltlt

endl Display The Results Of The SQL QueryExampleShowResults()if(rc = 0)break

if ( i500 == 0 ampamp i gt 0 )cout ltlt Loops ltlt i ltlt ltlt endl

cout ltlt AFTER ltlt LOOPS ltlt loops Press X to exit ltlt endlcin gtgt cif (c[0] == x || c[0] == X)

break

Free The SQL Statement Handleif (ExampleStmtHandle = NULL )

SQLFreeHandle(SQL_HANDLE_STMT ExampleStmtHandle) Disconnect From The Northwind Sample Databaserc = SQLDisconnect(ExampleConHandle)

Return To The Operating Systemreturn(rc)

55

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Tuning DB2 UDB for iSeries Access with IBM Toolbox for Java and JTOpen Driver This section covers JDBC implementation details for a sample Java program called TestJDBC (the source is provided at the end of this paper in Appendix A) The application uses the Java Naming and Directory Interface (JNDI) to obtain a database connection deletes 5000 records generates and inserts 5000 records and finally retrieves the newly inserted records from an SQL table called COFFEES The application executes in an AIX partition and accesses the DB2 UDB for iSeries through the JTOpen (or IBM Toolbox for Java) driver Figure 3 shows the software components involved in the execution of this simple application

Figure 3 JDBC client accessing DB2 UDB for iSeries

Apart from the JTOpen driver which can be downloaded from the IBM Toolbox for Java Web site you need three other JAR files to successfully compile and execute the JDBCTest application in a AIX partition

bull providerutiljar and fscontextjar mdashDownload a simple file system JNDI provider from Sun Microsystems JNDI Web site httpjavasuncomproductsjndidownloadsindexhtml

bull jdbc2_0-stdextjar mdash Copy the javaxsql package from the QIBMUserDataJava400ext IFS directory on the iSeries server

The location of the JAR files needs to be added to the CLASSPATH environment variable For instance the following entry could be added to the AIX profile script

6

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

CLASSPATH=homecodeJTOpenjt400jarCLASSPATH=$CLASSPATHhomecodefscontextproviderutiljarCLASSPATH=$CLASSPATHhomecodefscontextfscontextjarCLASSPATH=$CLASSPATHhomecodeJTOpenjdbc2_0-stdextjarexport CLASSPATH

To compile the source use the following command in the AIX partition

javac TestJDBCjava

Although the TestJDBC application is fairly simple it illustrates several important aspects of efficient JDBC programming for DB2 UDB for iSeries

Connection PoolingA JDBC connection can be obtained through either the DataSource or DriverManager object Either method involves significant overhead A fairly large amount of system resources is required to create and maintain the connection and then release it when it is no longer needed JTOpen allows a developer to establish a pool of database connections that can be shared by multiple client applications Connection pooling can improve the response time because the connection pool manager can locate and use an existing connection When the database request is completed the connection returns to the connection pool for reuse

In the JDBCTest sample JNDI was first used to register a connection pool-capable data source Heres an excerpt from the deployDataSource method of the sample application

Hashtable env = new Hashtable()envput(ContextINITIAL_CONTEXT_FACTORY

comsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env) [1]

Register an AS400JDBCConnectionPoolDataSource objectAS400JDBCConnectionPoolDataSource tkcpds = newAS400JDBCConnectionPoolDataSource() [2]tkcpdssetServerName(serverName) tkcpdssetDatabaseName(databaseName) tkcpdssetUser(userName) tkcpdssetPassword(password) tkcpdssetDescription(Toolkit Connection Pooling DataSourceobject) hellip ctxrebind(jdbcToolkitDataSource tkcpds) [3]

At [1] the initial JNDI context is created

Then at [2] an AS400JDBCConnectionPoolDataSource object is instantiated This is the JTOpen implementation of the javaxsqlConnectionPoolDataSource interface An AS400JDBCConnectionPoolDataSource object supports a number of methods that can be used to set iSeries-specific properties of the underlying DataSource object Some of these properties will be discussed in greater detail in the following sections of this paper

At [3] the data source object is bound to an arbitrary name that will be used in the main application Note that the deployDataSource method needs to be executed just once unless some of the data source properties need to be changed In that case the developer would need to rebind

7

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

The JNDI registered data source is then used in the main application to initialize the connection pool

AS400JDBCConnectionPoolDataSource tkcpds = [1](AS400JDBCConnectionPoolDataSource)ctxlookup(jdbcToolkitDataSource) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPool pool = newAS400JDBCConnectionPool(tkcpds)[2] Adds 1 connection to the pool that can be used by the application(creates the physical database connections based on the datasource)poolfill(1) [3] hellip con = poolgetConnection()[4]

At [1] the JNDI service is used to instantiate the AS400JDBCConnectionPoolDataSource

Then at [2] an AS400JDBCConnectionPool object is created This object is responsible for managing the connection pool

At [3] the connection pool is initialized with one connection

The pool object is used at [4] to obtain a database connection There are several additional things the developer should know about this code snippet

bull The advantage of using JNDI to register the data source object as opposed to just instantiating it in the main method is that in a more realistic scenario the data source would be registered just once at application deployment time Additionally the data source properties do not have to be hard-coded in the main method and can be changed at any time and then rebound without affecting the application

bull The AS400JDBCConnectionPool is a proprietary JTOpen implementation of a connection pool Specifically it does not implement the Referenceable interface and thus cannot be bound through JNDI services

bull The JTOpen AS400JDBCConnectionPoolDataSource does not support statement caching as described in the JDBC 30 specification Statement caching is implemented through SQL packages This feature is covered in the following section

Note The native iSeries JDBC driver supports both connection pooling and statement caching in a JDBC 30 compliant manner

8

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Extended Dynamic SQL and Statement Caching As mentioned the JTOpen data source object supports a number of properties that can be used to fine-tune the database performance In this section properties used to enable extended dynamic SQL support (see DB2 SQL Runtime Interfaces section above) and local statement caching will be discussed

Here is a relevant code excerpt from the deployDataSource method

AS400JDBCConnectionPoolDataSource tkcpds = new AS400JDBCConnectionPoolDataSource() hellip tkcpdssetExtendedDynamic(true)[1]tkcpdssetPackage(JDBCDS) [2]tkcpdssetPackageCache(true) [3]tkcpdssetPackageCriteria(select) [4]

At [1] the extended dynamic SQL support is enabled Note that the default is disabled for JTOpen The extended dynamic SQL functionality is often referred to as SQL package support The SQL packages are server-side repositories for SQL statements Packages contain the internal structures such as parse trees and access plans which are needed to execute SQL statements Because SQL packages are a shared resource the information built when a statement is prepared is available to all the users of the package This saves processing time especially in an environment where many users are using the same or similar statements Also because SQL packages are permanent this information is saved across job initiationtermination and IPLs In fact SQL packages can be saved and restored on other servers

At [2] the SQL package is named Note that the actual package name on the iSeries server is JDBCDSBAA The package name is generated by taking the name specified on the client and appending three letters that are an encoded set of the package configuration attributes By default an SQL package does not contain unparameterized select statements This behavior is overridden at [4] by setting the PackageCriteria property to select

At [3] the local statement cache is enabled A copy of the SQL package is cached on the AIX client This may improve application performance in a way similar to JDBC 30 statement caching Note however that local statement caching is not recommended for large SQL packages The copy of an SQL package is cached when the database connection is obtained This may cause increased network traffic as well as slow down the connection setup time

Reusable Open Data Paths (ODPs)An Open Data Path (ODP) definition is an internal i5OS object that is created when certain SQL statements (such as OPEN INSERT UPDATE and DELETE) are executed for the first time in a given job (or connection) The ODP can be thought of as a runtime implementation of an access plan The access plan created at the optimization time provides a recipe or in other words a sequence of steps necessary to execute the statement The ODP on the other hand provides the executable code for all requested IO operations The process of creating new ODP objects is fairly CPU- and IO-intensive so whenever possible the iSeries DB2 runtime tries to reuse existing ODPs For instance a ResultSetclose() call may close the SQL cursor but leave the ODP available to be used the next time the cursor is opened This can significantly reduce the response time in running SQL statements A reusable OPD usually requires 10 to 20 times less CPU resources than a newly created ODP Therefore it is important that the applications employ programming techniques that allow the DB2 runtime to reuse ODPs

With dynamic programming interfaces such as JDBC the most efficient way to avoid full opens is to employ the so-called prepare once execute many programming paradigm Ideally an SQL statement that is executed more than once should be prepared just once mdashfor example in the class constructor mdash and then reused for the consecutive executions At the prepare time the

9

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 engine stores the prepared statement along with the associated statement name in the QZDASOINIT jobs statement cache On the first execution the ODP created for a given statement is associated with the appropriate entry in the statement cache On consecutive executions the prepared statement and the corresponding ODP can be quickly located in the statement cache and reused The code snippet below illustrates the prepare once execute many programming technique

PreparedStatement pstmt = conprepareStatement(INSERT INTO COFFEES VALUES( ))[1] hellip for (int i = 0 i lt outerNumOfLoops i++)

insertfor (int j = 0 j lt numOfLoops j++)

pstmtsetString(1 Lavaza_ + IntegertoString(j)) hellip pstmtaddBatch()

int [] updateCounts = pstmtexecuteBatch()[2]concommit()

At [1] a PreparedStatement pstmt object is instantiated for a parameterized INSERT statement The statement is prepared just once The PreparedStatement object is then repeatedly used at [2] to perform blocked insert

Block Inserts Occasionally the developer may need to initially populate a table or insert a modified result set into a temporary table The efficiency of the insert operation for a large set of records can be dramatically improved by using the executeBatch method rather than the executeUpdate method The JTOpen driver converts parameterized insert statements in an executeBatch method to a block insert statement This significantly reduces the data flow and system resources required to perform the insert The following code snippet shows how to take advantage of the executeBatch method

10

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

PreparedStatement pstmt =conprepareStatement(INSERT INTO COFFEES VALUES( ))[1]for (int j = 0 j lt numOfLoops j++) pstmtsetString(1 Lavaza_ + IntegertoString(j))pstmtsetInt(2 i)pstmtsetFloat(3 499f)pstmtsetInt(4 0)pstmtsetInt(5 0)pstmtaddBatch() [2]

int [] updateCounts = pstmtexecuteBatch() [3]

At [1] a parameterized insert statement is prepared Note that all columns must be parameterized Otherwise the executeBatch method may throw the SQL0221 Number of rows 1 not valid exception In other words the developer should not mix parameter markers with literals or special registers in the VALUE clause

At [2] the addBatch method is used to add a new record to the client record buffer

At [3] all locally buffered data is sent to the server which in turn performs a block insert

Figure 4 shows the performance data for the executeBatch and executeUpdate methods

Figure 4 executeBatch() versus executeUpdate() performance comparison

11

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

WebSphere Considerations In certain situations an application provider may decide to deploy WebSphere Application Server in an AIX partition rather than natively in i5OS At the same time the application uses DB2 UDB for iSeries as an back-end database server Typically the WebSphere Application Server running in the AIX partition uses the virtual LAN to communicate with DB2 UDB for iSeries The WebSphere applications will access the database through a remote JDBC connection For performance and functionality reasons IBM recommends to utilize in such environments the IBM Toolbox for Java JTOpen driver Most of the tips and techniques described so far in this document hold true for WebSphere applications accessing DB2 UDB for iSeries There are however certain JDBC access aspects that are specific to this multi-tier architecture Letrsquos have a closer look at some of these considerations

Connection Pooling and Statement Caching

WebSphere Application Server provides its own connection pooling and statement caching mechanism that is by default enabled so that WebSphere applications automatically enjoy the performance benefits of these two critical programming techniques See the following link to learn more about the optimal connection pool setting in WebSphere

httppublibboulderibmcomwas40051englishinforzaiz51adminhelpudat_conpoolsethtml

Extended Dynamic SQL

For non-JTA connections WebSphere Application Server uses the comibmas400accessAS400JDBCConnectionPoolDataSource class as the iSeries JDBC provider implementation This is the DataSource implementation that has been used in all previous coding examples As mentioned the class supports a range of iSeries specific properties that can be used to fine tune JDBC performance These properties can be set through the WebSphere Application Server admin console For example herersquos the procedure to enable the extended dynamic SQL support In the WebSphere Application Server admin console navigate to the Data Source configuration dialog by selecting JDBC Providers -gt iSeriesToolbox -gt Data Sources then scroll down to the Additional Properties section Select Custom Properties link The Custom Properties dialog opens Scroll down to find the Extended Dynamic property and select it Change the default value false to true save the new configuration by clicking Apply button This is illustrated in Figure 5

12

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 5 Enabling the extended dynamic SQL through WebSphere Application Server console

The WebSphere Application Server needs to be restarted for the change to take effect The similar procedure can be followed to set other iSeries Data Source properties

Changing the WebSphere Application Server default isolation level

WebSphere Application Server V5 uses the REPEATABLE_READ (RR) isolation level for all implicit (WebSphere Application Server managed) transactions With the RR isolation level the rows selected updated deleted and inserted are locked until the end of the transaction Under certain circumstances this fairly extensive locking policy may cause locking contention especially when a WebSphere application competes for database resources with other applications that run on iSeries server For example a legacy order entry application may share data with the e-business customer care application running in WebSphere The locking contention may sometimes be eliminated by lowering the isolation level used by WebSphere Although the iSeries Data Source supports the custom transactionIsolation property resetting this property on the Data Source object will not change the default isolation level used by WebSphere for the connection objects produced by that Data Source In other words WebSphere will override the Data Source isolation level setting at the time the connection is obtained by a WebSphere application object such as servlet or Enterprise Java Bean (EJB) In order to change the default WebSphere behavior one must use the resource referencing Resource referencing allows a programmer to lookup DataSource or EJB objects using alias names rather than JNDI names Additionally by creating a resource reference a programmer can change certain properties of the underlying object Specifically a DataSource reference can be used to set a different isolation level for the connections produced by this database resource Typically resource references are defined by a programmer in a application development tool such as WebSphere Studio Application Developer The method to specify a DataSource reference differs depending on whether a programmer plans to use the reference in a servlet or in an EJB Letrsquos start with outlining the configuration process for a servlet In WebSphere Studio Application Developer open the deployment descriptor editor for the web project that contains the servlet To do so double click on the webxml file under WEB-INF directory in the web project In the deployment editor dialog select the References tab and then select Resource tab located in the top of the dialog that appears Under Resource References section select the Add button Herersquos an example of a DataSource reference created for iSeries DataSource named TestJDBCDS Note that the reference changes the default isolation level to READ_COMMITTED

13

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 6 Defining a resource reference for a servlet

Once the resource reference has been defined and saved the servlet source code needs to be changed to reflect the fact that a resource reference is used to obtain a DataSource from the JNDI service Herersquos the relevant code snippet try

ctx = new InitialContext() ds = (DataSource)ctxlookup(javacompenvTestJDBCJ2C)

catch (Exception e) eprintStackTrace(out)

Now the ds DataSource object will produce connections that by default run with the isolation level of READ_COMMITTED (RC)

As mentioned the process of defining a resource reference for an EJB differs from the process that is used in the case of a servlet In WebSphere Studio Application Developer open the deployment descriptor editor for the EJB project that contains the EJB To do so double click on the ejb-jarxml file under WEB-INF directory in the project In the deployment editor dialog select the References tab In the references section on the left locate and select the EJB for which the developer wants to change the default isolation level Click the Add button The Add Reference dialog opens Click the Resource Reference radio button and then Next Define the reference following the example shown in Figure 7

14

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 7 Adding a resource reference for an EJB

When you click ldquoFinishrdquo the reference definition is added to the EJB descriptor The new definition needs to be further modified To do so click on the (+) sign next to the EJB in the References list Click the new reference TestJDBCJ2C in this example to open the properties for the reference Change WebSphere Bindings and WebSphere Extensions sections as illustrated in Figure 8

15

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 8 Defining a resource reference for an EJB

Save the modified definition and then change the EJB source code to use the reference rather than directly DataSource

TroubleshootingTroubleshooting a multi-tier application may be a bit tricky because the developer needs to deal with software components that reside in separate partitions Three tools are particularly useful for pinning down the potential problem areas bull Joblog messages for a database server job mdash Provides enough details to isolate DB2 UDB for

iSeries runtime issues bull JDBC trace utility mdash Provides granular information about the data flow between the AIX

application and the iSeries server job bull Database Monitor ndash Provides detailed SQL runtime trace

Job Log MessagesAs mentioned a DB2 client communicates with a corresponding iSeries server job This server job runs the SQL requests on behalf of the client The iSeries database server jobs are called QZDASOINIT and they run in the QUSRWRK subsystem At any given time a large number of database server jobs may be active on the server so the first step is to identify the job that serves the particular client connection The easiest method to accomplish this task is to run the following CL command from the i5OS prompt

WRKOBJLCK OBJ(DB2USER) OBJTYPE(USRPRF)

Here DB2USER is the user profile that is used to connect to the iSeries server Note that a QZDASONIT job is assigned to a client after the connection has been established so the developer needs to set a breakpoint in the client application after the database connection has been established

Once the Work with Object Locks appears key in 5 (Work with Job) next to the only QZDASOINIT job that should be listed This shows the Work with Job dialog Select option 10 to

16

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

display the job log for the database server job Now the job log can be searched for any error messages generated by the DB2 runtime

Sometimes it is also useful to include debug messages in the job log The debug messages are informational messages written to the job log about the implementation of a query They describe query implementation methods such as the use of indexes join order ODP implementation (reusable versus non-reusable) and so on The easiest way to instruct an iSeries server to include the debug messages is to set the ServerTraceCategories property on the data source object

tkcpdssetServerTraceCategories(AS400JDBCDataSourceSERVER_TRACE_DEBUG_SERVER_JOB)

A sample of the job log messages with debug messages enabled is shown below

SET TRANSACTION completeSTATEMENT NAME FOUND QZ868F0A458E13AF8C Starting optimizer debug message for query Arrival sequence access was used for file COFFEESODP created ODP not deleted 5000 rows inserted in COFFEES in DB2USER STATEMENT NAME FOUND QZ868F0A4C144BF12EBlocking used for queryCursor CRSR0001 opened606 rows fetched from cursor CRSR0001 ODP not deleted Cursor CRSR0001 closed

So the job log offers fairly detailed information on how the AIX client requests were implemented by the DB2 runtime

JDBC Trace UtilityThe JTOpen driver provides a tracing utility which can be used to collect detailed client-side traces The JDBC tracing is turned off by default It can be enabled by setting the Trace property to true Heres an example of how to switch on tracing using the setTrace method on the data source object

tkcpdssetTrace(true)

The trace can also be enabled when using the DriverManagergetConnection() method for obtaining a connection to DB2 UDB for iSeries In this case the developer could add the trace property to the connection string This approach is illustrated in the following code snippet

ClassforName(comibmas400accessAS400JDBCDriver) [1] hellip con = DriverManagergetConnection(jdbcas400teraplextrace=true

db2userdb2pwd) [2]

At [1] an instance of the JTOpen JDBC Driver is initiated Then at [2] the driver is used to obtain a connection to the iSeries server Note how the trace property has been added to the database URL See the IBM Toolbox for Java JDBC properties documentation on the iSeries Information Center Web site for a complete list of properties supported by the JTOpen driver

Although the level of details provided by the trace utility is sufficient in most troubleshooting scenarios sometimes the developer may need to collect low-level traces scoped to a certain type

17

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

of information In V5R3 the IBM Toolbox for Java (as well as the latest JTOpen) added a comprehensive detailed trace facility The following is the complete list of detailed trace parameters and their purpose

bull None or ldquordquo ndash This setting disables the detailed trace bull datastream - This category is used by Toolbox classes to log dataflow between the local host

and the remote system It is not intended for use by application classes bull diagnostic - This category is used to log object state information bull error - This category is used to log errors that cause an exception bull information - This category is used to track the flow of control through the code bull warning - This category is used to log errors that are recoverable bull conversion - This category is used by Toolbox classes to log character set conversions

between Unicode and native code pages bull proxy - This category is used by Toolbox classes to log data flow between the client and the

proxy server bull pcml - This category is used to determine how PCML interprets the data that is sent to and

from the server bull jdbc - This category is used to track JDBC calls throughout the program bull thread - This category is used to enable tracing of thread information This is useful when

debugging multi-threaded applications bull all - This category will enable all previous categories

The detailed trace can be enabled when using the DriverManagergetConnection() method for obtaining a connection to DB2 UDB for iSeries In this case the developer could add the toolbox trace property to the connection string This is illustrated in the following code sample

String dbUrl = jdbcas400pwd1toolbox trace=diagnostic con = DriverManagergetConnection(dbUrl dbUser dbPassword)

Note that currently the driverrsquos DataSource interfaces do not allow the developer to directly activate the detailed tracing However they could set the server from the command line at the time the java program is launched The example below shows how the detailed trace properties could be enabled at the command line

java -Dcomibmas400accessTracecategory=diagnostic TestJDBC

The -D switch indicates to the java interpreter that the information following it will be a system property

In case of a WebSphere application the trace property can be set through the admin console In the console select Application Servers-gt server1-gt Process Definition -gt Java Virtual Machine Figure 9 shows how to set the Generic JVM Arguments for an application server instance

18

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 9 Setting JVM arguments to enable detailed Toolbox tracing

Database Monitor

The database monitor is the ultimate tool available on DB2 UDB for iSeries to collect low-level SQL traces It is mainly used to pin down the SQL performance problems Refer to the lsquoUsing iSeries Database Monitor to Identify and Tune SQL Queriesrsquo white paper for a detailed discussion on how to collect and analyze the database monitor traces httpibmcomserversenablesiteeducationiborecordhtmldtmon

IBM DB2 JDBC Universal Driver DB2 JDBC Universal Driver is one of the new features delivered with DB2 UDB Version 8 DB2 JDBC Universal Driver has been designed to eliminate the dependency on DB2 CLI runtime modules as well as to enable direct Type 4 connectivity to DB2 UDB for iSeries and DB2 UDB for zOSreg

The pure-Java (Type 4) remote connectivity is based on the DRDA open distributed protocol for cross-platform access to DB2 DRDA defines the rules the protocols and the semantics for accessing distributed data Applications can access data in a distributed relational environment by using SQL statements The iSeries DRDA application server implementation is based on multiple connection-oriented server jobs running in the QSYSWRK subsystem A DRDA listener job (QRWTLSTN) listens for TCP connect requests on port 446 Once an application requester connects to the listener job the listener wakes up one of the QRWTSRVR prestart jobs and assigns it to a given client connection Any further communication occurs directly between the client application and the QRWTSRVR job These concepts are illustrated in Figure 10

19

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 10 Accessing DB2 UDB for iSeries with DB2 Universal Driver

The DB2 Universal Driver can be loaded in an AIX partition by installing one of the DB2 Connect for AIX products (see the Additional Information section for details) It is also a part of a DB2 Enterprise Server Edition for AIX install Specifically the developer needs three JAR files in a AIX partition to successfully connect to an iSeries server db2jccjar db2jcc_license_cisuzjar and db2jcc_license_cujar The iSeries license is contained in db2jcc_license_cisuzjar Note that this file is not a part of DB2 Client In other words a DB2 Connect license is required to use the driver in production environments The location of the JAR files needs to be added to the CLASSPATH environment variable For instance the following entry could be added to the AIX profile script

CLASSPATH=homedb2inst2sqllibjavadb2jccjarCLASSPATH=$CLASSPATHhomedb2inst2sqllibjavadb2jcc_license_cujarCLASSPATH=$CLASSPATHhomedb2inst2sqllibjavadb2jcc_license_cisuzjarexport CLASSPATH

Java Runtime 131 is a prerequisite

Additionally the developer should install the latest database group PTF (SF99503 for i5OS V5R3) on the iSeries server The Informational APAR ii13348 is keeping track of any fixes relevant to DRDA above and beyond the current database group PTF

Obtaining a Connection to DB2 UDB for iSeries When Type 4 connectivity is used the DB2 Universal Driver connects directly to the DB2 on iSeries through TCPIP Note that this is different from the legacy DB2 Type 2 JDBC driver that requires a DB2 node and remote database configurations on the client accessing iSeries The following code snippet illustrates how to use the DB2 JDBC Universal Driver to obtain a connection to DB2 UDB for iSeries

20

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

try ClassforName(comibmdb2jccDB2Driver) [1] catch(javalangClassNotFoundException e) Systemerrprint(ClassNotFoundException )Systemerrprintln(egetMessage())

try DriverManagergetConnection(jdbcdb2teraplex446TERAPLEX[2]

db2userdb2pwd) hellip catch(SQLException ex) Systemerrprintln(

SQLException + exgetMessage())

At [1] an instance of the DB2 JDBC Universal Driver is instantiated Then at [2] the driver is used to obtain a connection to the iSeries server Note the proper form of the database URL required by the driver

Considerations There are several advantages of DB2 JDBC Universal Driver bull Ease of cross-platform development mdash Consistent coding techniques and consistent error

codes and messages bull Ease of deployment mdash Pure Java (no runtime client required) and a single driver for accessing

DB2 on different platforms

The ease of use comes at a price though The iSeries JTOpen driver is optimized for accessing DB2 UDB for iSeries data and it uses native iSeries protocol to communicate with the back-end database server job This usually results in better performance and more-efficient system resources utilization For instance when using the DB2 JDBC Universal Driver to access an iSeries server the executeBatch method results in a single record insert There are also some restrictions when using DB2 Universal JDBC Driver with Type 4 connectivity

bull Support for distributed transactions (JTA) is not enabled bull Driver built-in connection pooling is not supported

Refer to Java application support in DB2 for more details on DB2 JDBC Universal Driver

21

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 Connect data access This section will explore the most important aspects of DB2 Connect ndash iSeries integration - including configuration tips and coding examples

DB2 Connect provides functionality for accessing data stored in DB2 UDB for iSeries as well as DB2 UDB for zOS and DB2 UDB for OS390reg DB2 Connect offers capabilities to access DB2 family members via several SQL interfaces gateway functions such as connection pooling and federated database functionality Many applications supporting the DB2 family of products leverage DB2 Connect as a key middleware component DB2 Connect is offered as separate AIX license products

Enterprise Edition Application Server Edition

In addition to DB2 Connect there are several other DB2 UDB Version 81 products that are supported on AIX

DB2 Universal Database Enterprise Server Edition DB2 Universal Database Workgroup Server Unlimited Edition DB2 Universal Database Workgroup Server Edition DB2 Universal Database Universal Developers Edition All Clients

The DB2 Connect Enterprise Edition functionality is also contained in DB2 Enterprise Server Edition for AIX

22

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 Connect in a nutshell In the scenario described in this paper the DB2 Connect functions contained in DB2 Enterprise Edition for AIX are utilized DB2 Connect Enterprise Edition provides support for both local and remote DB2 clients This is illustrated in Figure 11 Accessing DB2 UDB for iSeries with DB2 Connect

Figure 11 Accessing DB2 UDB for iSeries with DB2 Connect

DB2 Connect implements the Distributed Relational Database Architecturetrade (DRDAreg) to reduce the cost and complexity of accessing data stored in DB2 UDB for iSeries and other DRDA-compliant database servers DRDA defines the rules the protocols and the semantics for accessing distributed data Applications can access data in a distributed relational environment by using SQL statements In a distributed environment the system running the application and sending the SQL requests across the network is called the application requester (AR) A remote database server that executes SQL requests submitted by an application requester is known as the application server (AS) In the example shown in Figure 11 (above) DB2 Connect plays the role of an application requester while DB2 UDB for iSeries is an application server In this case DB2 Connect communicates with the iSeries database through TCPIP The iSeries DRDA application server implementation is based on multiple connection-oriented server jobs running in the QSYSWRK subsystem A DRDA listener job (QRWTLSTN) listens for TCP connect requests on port 446 Once an application requester connects to the listener job the listener wakes up one of the QRWTSRVR prestart jobs and assigns it to a given client connection Any further communication occurs directly between the client application and the QRWTSRVR job

DB2 Connect supports a wide range of programming interfaces that can be used by AIX applications to access the iSeries database Embedded SQL frac34 Both static and dynamic SQL frac34 Various programming languages (Java CC++ Cobol Fortran REXX)

DB2 Call Level Interface (DB2 CLI) ODBC JDBC frac34 DB2 JDBC Type 2 Driver frac34 DB2 JDBC Type 4 Driver (Universal JDBC Driver)

23

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Note that DB2 Connect supports access to DB2 UDB for iSeries through DB2 JDBC Universal driver However for performance and ease of maintenance reasons IBM recommends that Java applications running in AIX use native iSeries Toolbox JDBC driver See the JDBC Data Access section of this paper (above) for more details On the other hand DB2 Connect is a very efficient and robust connectivity option for AIX applications especially in the environments that are not directly supported by the native iSeries JDBC driver Here are several possible scenarios that would require DB2 Connect installed in a AIX partition

Embedded SQL interface is used to access DB2 CLI or ODBC interface is used to access DB2 A single SQL interface is needed to access multiple back end DB2 server Specific DB2 Connect functionality is needed such as distributed join or connection

pooling

Prerequisites One of the DB2 Connect products or DB2 Enterprise Server Edition for AIX V81 is needed Additionally DB2 Application Development Client is required in the AIX partition to compile DB2 applications

For maximum database server stability the developer should install the latest database group PTF (SF99503 for i5OS V5R3) on the iSeries server The Informational APAR ii13348 is keeping track of any fixes relevant to DRDA above and beyond the current database group PTF

DB2 Connect configuration The following example employs i5OS V5R3 and DB2 UDB Enterprise Server Edition for AIX Version 81 FixPak 6

Configuration steps in the iSeries partition The following process lists the necessary steps to be performed on the iSeries server 1) Verify that the TCPIP stack is working correctly It is assumed that the Virtual LAN is used to

communicate with the i5OS partition First obtain the IP address of the iSeries server or its hostname and ping the iSeries server from the AIX partition

2) Create a relational database (RDB) entry for the iSeries database in the i5OS partition If this has already been created it can be displayed by using the DSPRDBDIRE command Make sure that the RDB entry with a location of LOCAL exists on the iSeries server If it does not exist use the ADDRDBDIRE command to add the appropriate RDB entry For example the following command would add an RDB entry named TPLX For simplicity it is recommended that the TCPIP host name and RDB entry remain the same

ADDRDBDIRE RDB(TPLX) RMTLOCNAME(LOCAL)

3) Create a collection called NULLID This is necessary because the utilities shipped with DB2 Connect and DB2 UDB for AIX store their packages in the NULLID collection Since it does not exist by default in the iSeries server you must create it using the following command

CRTLIB LIB(NULLID)

4) Products that support DRDA automatically perform any necessary code page conversions at the receiving system For this to happen both systems need a translation table from their code page to the partner code page The default Coded Character Set Identifier (CCSID) on the iSeries server is 65535 Since DB2 Connect does not have a translation table for this code page the developer needs to change the individual user profiles to contain a CCSID that can be converted properly by DB2 Connect For US English this is 037 For other languages see DB2 Connect Personal Edition Quick Beginning GC09-2967 The following command changes the CCSID for an individual user profile to 037

24

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

CHGUSRPRF userid CCSID(037)

5) Verify that the default port 446 for DRDA service is being used To do this go to the Configure TCPIP menu (CFGTCP) select Configure Related Tables and then select Work with service table entries Verify that the DRDA service is set for port 446

6) The Distributed Data Management (DDM) job must be started for DRDA to work If you want the DDM job to be automatically started whenever TCPIP is started change the attributes of the DDM job using the CHGDDMTCPA command and set the Autostart server parameter to YES

7) If the system administrator chooses not to autostart the server issue the following command to start the DDM server job

STRTCPSVR SERVER(DDM)

8) Make sure that the user profiles that will be used to connect to the iSeries server exist on the server

25

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Configuration steps in the AIX partition The following steps are required for DB2 Connect to be configured in the AIX partition 1) Sign on to the AIX partition as the DB2 administrator 2) Launch Client Configuration Assistant (db2ca from the command prompt) It is assumed that

VNC or an X-Windows server are being used on the workstation so that the db2ca GUI can be properly rendered

3) From the Selected pull-down menu select the Add Database using Wizard option The Select how you want to setup a connection dialog appears Select Manually configure a connection to a database and click Next This is shown in Figure 12

Figure 12 Accessing DB2 UDB for iSeries with DB2 Connect

26

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

4) On the Select a communications protocol choose TCPIP and select The database physical resides on a host or OS400 system Then select the option Connect directly to the server as shown in Figure 13 Click Next

Figure 13 mdash Selecting communications protocol

27

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

5) On the TCPIP tab fill in the host name of the iSeries server The port number should be 446 This is shown in Figure 14 Click Next

Figure 14 mdash Specifying TCPIP communication parameters

28

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

6) On the Database tab fill in the Relational Database name Use the RDB entry name (specified in step 2) in the Configuration steps in the iSeries partition section as shown in Figure 15 Click Next

Figure 15 mdash Specifying the remote database

7) If you plan to use the ODBC applications select Register this database for ODBC as a system data source on the ODBC tab Click Next

29

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

8) On the Specify the node option dialog select OS400 from the Operating System pull-down menu This is shown in Figure 16 Click Finish

Figure 16 mdash Specifying the node options

30

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

9) The Test Connection dialog appears This allows the developer to verify that the connection works Select both CLI and JDBC check boxes You are also prompted for an iSeries user ID and password as shown in Figure 17

Figure 17 mdash Testing the connection

31

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

10) The successful connection to the database server is confirmed by the message box shown in Figure 18

Figure 18 mdash Test Connection results 11) At this time a newly configured database connection should appear in the main DB2

Configuration Assistant window It is recommended that the DB2 utilities are also bound to the iSeries database The bind process creates the necessary SQL packages on the remote database In the main Configuration Assistant window click the TPLX database entry and then select Selected-gtBindhellip

32

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

12) The Bind dialog appears Click Select All and then enter the connection information as shown in Figure 19 Click Bind The Results message box appears This allows the developer to monitor the progress of the binding process Watch for any error and warning messages

Figure 19 mdash Binding the DB2 utilities This concludes the DB2 Connect configuration steps

33

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Accessing DB2 UDB for iSeries from C embedded SQL

As mentioned earlier DB2 Connect allows developers to compile and run embedded SQL applications that access DB2 UDB for iSeries data This section covers implementation details for a C embedded SQL application called cursorsjsqc (see Appendix B for source code)

Prerequisites An embedded SQL application running in an AIX partition will use DB2 Connect services to access DB2 UDB for iSeries therefore the developer needs to make sure that all components listed in section Prerequisites on page 24 are installed The developer also needs to create a remote database connection as described in the DB2 Connect configuration section of this paper on page 24

Static SQL and SQL packages To successfully run against a DB2 UDB for iSeries database an embedded SQL application needs to be first precompiled and bound to the back-end database This process creates an SQL package on the target iSeries server The SQL package contains the access plan information for the SQL statements executed by the application The internal structure of the package as well as the method how its content is used by the SQL runtime to facilitate the access plan reuse is similar to the Extended Dynamic SQL support covered in detail in the Extended Dynamic SQL and Statement Caching section of this paper (on page 9) There are however important differences between the packages created by the extended dynamic SQL support and the packages created for embedded SQL DRDA client applications The extended dynamic SQL packages support dynamic SQL interfaces such as JDBC

that can submit ad hoc SQL statements at the run time The SQL runtime can prepare the dynamic statements and add them to the package On the other hand the DRDA packages are created at the precompile time and contain static SQL In order to add new statements to the package the application needs to be precompiled and rebound again

The extended dynamic SQL package can dynamically grow up to 500MB by allocating new space as required The DRDA packages since they are created at the precompile time have a fix size and do not grow over their life time

Simple embedded SQL application The application is based on a source code provided in the DB2 UDB samples directory typically to be found at homedb2inst1sqllibsamples The cursorsjsqc performs a join between STAFF and ORG tables located in DB2USER schema (library) on the TPLX database server (the source is provided at the end of this paper in Appendix B) The join statement retrieves the DEPTNAME column from ORG NAME column from STAFF and calculates the total compensation for an employee by adding SALARY and COMM columns in STAFF The results are sorted by department name and total compensation Here is the SELECT statement used by the application

SELECT deptname name salary + IFNULL(comm0) as compensationFROM org o staff sWHERE odeptnumb = sdeptORDER BY deptname compensation DESC

The application iterates through the selected records and prints out the data to the standard output device The sample DB2USER schema was created with the following SQL statements

db2 CONNECT TO tplx USER db2user USING mypassworddb2 CALL QSYSCREATE_SQL_SAMPLE(DB2USER)

34

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Make sure that the AIX partition is logged into with the DB2 admin user profile If the defaults were selected at the DB2 installation time this profile name is db2inst1 It is also assumed that DB2USER user exists on the iSeries server and that it has appropriate authority

There are several steps that are required to create an executable for the cursorsjsqc source code First the DB2 PRECOMPILE utility needs to be called The utility creates a bind file that is used to bind the required SQL package to the TPLX database It also converts embedded SQL statements into DB2 run-time API calls and produces a pure C source file that can be processed by an AIX C compiler

db2 CONNECT TO tplx USER db2user USING mypassworddb2 prep cursorsjsqc bindfile

Note that the connect statement is required only if the developer is not already connected to the database on an iSeries server Watch for any error or warning messages returned by the DB2 prep utility The prepare step should produce cursorsjbnd and cursorsjc files in the current directory Now the developer can invoke the bind utility to prepare the statements contained in the bind file and create the package on the target iSeries database server

db2 bind cursorsjbnd

It is assumed that Visual C++ 60 is installed and configured in the AIX partition Refer to the ldquoDeveloping and Porting C and C++ Applications on AIXrdquo redbook for more information on how to use the Visual C++ compiler httpibmcomredbooksabstractssg245674htmlOpen

Use the following commands to compile the C source generated by the precompile utility

xlc -I$INSTHOMEsqllibinclude ndashc cursorsjcxlc ndasho cursorsj cursorsjo -L$INSTHOMEsqlliblib ndashldb2

Run the program from the AIX prompt

cursorsj db2user mypassword

Distributed Join DB2 UDB Version 8 provides core federated server functionality A federated system consists of a DB2 UDB instance that operates as a federated server a database that acts as the federated database one or more data sources and clients (users and applications) that access the database and data sources Federated server permits objects stored in multiple databases to be accessed together in the same query For example a query can refer to a table that resides in DB2 UDB for iSeries and join it to a table stored in DB2 UDB for AIX Such a query would constitute so called distributed join The support for DB2 UDB for iSeries as a federated data source is provided by core federated server functionality directly implemented in DB2 UDB Enterprise Server Edition and DB2 UDB Connect Enterprise Edition All other DB2 UDB family members are also supported directly by core DB2 UDB federated server An additional software product DB2 Information Integratortrade is required to access non-DB2 UDB databases such as Oracle Sybase or Microsoftreg SQL Server Consult the following white papers for a detailed discussion on DB2 federated server support Heterogeneous data access for iSeries applications Version 2 httpibmcomserversenablesiteeducationiborecordhtmlhetdata Fundamentals of IBM DB2 Federated Server and Relational Connect httpwww7bsoftwareibmcomdmddlibrarytecharticle0206purnell0206purnellhtml

35

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Distributed Join Example In this section the steps that are required to configure DB2 UDB for iSeries as a federated data source will be illustrated Then the cursorsjsqc program will be ldquotweakedrdquo so that it executes a distributed join query that accesses data stored on an iSeries server and in the local DB2 UDB for AIX database It is assumed that the developer is familiar with the DB2 federated server concepts

Note Run the following commands from the Command Line Processor prompt Load the utility by executing the db2 command at the AIX prompt 1) First the local DB2 UDB for AIX instance needs to be enabled as a DB2 federated server

This is done by setting the database manager configuration parameter FEDERATED to YES

db2=gt update dbm cfg using FEDERATED YES

The database instance needs to be restarted for the change to take effect

NOTE A federated database is a regular database in a DB2 UDB instance that has the FEDERATED parameter enabled Therefore in this example the SAMPLE database that was created earlier is used as the federated database A new database can also be created using the CREATE DATABASE command

2) Connect to the federated database

db2=gt connect to sample

3) Use the CREATE WRAPPER statement to register a wrapper for the iSeries data source Wrappers are library routines that are used by the federated server to perform operations such as connecting to a data source and retrieving data from it The default wrapper name for DB2 UDB for iSeries is DRDA Here is the command to register the DRDA wrapper

db2=gt create wrapper drda

4) Use the CREATE SERVER statement to register a data source as a server within the federated database The server definition specifies the type and version of the data source and the wrapper used for communications with this data source For the DB2 UDB for iSeries data source the node and the database names are also needed The node and database name parameters have been configured for our TPLX database in the Configuration steps in the AIX partition section (on page 24) Use the following DB2 UDB command to lookup these parameter on the federated server

db2=gt list database directory

In this case the command produced the following output

Database alias = TPLX Database name = DCSE99E1 Node name = NDE9BF76 Database release level = a00 Comment = Directory entry type = Remote Authentication = SERVER Catalog database partition number = -1

36

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Note that the node name is set to NDE9BF76 The name was generated by the Configuration Administrator utility (db2ca)

Here is the command to register the TPLX database as a federated server

db2=gt create server tplx type db2400 version 530 wrapperdrda authorization db2user password mypassword options(nodeNDE9BF76 dbname TPLX)

The command is quite complex so make sure that the syntax is correct

5) Define the user mappings that instructs the federated server what user ID and password should be used when connecting to the iSeries data source

db2=gt create user mapping for user server tplxoptions(remote_authid db2user remote_password mypassword)

Specify the nickname for the iSeries table or view A nickname is an identifier that is used by the federated server to reference an object located at the data source The following command creates a nickname for the STAFF table located in the DB2USER schema on the TPLX database

db2=gt create nickname tplx_staff for tplxdb2userstaff

6) Test the distributed join query

db2=gt SELECT deptname name salary + COALESCE(comm0) ascompensation FROM org o tplx_staff s WHERE odeptnumb =sdept ORDER BY deptname compensation DESC

Note that the native iSeries function IFNULL has been substituted with an equivalent DB2 UDB function COALESCE COALESCE is also supported on iSeries servers For better portability IBM encourages the use of COALESCE rather than IFNULL Note also that the query runs on the federated server rather than on TPLX It accesses the ORG table in the local DB2 UDB for AIX SAMPLE database and the STAFF table that resides in TPLX The federated server performs the necessary distributed join

7) Modify the cursorsjsqc so that it executes a distributed join There are two source code modifications - Change the CONNECT TO statements Now the application needs to connect to the

federated database SAMPLE rather than to TPLX

EXEC SQL CONNECT TO SAMPLEEXEC SQL CONNECT TO SAMPLE USER userid USING passwd

- Modify the select statement so that it performs a distributed join Use the statement (shown in step 6) above Save the new source version as cursordjsqc

- Prepare bind and compile the distributed join version of the program as described in the Simple C embedded SQL application section (on page 34)

db2 prep cursordjsqc bindfiledb2 bind cursordjbndxlc -I$INSTHOMEsqllibinclude ndashc cursordjcxlc ndasho cursordj cursordjo -L$INSTHOMEsqlliblib ndashldb2

37

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

- Run the program from the AIX prompt

cursordj

Connection Pooling and Connection ConcentratorA modern Web-based application typically executes a large number of short-lived transactions Executing a transaction in this environment means establishing a database connection executing a few SQL statements and terminating this connection Creating connections to the database server is a very costly process To reduce the unnecessary workload DB2 Connect implements connection pooling and connection concentrator Connection pooling mechanism allows DB2 Connect to reuse an existing connection infrastructure for subsequent connection requests The connection concentrator is an advanced technology that allows DB2 Connect to serve a potentially very large number of clients with a limited number of database connections This is accomplished by decoupling clients from a particular database connection

Note that currently neither connection pooling nor connection concentrator support DB2 UDB for iSeries Therefore for performance reasons the author strongly recommends that the application server that obtains and drops connections very frequently implements its own database connection pooling mechanism that would assign an existing pooled database connection to a new AIX process or thread

TroubleshootingTroubleshooting a multi-tier application may be a bit tricky because the developer needs to deal with software components that reside in separate partitions The authorrsquos experience shows that two tools are particularly useful for pinning down the potential problem areas The joblog messages for a database server job usually provide enough details to isolate DB2

UDB for iSeries runtime issues The DRDA trace utility provides granular information about the data flow between the AIX

application and the iSeries server job

38

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Job Log MessagesAs mentioned earlier a DB2 client communicates with a corresponding iSeries server job This server job runs the SQL requests on behalf of the client More precisely when a DB2 client submits an SQL statement the statement is passed to a server job that in turn calls the DB2 runtime to execute the statement The results are then reformatted and marshaled to the client The iSeries DRDA server jobs are called QRWTSRVR and they run in the QUSRWRK subsystem At any given time there may be a large number of DRDA server jobs active on the system so the first step is to identify the job that serves the particular client connection The easiest method to accomplish this task is to run the following CL command from the i5OS prompt

WRKOBJLCK OBJ(DB2USER) OBJTYPE(USRPRF)

Here DB2USER is the user profile that is used to connect to the iSeries server Note that a QRWTSRVR job is assigned to a client after the connection has been established so the developer needs to set a breakpoint in the client application below the CONNECT TO statement

Once the Work with Object Locks appears key in 5 (Work with Job) next to the only QRWTSRVR job that should be listed This shows the Work with Job dialog Select option 10 to display the job log for the database server job Now the developer can search the job log for any error messages generated by the DB2 runtime

Sometimes it is also useful to include debug messages in the job log The debug messages are informational messages written to the job log about the implementation of a query They describe query implementation methods such as use of indexes join order ODP implementation (reusable versus non-reusable) and so on The easiest way to instruct the iSeries server to include the debug messages is to call the following stored procedure just after the connection to the iSeries server is established

EXEC SQL call qsysqcmdexc(STRDBGUPDPROD(YES)000000002000000)

A sample of the job log messages with debug messages enabled is shown below in Figure 20

Arrival sequence access was used for file STAFFAccess path suggestion for file STAFFQuery options used to build the OS400 query access plan Ending debug message for query ODP created Blocking used for queryCursor SQLCUR201 opened1 rows fetched from cursor SQLCUR201Row not found for SQLCUR201ODP deleted Cursor SQLCUR201 closedDESCRIBE of prepared statement STMT0201 completed

Figure 20 mdash Joblog with debug messages enabled

So the job log offers fairly detailed information on how the AIX client requests were implemented by the DB2 runtime

39

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 DRDA trace utilityThe DB2 DRDA trace utility (db2drdat) provides detailed information about the data streams exchanged between DB2 Connect and target database server The output file produced by the utility contains send and receive communications buffers TCPIP error messages and SQL Communications Area (SQLCA) information Please refer to lsquoDB2 Connect Userrsquos Guidersquo manual for in-depth discussion of the DRDA trace utility

Accessing DB2 UDB for iSeries from CLI DB2 Call Level Interface (CLI ) is based on the Microsoft Open Database Connectivity (ODBC) specification and the ISO CLI standard The DB2 CLI interface gained popularity among DB2 application providers because the developer can build an ODBC application by simply linking the application with libdb2 library on a UNIX server In other words the developer directly utilizes the DB2 ODBC driver services without a need for an ODBC driver manager Additionally in contrast to embedded SQL the developer does not need to precompile or bind DB2 CLI applications because they use packages provided with DB2 UDB The developer simply compiles and links the application

Prerequisites A DB2 CLI application running in an AIX partition will use DB2 Connect services to access DB2 UDB for iSeries therefore make sure that all components listed in Prerequisites section of this paper on page 24 are installed The developer also needs to create a remote database connection as described in the DB2 Connect configuration section of this paper on page 24

Dynamic SQL and Access Plan Caching A DB2 CLI client application uses the dynamic SQL interface and does not have the capability to utilize the extended dynamic SQL support Therefore it runs lsquopurersquo dynamic SQL statements That does not mean however that the process of parsing validating and optimizing will be repeated for every execution of a given dynamic SQL statement

The DB2 UDB for iSeries database implements an internal object called System-Wide SQL Statement Cache (SWSC) The SWSC can improve the performance of programs using dynamic SQL statements by caching the access plans in a system-wide cache When a dynamic SQL statement is submitted the SQL runtime searches the SWSC to see if this statement has been previously executed If so then DB2 retrieves and reuses the key information associated with the cached statement and thereby the processing time and the resources utilization can be significantly reduced

Simple DB2 CLI C++ ApplicationThis section covers DB2 CLI implementation details for a sample C++ program called testclicpp (the source is provided at the end of this paper in Appendix C) To compile the source with Visual C++ complier use the following command in the AIX partition

xlC ndashI$INSTHOMEsqllibinclude ndashc testclicppxlC ndasho testcli testclio ndashL$INSTHOMEsqlliblib ndashldb2

The application performs a join between STAFF and ORG tables located in DB2USER schema (library) The join statement retrieves the DEPTNAME column from ORG NAME and JOB columns from STAFF and calculates the total compensation for an employee by adding SALARY and COMM columns in STAFF The results are sorted by total compensation The selection criterion is based on the current value of the department name parameter Here is the SELECT statement used by testcli

40

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

select name job salary + coalesce(comm0) as compensationfrom org o staff swhere odeptnumb = sdeptand deptname = order by compensation desc

Figure 21 shows the software components involved in the execution of this sample application

Figure 21 How a DB2 CLI client accesses DB2 UDB on an iSeries server

Although the testcli application is fairly simple it covers some important aspects of efficient CLI programming for DB2 UDB for iSeries

Reusable Open Data Paths (ODPs)An Open Data Path (ODP) definition is an internal i5OS object that is created when certain SQL statements (such as OPEN INSERT UPDATE and DELETE) are executed for the first time in a given job (or connection) The ODP can be thought of as a runtime implementation of an access plan The access plan created at the optimization time provides a recipe or in other words a sequence of steps necessary to execute the statement The ODP on the other hand provides the executable code for all requested IO operations The process of creating new ODP objects is fairly CPU- and IO-intensive so whenever possible the iSeries DB2 runtime tries to reuse existing ODPs For instance a SQLCloseCursor() API call may close the SQL cursor but leave the ODP available to be used the next time the cursor is opened This can significantly reduce the processing and response time in running SQL statements A reusable OPD usually requires 10 to 20 times less CPU resources than a newly created ODP Therefore it is important that the applications employ programming techniques that allow the DB2 runtime to reuse ODPs

With dynamic interfaces such as CLI full opens are avoided by using a prepare once execute many programming paradigm It means that when an SQL statement is going to be executed more than once you should prepare the statement just once and then reuse the prepared

41

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

statements for consecutive executions Although DB2 UDB does try to convert literals to parameter markers so that similar statements can be reused it is a better programming practice to explicitly implement parameter markers That way the chances for reusable ODPs are quite significantly improved The code snippet in Figure 22 illustrates how to implement the prepare once execute many programming technique

Define A SELECT SQL Statementstrcpy((char ) SQLStmt select name job salary + ifnull(comm0) ascompensation )ptr = strcat( (char ) SQLStmt from org o staff s )ptr = strcat( (char ) SQLStmt where odeptnumb = sdept)ptr = strcat( (char ) SQLStmt and deptname = )ptr = strcat( (char ) SQLStmt order by compensation desc) [1]

Prepare The SQL Statementrc = SQLPrepare(ExampleStmtHandle SQLStmt SQL_NTS) [2]

Bind The Columns In The Result Data Set Returned To Application Variablesrc = SQLBindCol(ExampleStmtHandle 1 SQL_C_CHAR (SQLPOINTER)

ExampleName sizeof(ExampleName) NULL)rc = SQLBindCol(ExampleStmtHandle 2 SQL_C_CHAR (SQLPOINTER)

ExampleJob sizeof(ExampleJob) NULL)rc = SQLBindCol(ExampleStmtHandle 3 SQL_C_DOUBLE (SQLPOINTER)

ampExampleComp sizeof(ExampleComp) NULL)

for (int i = 0 i lt LOOPS i++)rc=SQLBindParameter(ExampleStmtHandle

1SQL_PARAM_INPUTSQL_C_CHARSQL_CHAR10(SQLPOINTER) currentDepartment[i8]0NULL) [3]

rc = SQLExecute(ExampleStmtHandle) [4]cout ltlt endl ltlt Current Dept ltlt currentDepartment[i8] ltlt endl Display The Results Of The SQL QueryExampleShowResults()

Figure 22 Use the prepare once execute many programming technique

The error-handling code has been removed for clarity At [1] the statement text is assigned to a variable Note that a parameter marker is used in the WHERE clause The statement is then prepared just once at [2] The current value of the parameter is bound to the prepared statement at [3] The prepared statement is executed at [4] Steps [3] and [4] are repeatedly executed in a for loop

Techniques to Further Improve DB2 CLI Performance Thus far this paper has discussed the techniques used by a sample application to tune the CLI performance However depending on the application architecture other methods of improving CLI performance may be considered

Connection PoolingCurrently the CLI application connecting through DB2 Connect to DB2 UDB for iSeries does not take advantage of the connection pooling mechanism implemented by DB2 Connect Therefore for performance reasons the author strongly recommends that the application server that obtains and drops connections very frequently implements its own database connection pooling mechanism that would assign an existing pooled database connection to a new AIX process or thread

42

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Blocking

For queries which result in returning large data blocks from the iSeries server (usually 32K of data and above) ensure that the database manager configuration parameter RQRIOBLK is set to 32767 This can be done using the Command Line Processor (CLP) as follows

db2 update database manager configuration using RQRIOBLK 32767

TroubleshootingThe experience of the author shows that two tools are particularly useful for pinning down the potential problem areas bull Joblog messages for a database server job usually provides enough details to isolate DB2

runtime issues bull CLI trace utility provides granular information about the data flow between the AIX application

and the database server job

Job Log MessagesThe process of finding and analyzing the job log for a DB2 CLI connection is identical to the process outlined for an embedded SQL application in the Job Log Message section of this paper on page 39

CLI Trace The DB2 CLIODBCJDBC trace utility provides very detailed information about the data streams exchanged between DB2 Connect and target database server Refer to the DB2 Information Center for more information on how to set up and analyze the CLI traces httppublibboulderibmcominfocenterdb2v8luwindexjsptopic=comibmdb2udbdocadc000 7959htm

43

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Trademarks

IBM eServer iSeries AIX AIX 5L i5OS WebSphere DB2 DB2 Universal Database DB2 Connect OS400 zOS OS390 Distributed Relational Database Architecture DRDA and DB2 Information Integration are trademarks or registered trademarks of International Business Machines Corporation in the United States and other countries

Java and all Java-based trademarks are trademarks of Sun Microsystems Inc in the United States other countries or both

Linux is a registered trademark of Linus Torvalds in the United States other countries or both

UNIX is a registered trademark of The Open Group in the United States and other countries

Microsoft and Windows are registered trademarks of Microsoft Corporation in the United States andor other countries

All other registered trademarks and trademarks are properties of their respective owners

IBM makes no commitment to make available any products referred to herein

References in this publication to IBM products or services do not imply that IBM intends to make them available in every country in which IBM operates

Additional Information ITSO offers a Redbook that can be helpful to those who want to learn more about i5OS AIX integration

bull AIX Integration with I5OS on the IBM eServer iSeries Server (SG24-6551)

Jarek Miszczyk is the Senior Software Engineer IBM eServer Solutions Enablement IBM Rochester

[Portions of this white paper reprinted with permission from MC Mag Online published by MC Press LLP httpwwwmcpressonlinecom]

Acknowledgments The author would like to thank the following people for their advice contributions and support on this paper

Bob Bittner IBM Rochester Jon Rush IBM Rochester Prasad Vallurupalli IBM Rochester Neil Willis IBM Rochester

44

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix A Source Listing of TestJDBCjava

package comibmiseriespwdimport javasqlimport javaxnamingimport javautilHashtableimport javautilimport javaxsqlimport comibmas400access

public class TestJDBC public static void main(javalangString[] args)

throws Exception

int numOfLoops = 5000int outerNumOfLoops = 5boolean firstExec = trueConnection conStatement sPreparedStatement psPreparedStatement pstmtdelCallableStatement cstmPreparedStatement pstmtHashtable env = new Hashtable()

envput(ContextINITIAL_CONTEXT_FACTORYcomsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env)Systemoutprintln(Deploying connection pooling data source)deployDataSource() Do the work with connection pooling onlyAS400JDBCConnectionPoolDataSource tkcpds =

(AS400JDBCConnectionPoolDataSource)ctxlookup(jdbcToolkitDataSource) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPool pool = new AS400JDBCConnectionPool(tkcpds) Adds 1 connection to the pool that can be used by theapplication (creates the physical database connections based onthe data source)poolfill(1)Systemoutprintln(nStart timing Toolkit connection pooling)long startTime = SystemcurrentTimeMillis()

for (int i = 0 i lt outerNumOfLoops i++) con = poolgetConnection()consetAutoCommit(false) deleteif ( i == 0)

long startDelete = SystemcurrentTimeMillis()cstm = cstm = conprepareCall(

CALL qsysqcmdexc(CLRPFM FILE(DB2USERCOFFEES) + 000000002800000))

cstmexecuteUpdate()cstmclose()long endDelete = SystemcurrentTimeMillis()Systemoutprintln(Delete all records +

(endDelete - startDelete) + ms elapsed)

45

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

String sqlinstrlong startInsert = SystemcurrentTimeMillis() insert

pstmt =conprepareStatement(INSERT INTO COFFEES VALUES( ))for (int j = 0 j lt numOfLoops j++) pstmtsetString(1 Kona_ + IntegertoString(i))pstmtsetInt(2 150)pstmtsetFloat(3 999f)pstmtsetInt(4 0)pstmtsetInt(5 0)pstmtaddBatch()int [] updateCounts = pstmtexecuteBatch()concommit()pstmtclose()long endInsert = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for + numOfLoops + inserts

+ (endInsert - startInsert)) selectlong startSelect = SystemcurrentTimeMillis()ps = conprepareStatement(SELECT FROM COFFEES)ResultSet rs = psexecuteQuery()rsnext()rsclose()concommit()psclose()long endSelect = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for select +

(endSelect - startSelect))consetAutoCommit(true)conclose()long endTime = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for + outerNumOfLoops +

loops + (endTime - startTime))Systemexit(0)

private static void deployDataSource()throws ExceptionString serverName = teraplex String databaseName = TERAPLEX String userName = db2user String password = db2pwd

Establish a JNDI context and bind the connection pool data sourceHashtable env = new Hashtable()envput(ContextINITIAL_CONTEXT_FACTORY

comsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPoolDataSource tkcpds = new

AS400JDBCConnectionPoolDataSource()tkcpdssetServerName(serverName) tkcpdssetDatabaseName(databaseName) tkcpdssetUser(userName) tkcpdssetPassword(password) tkcpdssetDescription(Toolkit Connection Pooling DataSource)tkcpdssetSavePasswordWhenSerialized(true)tkcpdssetExtendedDynamic(true)

46

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

tkcpdssetPackage(JDBCDS)tkcpdssetPackageCache(true)tkcpdssetPackageCriteria(select)enable the following properties as requiredcpdssetTrace(true)tkcpdssetServerTraceCategories( AS400JDBCDataSourceSERVER_TRACE_DEBUG_SERVER_JOB)

ctxrebind(jdbcToolkitDataSource tkcpds)

47

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix B mdash Source Listing of cursorsjsqc

Source File Name = cursorsjsqc Licensed Materials - Property of IBM (C) COPYRIGHT International Business Machines Corp 1995 2000 2004 All Rights Reserved US Government Users Restricted Rights - Use duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp PURPOSE This sample program demonstrates the use of a CURSOR The CURSOR is processed using static SQL EXTERNAL DEPENDENCIES - Ensure existence of database for precompile purposes - Precompile with the SQL precompiler (PREP in DB2) - Bind to a database (BIND in DB2) - Compile and link with the IBM Cset++ compiler (AIX and OS2) or the Microsoft Visual C++ compiler (Windows) or the compiler supported on your platform For more information about these samples see the README file For more information on programming in C see the - Programming in C and C++ section of the Application Development Guide For more information on building C applications see the - Building C Applications section of the Application Building Guide For more information on the SQL language see the SQL Reference

include ltstdiohgt include ltstdlibhgt include ltstringhgtinclude ltsqlhgtinclude ltsqlenvhgtinclude ltsqldahgtinclude ltsqlcahgt

int SqlInfoPrint( char struct sqlca int char )void TransRollback( void)

define EMB_SQL_CHECK( MSG_STR ) rc = SqlInfoPrint( MSG_STR ampsqlca __LINE__ __FILE__) if ( rc = 0 ) TransRollback( )

return 1

EXEC SQL INCLUDE SQLCA

int main(int argc char argv[])

EXEC SQL BEGIN DECLARE SECTIONchar dname[15]

48

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

char pname[10]double compchar userid[9]char passwd[19]

EXEC SQL END DECLARE SECTION

int rc = 0printf( Sample C program CURSORSJ n )if (argc == 1)

EXEC SQL CONNECT TO TPLXEMB_SQL_CHECK(CONNECT TO TPLX)

else if (argc == 3)

strcpy (userid argv[1])strcpy (passwd argv[2])EXEC SQL CONNECT TO TPLX USER userid USING passwdEMB_SQL_CHECK(CONNECT TO TPLX)

else

printf (nUSAGE cursor [userid passwd]nn)return 1

endif

EXEC SQL DECLARE c1 CURSOR FORselect deptname name salary + ifnull(comm0) as compensationfrom org o staff swhere odeptnumb = sdeptorder by deptname compensation desc

EXEC SQL OPEN c1EMB_SQL_CHECK(OPEN CURSOR)

printf(DEPARTMENT NAME COMPENSn)printf(-----------------------------------n)do

EXEC SQL FETCH c1 INTO dname pname compif (SQLCODE = 0) breakprintf( -1515s -1010s 72fn dname pname comp )

while ( 1 )

EXEC SQL CLOSE c1EMB_SQL_CHECK(CLOSE CURSOR)

EXEC SQL CONNECT RESETEMB_SQL_CHECK(CONNECT RESET)

exit(0)

end of program CURSORSJSQC

int SqlInfoPrint( char appMsgstruct sqlca pSqlcaint linechar file )

int rc = 0char sqlInfo[1024]char sqlInfoToken[1024]char sqlstateMsg[1024]char errorMsg[1024]

if (pSqlca-gtsqlcode = 0 ampamp pSqlca-gtsqlcode = 100)

49

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

strcpy(sqlInfo )if( pSqlca-gtsqlcode lt 0) sprintf( sqlInfoToken n---- error report ----n)

strcat( sqlInfo sqlInfoToken)else sprintf( sqlInfoToken n---- warning report ----n)

strcat( sqlInfo sqlInfoToken) endif

sprintf( sqlInfoToken app message = sn appMsg)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken line = dn line)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken file = sn file)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken SQLCODE = ldn pSqlca-gtsqlcode)strcat( sqlInfo sqlInfoToken)

get error message rc = sqlaintp( errorMsg 1024 80 pSqlca) return code is the length of the errorMsg string if( rc gt 0) sprintf( sqlInfoToken sn errorMsg)

strcat( sqlInfo sqlInfoToken)

get SQLSTATE message rc = sqlogstt( sqlstateMsg 1024 80 pSqlca-gtsqlstate)if (rc == 0) sprintf( sqlInfoToken sn sqlstateMsg)

strcat( sqlInfo sqlInfoToken)

if( pSqlca-gtsqlcode lt 0) sprintf( sqlInfoToken --- end error report ---n)

strcat( sqlInfo sqlInfoToken)printf(s sqlInfo)return 1

else sprintf( sqlInfoToken --- end warning report ---n)

strcat( sqlInfo sqlInfoToken)printf(s sqlInfo)return 0

endif endif

return 0

void TransRollback( ) struct sqlca sqlca

int rc = 0 rollback the transaction printf( nRolling back the transaction n)

EXEC SQL ROLLBACKrc = SqlInfoPrint( ROLLBACK ampsqlca __LINE__ __FILE__)if( rc == 0) printf( The transaction was rolled backn)

50

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

51

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix C mdash Source Listing of testclicpp

Include The Appropriate Header Filesinclude ltsqlclihgtinclude ltsqlcli1hgtinclude ltsqlutilhgtinclude ltsqlenvhgtinclude ltstdiohgt include ltiostreamgt include ltlocalehgt include ltstringhgtdefine SQL_SQLSTATE_SIZE 5define LOOPS 8

using namespace std

Define The CLI_Class Classclass CLI_Class

Attributespublic

SQLHANDLE EnvHandleSQLHANDLE ConHandleSQLHANDLE StmtHandleSQLRETURN rcSQLCHAR Job[6]SQLCHAR Name[10]SQLDOUBLE Comp

Operationspublic

CLI_Class()~CLI_Class()SQLRETURN ShowResults()

Constructor Destructor

SQLRETURN printError( SQLHDBC SQLHSTMT)

Define The Class ConstructorCLI_ClassCLI_Class()

setlocale( LC_ALL )

Initialize The Return Code Variablerc = SQL_SUCCESS

Allocate An Environment Handlerc = SQLAllocHandle(SQL_HANDLE_ENV SQL_NULL_HANDLE ampEnvHandle)

Allocate A Connection Handleif (rc == SQL_SUCCESS)

rc = SQLAllocHandle(SQL_HANDLE_DBC EnvHandle ampConHandle)

Define The Class DestructorCLI_Class~CLI_Class()

Free The Connection Handleif (ConHandle = NULL)

SQLFreeHandle(SQL_HANDLE_DBC ConHandle)

Free The Environment Handle

52

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

if (EnvHandle = NULL)SQLFreeHandle(SQL_HANDLE_ENV EnvHandle)

Define The ShowResults() Member FunctionSQLRETURN CLI_ClassShowResults(void)

While There Are Records In The Result Data Set Generated Retrieve And Display Themcout ltlt Name Job Compensation ltlt endlcout ltlt --------- ------ ------------ ltlt endlcoutsetf(iosleft)coutprecision(2)coutsetf(iosfixed)while (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)

rc = SQLFetch(StmtHandle)if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)

coutwidth(15)cout ltlt Name

coutwidth(10)cout ltlt Job

coutwidth(7)cout ltlt Comp ltltendl

if(rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO ampamp rc = SQL_NO_DATA)printError(ConHandle StmtHandle)

else

rc = 0SQLCloseCursor(StmtHandle)

Return The ODBC API Return Code To The Calling Functionreturn(rc)

SQLRETURN CLI_ClassprintError (SQLHDBC hdbc

SQLHSTMT hstmt)

SQLCHAR buffer[SQL_MAX_MESSAGE_LENGTH + 1]SQLCHAR sqlstate[SQL_SQLSTATE_SIZE + 1]SQLINTEGER sqlcodeSQLSMALLINT lengthSQLRETURN rcwhile ((rc = SQLError(SQL_NULL_HENV hdbc hstmt

sqlstateampsqlcodebufferSQL_MAX_MESSAGE_LENGTH + 1amplength)) == SQL_SUCCESS || rc ==

SQL_SUCCESS_WITH_INFO)

cout ltlt SQLSTATE ltlt sqlstate ltlt endlcout ltlt SQLCODE ltlt sqlcode ltlt endlcout ltlt Error msg ltlt buffer ltlt endl

53

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

cout ltlt----------------------------- ltlt endl ltlt endl

return(SQL_ERROR)

----------------------------------------------------------------- The Main Function -----------------------------------------------------------------int main()

Declare The Local Memory Variables

(SQLCHAR ) db2user SQL_NTS (SQLCHAR ) test26t SQL_NTS)

SQLRETURNSQLCHARSQLCHARSQLCHARchar

SQLCHAR

rc = SQL_SUCCESSDBName[10] = TPLXSQLStmt[255]c[10]ptrcurrentDepartment[8][15] = Head Office

New England Mid Atlantic South Atlantic Great Lakes PlainsPacificMountain

Create An Instance Of The CLI_Class ClassCLI_Class Example

Connect To iSeries Database if (ExampleConHandle = NULL)

rc = SQLConnect(ExampleConHandle DBName SQL_NTS

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)ExampleprintError(ExampleConHandle SQL_NULL_HSTMT)

return(rc)

cout ltlt Successfully connected to ltlt DBName ltlt ltlt endlrc = SQLSetConnectAttr(ExampleConHandle SQL_ATTR_AUTOCOMMIT

(SQLPOINTER) SQL_AUTOCOMMIT_OFF SQL_IS_UINTEGER) Allocate An SQL Statement Handlerc = SQLAllocHandle(SQL_HANDLE_STMT ExampleConHandle

ampExampleStmtHandle)if (rc == SQL_SUCCESS)

Define A SELECT SQL Statement

strcpy((char ) SQLStmt select name job salary + ifnull(comm0) ascompensation )

ptr = strcat( (char ) SQLStmt from org o staff s )ptr = strcat( (char ) SQLStmt where odeptnumb = sdept)ptr = strcat( (char ) SQLStmt and deptname = )ptr = strcat( (char ) SQLStmt order by compensation desc)

Prepare The SQL Statementrc = SQLPrepare(ExampleStmtHandle SQLStmt SQL_NTS)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)ExampleprintError(ExampleConHandle ExampleStmtHandle)

54

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

return(rc)

Bind The Columns In The Result Data Set Returned To Application Variables

rc = SQLBindCol(ExampleStmtHandle 1 SQL_C_CHAR (SQLPOINTER)ExampleName sizeof(ExampleName) NULL)

rc = SQLBindCol(ExampleStmtHandle 2 SQL_C_CHAR (SQLPOINTER)ExampleJob sizeof(ExampleJob) NULL)

rc = SQLBindCol(ExampleStmtHandle 3 SQL_C_DOUBLE (SQLPOINTER)ampExampleComp sizeof(ExampleComp) NULL)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO) ExampleprintError(ExampleConHandle ExampleStmtHandle)

return(rc)

while (true)

for (int i = 0 i lt LOOPS i++)

rc=SQLBindParameter(ExampleStmtHandle1SQL_PARAM_INPUTSQL_C_CHARSQL_CHAR

150(SQLPOINTER) currentDepartment[i8]0NULL)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)

ExampleprintError(ExampleConHandle ExampleStmtHandle)return(rc)

rc = SQLExecute(ExampleStmtHandle)if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)

ExampleprintError(ExampleConHandle ExampleStmtHandle)return(rc)

cout ltlt endl ltlt Current Dept ltlt currentDepartment[i8] ltlt

endl Display The Results Of The SQL QueryExampleShowResults()if(rc = 0)break

if ( i500 == 0 ampamp i gt 0 )cout ltlt Loops ltlt i ltlt ltlt endl

cout ltlt AFTER ltlt LOOPS ltlt loops Press X to exit ltlt endlcin gtgt cif (c[0] == x || c[0] == X)

break

Free The SQL Statement Handleif (ExampleStmtHandle = NULL )

SQLFreeHandle(SQL_HANDLE_STMT ExampleStmtHandle) Disconnect From The Northwind Sample Databaserc = SQLDisconnect(ExampleConHandle)

Return To The Operating Systemreturn(rc)

55

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

CLASSPATH=homecodeJTOpenjt400jarCLASSPATH=$CLASSPATHhomecodefscontextproviderutiljarCLASSPATH=$CLASSPATHhomecodefscontextfscontextjarCLASSPATH=$CLASSPATHhomecodeJTOpenjdbc2_0-stdextjarexport CLASSPATH

To compile the source use the following command in the AIX partition

javac TestJDBCjava

Although the TestJDBC application is fairly simple it illustrates several important aspects of efficient JDBC programming for DB2 UDB for iSeries

Connection PoolingA JDBC connection can be obtained through either the DataSource or DriverManager object Either method involves significant overhead A fairly large amount of system resources is required to create and maintain the connection and then release it when it is no longer needed JTOpen allows a developer to establish a pool of database connections that can be shared by multiple client applications Connection pooling can improve the response time because the connection pool manager can locate and use an existing connection When the database request is completed the connection returns to the connection pool for reuse

In the JDBCTest sample JNDI was first used to register a connection pool-capable data source Heres an excerpt from the deployDataSource method of the sample application

Hashtable env = new Hashtable()envput(ContextINITIAL_CONTEXT_FACTORY

comsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env) [1]

Register an AS400JDBCConnectionPoolDataSource objectAS400JDBCConnectionPoolDataSource tkcpds = newAS400JDBCConnectionPoolDataSource() [2]tkcpdssetServerName(serverName) tkcpdssetDatabaseName(databaseName) tkcpdssetUser(userName) tkcpdssetPassword(password) tkcpdssetDescription(Toolkit Connection Pooling DataSourceobject) hellip ctxrebind(jdbcToolkitDataSource tkcpds) [3]

At [1] the initial JNDI context is created

Then at [2] an AS400JDBCConnectionPoolDataSource object is instantiated This is the JTOpen implementation of the javaxsqlConnectionPoolDataSource interface An AS400JDBCConnectionPoolDataSource object supports a number of methods that can be used to set iSeries-specific properties of the underlying DataSource object Some of these properties will be discussed in greater detail in the following sections of this paper

At [3] the data source object is bound to an arbitrary name that will be used in the main application Note that the deployDataSource method needs to be executed just once unless some of the data source properties need to be changed In that case the developer would need to rebind

7

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

The JNDI registered data source is then used in the main application to initialize the connection pool

AS400JDBCConnectionPoolDataSource tkcpds = [1](AS400JDBCConnectionPoolDataSource)ctxlookup(jdbcToolkitDataSource) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPool pool = newAS400JDBCConnectionPool(tkcpds)[2] Adds 1 connection to the pool that can be used by the application(creates the physical database connections based on the datasource)poolfill(1) [3] hellip con = poolgetConnection()[4]

At [1] the JNDI service is used to instantiate the AS400JDBCConnectionPoolDataSource

Then at [2] an AS400JDBCConnectionPool object is created This object is responsible for managing the connection pool

At [3] the connection pool is initialized with one connection

The pool object is used at [4] to obtain a database connection There are several additional things the developer should know about this code snippet

bull The advantage of using JNDI to register the data source object as opposed to just instantiating it in the main method is that in a more realistic scenario the data source would be registered just once at application deployment time Additionally the data source properties do not have to be hard-coded in the main method and can be changed at any time and then rebound without affecting the application

bull The AS400JDBCConnectionPool is a proprietary JTOpen implementation of a connection pool Specifically it does not implement the Referenceable interface and thus cannot be bound through JNDI services

bull The JTOpen AS400JDBCConnectionPoolDataSource does not support statement caching as described in the JDBC 30 specification Statement caching is implemented through SQL packages This feature is covered in the following section

Note The native iSeries JDBC driver supports both connection pooling and statement caching in a JDBC 30 compliant manner

8

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Extended Dynamic SQL and Statement Caching As mentioned the JTOpen data source object supports a number of properties that can be used to fine-tune the database performance In this section properties used to enable extended dynamic SQL support (see DB2 SQL Runtime Interfaces section above) and local statement caching will be discussed

Here is a relevant code excerpt from the deployDataSource method

AS400JDBCConnectionPoolDataSource tkcpds = new AS400JDBCConnectionPoolDataSource() hellip tkcpdssetExtendedDynamic(true)[1]tkcpdssetPackage(JDBCDS) [2]tkcpdssetPackageCache(true) [3]tkcpdssetPackageCriteria(select) [4]

At [1] the extended dynamic SQL support is enabled Note that the default is disabled for JTOpen The extended dynamic SQL functionality is often referred to as SQL package support The SQL packages are server-side repositories for SQL statements Packages contain the internal structures such as parse trees and access plans which are needed to execute SQL statements Because SQL packages are a shared resource the information built when a statement is prepared is available to all the users of the package This saves processing time especially in an environment where many users are using the same or similar statements Also because SQL packages are permanent this information is saved across job initiationtermination and IPLs In fact SQL packages can be saved and restored on other servers

At [2] the SQL package is named Note that the actual package name on the iSeries server is JDBCDSBAA The package name is generated by taking the name specified on the client and appending three letters that are an encoded set of the package configuration attributes By default an SQL package does not contain unparameterized select statements This behavior is overridden at [4] by setting the PackageCriteria property to select

At [3] the local statement cache is enabled A copy of the SQL package is cached on the AIX client This may improve application performance in a way similar to JDBC 30 statement caching Note however that local statement caching is not recommended for large SQL packages The copy of an SQL package is cached when the database connection is obtained This may cause increased network traffic as well as slow down the connection setup time

Reusable Open Data Paths (ODPs)An Open Data Path (ODP) definition is an internal i5OS object that is created when certain SQL statements (such as OPEN INSERT UPDATE and DELETE) are executed for the first time in a given job (or connection) The ODP can be thought of as a runtime implementation of an access plan The access plan created at the optimization time provides a recipe or in other words a sequence of steps necessary to execute the statement The ODP on the other hand provides the executable code for all requested IO operations The process of creating new ODP objects is fairly CPU- and IO-intensive so whenever possible the iSeries DB2 runtime tries to reuse existing ODPs For instance a ResultSetclose() call may close the SQL cursor but leave the ODP available to be used the next time the cursor is opened This can significantly reduce the response time in running SQL statements A reusable OPD usually requires 10 to 20 times less CPU resources than a newly created ODP Therefore it is important that the applications employ programming techniques that allow the DB2 runtime to reuse ODPs

With dynamic programming interfaces such as JDBC the most efficient way to avoid full opens is to employ the so-called prepare once execute many programming paradigm Ideally an SQL statement that is executed more than once should be prepared just once mdashfor example in the class constructor mdash and then reused for the consecutive executions At the prepare time the

9

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 engine stores the prepared statement along with the associated statement name in the QZDASOINIT jobs statement cache On the first execution the ODP created for a given statement is associated with the appropriate entry in the statement cache On consecutive executions the prepared statement and the corresponding ODP can be quickly located in the statement cache and reused The code snippet below illustrates the prepare once execute many programming technique

PreparedStatement pstmt = conprepareStatement(INSERT INTO COFFEES VALUES( ))[1] hellip for (int i = 0 i lt outerNumOfLoops i++)

insertfor (int j = 0 j lt numOfLoops j++)

pstmtsetString(1 Lavaza_ + IntegertoString(j)) hellip pstmtaddBatch()

int [] updateCounts = pstmtexecuteBatch()[2]concommit()

At [1] a PreparedStatement pstmt object is instantiated for a parameterized INSERT statement The statement is prepared just once The PreparedStatement object is then repeatedly used at [2] to perform blocked insert

Block Inserts Occasionally the developer may need to initially populate a table or insert a modified result set into a temporary table The efficiency of the insert operation for a large set of records can be dramatically improved by using the executeBatch method rather than the executeUpdate method The JTOpen driver converts parameterized insert statements in an executeBatch method to a block insert statement This significantly reduces the data flow and system resources required to perform the insert The following code snippet shows how to take advantage of the executeBatch method

10

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

PreparedStatement pstmt =conprepareStatement(INSERT INTO COFFEES VALUES( ))[1]for (int j = 0 j lt numOfLoops j++) pstmtsetString(1 Lavaza_ + IntegertoString(j))pstmtsetInt(2 i)pstmtsetFloat(3 499f)pstmtsetInt(4 0)pstmtsetInt(5 0)pstmtaddBatch() [2]

int [] updateCounts = pstmtexecuteBatch() [3]

At [1] a parameterized insert statement is prepared Note that all columns must be parameterized Otherwise the executeBatch method may throw the SQL0221 Number of rows 1 not valid exception In other words the developer should not mix parameter markers with literals or special registers in the VALUE clause

At [2] the addBatch method is used to add a new record to the client record buffer

At [3] all locally buffered data is sent to the server which in turn performs a block insert

Figure 4 shows the performance data for the executeBatch and executeUpdate methods

Figure 4 executeBatch() versus executeUpdate() performance comparison

11

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

WebSphere Considerations In certain situations an application provider may decide to deploy WebSphere Application Server in an AIX partition rather than natively in i5OS At the same time the application uses DB2 UDB for iSeries as an back-end database server Typically the WebSphere Application Server running in the AIX partition uses the virtual LAN to communicate with DB2 UDB for iSeries The WebSphere applications will access the database through a remote JDBC connection For performance and functionality reasons IBM recommends to utilize in such environments the IBM Toolbox for Java JTOpen driver Most of the tips and techniques described so far in this document hold true for WebSphere applications accessing DB2 UDB for iSeries There are however certain JDBC access aspects that are specific to this multi-tier architecture Letrsquos have a closer look at some of these considerations

Connection Pooling and Statement Caching

WebSphere Application Server provides its own connection pooling and statement caching mechanism that is by default enabled so that WebSphere applications automatically enjoy the performance benefits of these two critical programming techniques See the following link to learn more about the optimal connection pool setting in WebSphere

httppublibboulderibmcomwas40051englishinforzaiz51adminhelpudat_conpoolsethtml

Extended Dynamic SQL

For non-JTA connections WebSphere Application Server uses the comibmas400accessAS400JDBCConnectionPoolDataSource class as the iSeries JDBC provider implementation This is the DataSource implementation that has been used in all previous coding examples As mentioned the class supports a range of iSeries specific properties that can be used to fine tune JDBC performance These properties can be set through the WebSphere Application Server admin console For example herersquos the procedure to enable the extended dynamic SQL support In the WebSphere Application Server admin console navigate to the Data Source configuration dialog by selecting JDBC Providers -gt iSeriesToolbox -gt Data Sources then scroll down to the Additional Properties section Select Custom Properties link The Custom Properties dialog opens Scroll down to find the Extended Dynamic property and select it Change the default value false to true save the new configuration by clicking Apply button This is illustrated in Figure 5

12

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 5 Enabling the extended dynamic SQL through WebSphere Application Server console

The WebSphere Application Server needs to be restarted for the change to take effect The similar procedure can be followed to set other iSeries Data Source properties

Changing the WebSphere Application Server default isolation level

WebSphere Application Server V5 uses the REPEATABLE_READ (RR) isolation level for all implicit (WebSphere Application Server managed) transactions With the RR isolation level the rows selected updated deleted and inserted are locked until the end of the transaction Under certain circumstances this fairly extensive locking policy may cause locking contention especially when a WebSphere application competes for database resources with other applications that run on iSeries server For example a legacy order entry application may share data with the e-business customer care application running in WebSphere The locking contention may sometimes be eliminated by lowering the isolation level used by WebSphere Although the iSeries Data Source supports the custom transactionIsolation property resetting this property on the Data Source object will not change the default isolation level used by WebSphere for the connection objects produced by that Data Source In other words WebSphere will override the Data Source isolation level setting at the time the connection is obtained by a WebSphere application object such as servlet or Enterprise Java Bean (EJB) In order to change the default WebSphere behavior one must use the resource referencing Resource referencing allows a programmer to lookup DataSource or EJB objects using alias names rather than JNDI names Additionally by creating a resource reference a programmer can change certain properties of the underlying object Specifically a DataSource reference can be used to set a different isolation level for the connections produced by this database resource Typically resource references are defined by a programmer in a application development tool such as WebSphere Studio Application Developer The method to specify a DataSource reference differs depending on whether a programmer plans to use the reference in a servlet or in an EJB Letrsquos start with outlining the configuration process for a servlet In WebSphere Studio Application Developer open the deployment descriptor editor for the web project that contains the servlet To do so double click on the webxml file under WEB-INF directory in the web project In the deployment editor dialog select the References tab and then select Resource tab located in the top of the dialog that appears Under Resource References section select the Add button Herersquos an example of a DataSource reference created for iSeries DataSource named TestJDBCDS Note that the reference changes the default isolation level to READ_COMMITTED

13

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 6 Defining a resource reference for a servlet

Once the resource reference has been defined and saved the servlet source code needs to be changed to reflect the fact that a resource reference is used to obtain a DataSource from the JNDI service Herersquos the relevant code snippet try

ctx = new InitialContext() ds = (DataSource)ctxlookup(javacompenvTestJDBCJ2C)

catch (Exception e) eprintStackTrace(out)

Now the ds DataSource object will produce connections that by default run with the isolation level of READ_COMMITTED (RC)

As mentioned the process of defining a resource reference for an EJB differs from the process that is used in the case of a servlet In WebSphere Studio Application Developer open the deployment descriptor editor for the EJB project that contains the EJB To do so double click on the ejb-jarxml file under WEB-INF directory in the project In the deployment editor dialog select the References tab In the references section on the left locate and select the EJB for which the developer wants to change the default isolation level Click the Add button The Add Reference dialog opens Click the Resource Reference radio button and then Next Define the reference following the example shown in Figure 7

14

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 7 Adding a resource reference for an EJB

When you click ldquoFinishrdquo the reference definition is added to the EJB descriptor The new definition needs to be further modified To do so click on the (+) sign next to the EJB in the References list Click the new reference TestJDBCJ2C in this example to open the properties for the reference Change WebSphere Bindings and WebSphere Extensions sections as illustrated in Figure 8

15

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 8 Defining a resource reference for an EJB

Save the modified definition and then change the EJB source code to use the reference rather than directly DataSource

TroubleshootingTroubleshooting a multi-tier application may be a bit tricky because the developer needs to deal with software components that reside in separate partitions Three tools are particularly useful for pinning down the potential problem areas bull Joblog messages for a database server job mdash Provides enough details to isolate DB2 UDB for

iSeries runtime issues bull JDBC trace utility mdash Provides granular information about the data flow between the AIX

application and the iSeries server job bull Database Monitor ndash Provides detailed SQL runtime trace

Job Log MessagesAs mentioned a DB2 client communicates with a corresponding iSeries server job This server job runs the SQL requests on behalf of the client The iSeries database server jobs are called QZDASOINIT and they run in the QUSRWRK subsystem At any given time a large number of database server jobs may be active on the server so the first step is to identify the job that serves the particular client connection The easiest method to accomplish this task is to run the following CL command from the i5OS prompt

WRKOBJLCK OBJ(DB2USER) OBJTYPE(USRPRF)

Here DB2USER is the user profile that is used to connect to the iSeries server Note that a QZDASONIT job is assigned to a client after the connection has been established so the developer needs to set a breakpoint in the client application after the database connection has been established

Once the Work with Object Locks appears key in 5 (Work with Job) next to the only QZDASOINIT job that should be listed This shows the Work with Job dialog Select option 10 to

16

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

display the job log for the database server job Now the job log can be searched for any error messages generated by the DB2 runtime

Sometimes it is also useful to include debug messages in the job log The debug messages are informational messages written to the job log about the implementation of a query They describe query implementation methods such as the use of indexes join order ODP implementation (reusable versus non-reusable) and so on The easiest way to instruct an iSeries server to include the debug messages is to set the ServerTraceCategories property on the data source object

tkcpdssetServerTraceCategories(AS400JDBCDataSourceSERVER_TRACE_DEBUG_SERVER_JOB)

A sample of the job log messages with debug messages enabled is shown below

SET TRANSACTION completeSTATEMENT NAME FOUND QZ868F0A458E13AF8C Starting optimizer debug message for query Arrival sequence access was used for file COFFEESODP created ODP not deleted 5000 rows inserted in COFFEES in DB2USER STATEMENT NAME FOUND QZ868F0A4C144BF12EBlocking used for queryCursor CRSR0001 opened606 rows fetched from cursor CRSR0001 ODP not deleted Cursor CRSR0001 closed

So the job log offers fairly detailed information on how the AIX client requests were implemented by the DB2 runtime

JDBC Trace UtilityThe JTOpen driver provides a tracing utility which can be used to collect detailed client-side traces The JDBC tracing is turned off by default It can be enabled by setting the Trace property to true Heres an example of how to switch on tracing using the setTrace method on the data source object

tkcpdssetTrace(true)

The trace can also be enabled when using the DriverManagergetConnection() method for obtaining a connection to DB2 UDB for iSeries In this case the developer could add the trace property to the connection string This approach is illustrated in the following code snippet

ClassforName(comibmas400accessAS400JDBCDriver) [1] hellip con = DriverManagergetConnection(jdbcas400teraplextrace=true

db2userdb2pwd) [2]

At [1] an instance of the JTOpen JDBC Driver is initiated Then at [2] the driver is used to obtain a connection to the iSeries server Note how the trace property has been added to the database URL See the IBM Toolbox for Java JDBC properties documentation on the iSeries Information Center Web site for a complete list of properties supported by the JTOpen driver

Although the level of details provided by the trace utility is sufficient in most troubleshooting scenarios sometimes the developer may need to collect low-level traces scoped to a certain type

17

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

of information In V5R3 the IBM Toolbox for Java (as well as the latest JTOpen) added a comprehensive detailed trace facility The following is the complete list of detailed trace parameters and their purpose

bull None or ldquordquo ndash This setting disables the detailed trace bull datastream - This category is used by Toolbox classes to log dataflow between the local host

and the remote system It is not intended for use by application classes bull diagnostic - This category is used to log object state information bull error - This category is used to log errors that cause an exception bull information - This category is used to track the flow of control through the code bull warning - This category is used to log errors that are recoverable bull conversion - This category is used by Toolbox classes to log character set conversions

between Unicode and native code pages bull proxy - This category is used by Toolbox classes to log data flow between the client and the

proxy server bull pcml - This category is used to determine how PCML interprets the data that is sent to and

from the server bull jdbc - This category is used to track JDBC calls throughout the program bull thread - This category is used to enable tracing of thread information This is useful when

debugging multi-threaded applications bull all - This category will enable all previous categories

The detailed trace can be enabled when using the DriverManagergetConnection() method for obtaining a connection to DB2 UDB for iSeries In this case the developer could add the toolbox trace property to the connection string This is illustrated in the following code sample

String dbUrl = jdbcas400pwd1toolbox trace=diagnostic con = DriverManagergetConnection(dbUrl dbUser dbPassword)

Note that currently the driverrsquos DataSource interfaces do not allow the developer to directly activate the detailed tracing However they could set the server from the command line at the time the java program is launched The example below shows how the detailed trace properties could be enabled at the command line

java -Dcomibmas400accessTracecategory=diagnostic TestJDBC

The -D switch indicates to the java interpreter that the information following it will be a system property

In case of a WebSphere application the trace property can be set through the admin console In the console select Application Servers-gt server1-gt Process Definition -gt Java Virtual Machine Figure 9 shows how to set the Generic JVM Arguments for an application server instance

18

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 9 Setting JVM arguments to enable detailed Toolbox tracing

Database Monitor

The database monitor is the ultimate tool available on DB2 UDB for iSeries to collect low-level SQL traces It is mainly used to pin down the SQL performance problems Refer to the lsquoUsing iSeries Database Monitor to Identify and Tune SQL Queriesrsquo white paper for a detailed discussion on how to collect and analyze the database monitor traces httpibmcomserversenablesiteeducationiborecordhtmldtmon

IBM DB2 JDBC Universal Driver DB2 JDBC Universal Driver is one of the new features delivered with DB2 UDB Version 8 DB2 JDBC Universal Driver has been designed to eliminate the dependency on DB2 CLI runtime modules as well as to enable direct Type 4 connectivity to DB2 UDB for iSeries and DB2 UDB for zOSreg

The pure-Java (Type 4) remote connectivity is based on the DRDA open distributed protocol for cross-platform access to DB2 DRDA defines the rules the protocols and the semantics for accessing distributed data Applications can access data in a distributed relational environment by using SQL statements The iSeries DRDA application server implementation is based on multiple connection-oriented server jobs running in the QSYSWRK subsystem A DRDA listener job (QRWTLSTN) listens for TCP connect requests on port 446 Once an application requester connects to the listener job the listener wakes up one of the QRWTSRVR prestart jobs and assigns it to a given client connection Any further communication occurs directly between the client application and the QRWTSRVR job These concepts are illustrated in Figure 10

19

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 10 Accessing DB2 UDB for iSeries with DB2 Universal Driver

The DB2 Universal Driver can be loaded in an AIX partition by installing one of the DB2 Connect for AIX products (see the Additional Information section for details) It is also a part of a DB2 Enterprise Server Edition for AIX install Specifically the developer needs three JAR files in a AIX partition to successfully connect to an iSeries server db2jccjar db2jcc_license_cisuzjar and db2jcc_license_cujar The iSeries license is contained in db2jcc_license_cisuzjar Note that this file is not a part of DB2 Client In other words a DB2 Connect license is required to use the driver in production environments The location of the JAR files needs to be added to the CLASSPATH environment variable For instance the following entry could be added to the AIX profile script

CLASSPATH=homedb2inst2sqllibjavadb2jccjarCLASSPATH=$CLASSPATHhomedb2inst2sqllibjavadb2jcc_license_cujarCLASSPATH=$CLASSPATHhomedb2inst2sqllibjavadb2jcc_license_cisuzjarexport CLASSPATH

Java Runtime 131 is a prerequisite

Additionally the developer should install the latest database group PTF (SF99503 for i5OS V5R3) on the iSeries server The Informational APAR ii13348 is keeping track of any fixes relevant to DRDA above and beyond the current database group PTF

Obtaining a Connection to DB2 UDB for iSeries When Type 4 connectivity is used the DB2 Universal Driver connects directly to the DB2 on iSeries through TCPIP Note that this is different from the legacy DB2 Type 2 JDBC driver that requires a DB2 node and remote database configurations on the client accessing iSeries The following code snippet illustrates how to use the DB2 JDBC Universal Driver to obtain a connection to DB2 UDB for iSeries

20

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

try ClassforName(comibmdb2jccDB2Driver) [1] catch(javalangClassNotFoundException e) Systemerrprint(ClassNotFoundException )Systemerrprintln(egetMessage())

try DriverManagergetConnection(jdbcdb2teraplex446TERAPLEX[2]

db2userdb2pwd) hellip catch(SQLException ex) Systemerrprintln(

SQLException + exgetMessage())

At [1] an instance of the DB2 JDBC Universal Driver is instantiated Then at [2] the driver is used to obtain a connection to the iSeries server Note the proper form of the database URL required by the driver

Considerations There are several advantages of DB2 JDBC Universal Driver bull Ease of cross-platform development mdash Consistent coding techniques and consistent error

codes and messages bull Ease of deployment mdash Pure Java (no runtime client required) and a single driver for accessing

DB2 on different platforms

The ease of use comes at a price though The iSeries JTOpen driver is optimized for accessing DB2 UDB for iSeries data and it uses native iSeries protocol to communicate with the back-end database server job This usually results in better performance and more-efficient system resources utilization For instance when using the DB2 JDBC Universal Driver to access an iSeries server the executeBatch method results in a single record insert There are also some restrictions when using DB2 Universal JDBC Driver with Type 4 connectivity

bull Support for distributed transactions (JTA) is not enabled bull Driver built-in connection pooling is not supported

Refer to Java application support in DB2 for more details on DB2 JDBC Universal Driver

21

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 Connect data access This section will explore the most important aspects of DB2 Connect ndash iSeries integration - including configuration tips and coding examples

DB2 Connect provides functionality for accessing data stored in DB2 UDB for iSeries as well as DB2 UDB for zOS and DB2 UDB for OS390reg DB2 Connect offers capabilities to access DB2 family members via several SQL interfaces gateway functions such as connection pooling and federated database functionality Many applications supporting the DB2 family of products leverage DB2 Connect as a key middleware component DB2 Connect is offered as separate AIX license products

Enterprise Edition Application Server Edition

In addition to DB2 Connect there are several other DB2 UDB Version 81 products that are supported on AIX

DB2 Universal Database Enterprise Server Edition DB2 Universal Database Workgroup Server Unlimited Edition DB2 Universal Database Workgroup Server Edition DB2 Universal Database Universal Developers Edition All Clients

The DB2 Connect Enterprise Edition functionality is also contained in DB2 Enterprise Server Edition for AIX

22

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 Connect in a nutshell In the scenario described in this paper the DB2 Connect functions contained in DB2 Enterprise Edition for AIX are utilized DB2 Connect Enterprise Edition provides support for both local and remote DB2 clients This is illustrated in Figure 11 Accessing DB2 UDB for iSeries with DB2 Connect

Figure 11 Accessing DB2 UDB for iSeries with DB2 Connect

DB2 Connect implements the Distributed Relational Database Architecturetrade (DRDAreg) to reduce the cost and complexity of accessing data stored in DB2 UDB for iSeries and other DRDA-compliant database servers DRDA defines the rules the protocols and the semantics for accessing distributed data Applications can access data in a distributed relational environment by using SQL statements In a distributed environment the system running the application and sending the SQL requests across the network is called the application requester (AR) A remote database server that executes SQL requests submitted by an application requester is known as the application server (AS) In the example shown in Figure 11 (above) DB2 Connect plays the role of an application requester while DB2 UDB for iSeries is an application server In this case DB2 Connect communicates with the iSeries database through TCPIP The iSeries DRDA application server implementation is based on multiple connection-oriented server jobs running in the QSYSWRK subsystem A DRDA listener job (QRWTLSTN) listens for TCP connect requests on port 446 Once an application requester connects to the listener job the listener wakes up one of the QRWTSRVR prestart jobs and assigns it to a given client connection Any further communication occurs directly between the client application and the QRWTSRVR job

DB2 Connect supports a wide range of programming interfaces that can be used by AIX applications to access the iSeries database Embedded SQL frac34 Both static and dynamic SQL frac34 Various programming languages (Java CC++ Cobol Fortran REXX)

DB2 Call Level Interface (DB2 CLI) ODBC JDBC frac34 DB2 JDBC Type 2 Driver frac34 DB2 JDBC Type 4 Driver (Universal JDBC Driver)

23

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Note that DB2 Connect supports access to DB2 UDB for iSeries through DB2 JDBC Universal driver However for performance and ease of maintenance reasons IBM recommends that Java applications running in AIX use native iSeries Toolbox JDBC driver See the JDBC Data Access section of this paper (above) for more details On the other hand DB2 Connect is a very efficient and robust connectivity option for AIX applications especially in the environments that are not directly supported by the native iSeries JDBC driver Here are several possible scenarios that would require DB2 Connect installed in a AIX partition

Embedded SQL interface is used to access DB2 CLI or ODBC interface is used to access DB2 A single SQL interface is needed to access multiple back end DB2 server Specific DB2 Connect functionality is needed such as distributed join or connection

pooling

Prerequisites One of the DB2 Connect products or DB2 Enterprise Server Edition for AIX V81 is needed Additionally DB2 Application Development Client is required in the AIX partition to compile DB2 applications

For maximum database server stability the developer should install the latest database group PTF (SF99503 for i5OS V5R3) on the iSeries server The Informational APAR ii13348 is keeping track of any fixes relevant to DRDA above and beyond the current database group PTF

DB2 Connect configuration The following example employs i5OS V5R3 and DB2 UDB Enterprise Server Edition for AIX Version 81 FixPak 6

Configuration steps in the iSeries partition The following process lists the necessary steps to be performed on the iSeries server 1) Verify that the TCPIP stack is working correctly It is assumed that the Virtual LAN is used to

communicate with the i5OS partition First obtain the IP address of the iSeries server or its hostname and ping the iSeries server from the AIX partition

2) Create a relational database (RDB) entry for the iSeries database in the i5OS partition If this has already been created it can be displayed by using the DSPRDBDIRE command Make sure that the RDB entry with a location of LOCAL exists on the iSeries server If it does not exist use the ADDRDBDIRE command to add the appropriate RDB entry For example the following command would add an RDB entry named TPLX For simplicity it is recommended that the TCPIP host name and RDB entry remain the same

ADDRDBDIRE RDB(TPLX) RMTLOCNAME(LOCAL)

3) Create a collection called NULLID This is necessary because the utilities shipped with DB2 Connect and DB2 UDB for AIX store their packages in the NULLID collection Since it does not exist by default in the iSeries server you must create it using the following command

CRTLIB LIB(NULLID)

4) Products that support DRDA automatically perform any necessary code page conversions at the receiving system For this to happen both systems need a translation table from their code page to the partner code page The default Coded Character Set Identifier (CCSID) on the iSeries server is 65535 Since DB2 Connect does not have a translation table for this code page the developer needs to change the individual user profiles to contain a CCSID that can be converted properly by DB2 Connect For US English this is 037 For other languages see DB2 Connect Personal Edition Quick Beginning GC09-2967 The following command changes the CCSID for an individual user profile to 037

24

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

CHGUSRPRF userid CCSID(037)

5) Verify that the default port 446 for DRDA service is being used To do this go to the Configure TCPIP menu (CFGTCP) select Configure Related Tables and then select Work with service table entries Verify that the DRDA service is set for port 446

6) The Distributed Data Management (DDM) job must be started for DRDA to work If you want the DDM job to be automatically started whenever TCPIP is started change the attributes of the DDM job using the CHGDDMTCPA command and set the Autostart server parameter to YES

7) If the system administrator chooses not to autostart the server issue the following command to start the DDM server job

STRTCPSVR SERVER(DDM)

8) Make sure that the user profiles that will be used to connect to the iSeries server exist on the server

25

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Configuration steps in the AIX partition The following steps are required for DB2 Connect to be configured in the AIX partition 1) Sign on to the AIX partition as the DB2 administrator 2) Launch Client Configuration Assistant (db2ca from the command prompt) It is assumed that

VNC or an X-Windows server are being used on the workstation so that the db2ca GUI can be properly rendered

3) From the Selected pull-down menu select the Add Database using Wizard option The Select how you want to setup a connection dialog appears Select Manually configure a connection to a database and click Next This is shown in Figure 12

Figure 12 Accessing DB2 UDB for iSeries with DB2 Connect

26

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

4) On the Select a communications protocol choose TCPIP and select The database physical resides on a host or OS400 system Then select the option Connect directly to the server as shown in Figure 13 Click Next

Figure 13 mdash Selecting communications protocol

27

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

5) On the TCPIP tab fill in the host name of the iSeries server The port number should be 446 This is shown in Figure 14 Click Next

Figure 14 mdash Specifying TCPIP communication parameters

28

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

6) On the Database tab fill in the Relational Database name Use the RDB entry name (specified in step 2) in the Configuration steps in the iSeries partition section as shown in Figure 15 Click Next

Figure 15 mdash Specifying the remote database

7) If you plan to use the ODBC applications select Register this database for ODBC as a system data source on the ODBC tab Click Next

29

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

8) On the Specify the node option dialog select OS400 from the Operating System pull-down menu This is shown in Figure 16 Click Finish

Figure 16 mdash Specifying the node options

30

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

9) The Test Connection dialog appears This allows the developer to verify that the connection works Select both CLI and JDBC check boxes You are also prompted for an iSeries user ID and password as shown in Figure 17

Figure 17 mdash Testing the connection

31

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

10) The successful connection to the database server is confirmed by the message box shown in Figure 18

Figure 18 mdash Test Connection results 11) At this time a newly configured database connection should appear in the main DB2

Configuration Assistant window It is recommended that the DB2 utilities are also bound to the iSeries database The bind process creates the necessary SQL packages on the remote database In the main Configuration Assistant window click the TPLX database entry and then select Selected-gtBindhellip

32

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

12) The Bind dialog appears Click Select All and then enter the connection information as shown in Figure 19 Click Bind The Results message box appears This allows the developer to monitor the progress of the binding process Watch for any error and warning messages

Figure 19 mdash Binding the DB2 utilities This concludes the DB2 Connect configuration steps

33

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Accessing DB2 UDB for iSeries from C embedded SQL

As mentioned earlier DB2 Connect allows developers to compile and run embedded SQL applications that access DB2 UDB for iSeries data This section covers implementation details for a C embedded SQL application called cursorsjsqc (see Appendix B for source code)

Prerequisites An embedded SQL application running in an AIX partition will use DB2 Connect services to access DB2 UDB for iSeries therefore the developer needs to make sure that all components listed in section Prerequisites on page 24 are installed The developer also needs to create a remote database connection as described in the DB2 Connect configuration section of this paper on page 24

Static SQL and SQL packages To successfully run against a DB2 UDB for iSeries database an embedded SQL application needs to be first precompiled and bound to the back-end database This process creates an SQL package on the target iSeries server The SQL package contains the access plan information for the SQL statements executed by the application The internal structure of the package as well as the method how its content is used by the SQL runtime to facilitate the access plan reuse is similar to the Extended Dynamic SQL support covered in detail in the Extended Dynamic SQL and Statement Caching section of this paper (on page 9) There are however important differences between the packages created by the extended dynamic SQL support and the packages created for embedded SQL DRDA client applications The extended dynamic SQL packages support dynamic SQL interfaces such as JDBC

that can submit ad hoc SQL statements at the run time The SQL runtime can prepare the dynamic statements and add them to the package On the other hand the DRDA packages are created at the precompile time and contain static SQL In order to add new statements to the package the application needs to be precompiled and rebound again

The extended dynamic SQL package can dynamically grow up to 500MB by allocating new space as required The DRDA packages since they are created at the precompile time have a fix size and do not grow over their life time

Simple embedded SQL application The application is based on a source code provided in the DB2 UDB samples directory typically to be found at homedb2inst1sqllibsamples The cursorsjsqc performs a join between STAFF and ORG tables located in DB2USER schema (library) on the TPLX database server (the source is provided at the end of this paper in Appendix B) The join statement retrieves the DEPTNAME column from ORG NAME column from STAFF and calculates the total compensation for an employee by adding SALARY and COMM columns in STAFF The results are sorted by department name and total compensation Here is the SELECT statement used by the application

SELECT deptname name salary + IFNULL(comm0) as compensationFROM org o staff sWHERE odeptnumb = sdeptORDER BY deptname compensation DESC

The application iterates through the selected records and prints out the data to the standard output device The sample DB2USER schema was created with the following SQL statements

db2 CONNECT TO tplx USER db2user USING mypassworddb2 CALL QSYSCREATE_SQL_SAMPLE(DB2USER)

34

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Make sure that the AIX partition is logged into with the DB2 admin user profile If the defaults were selected at the DB2 installation time this profile name is db2inst1 It is also assumed that DB2USER user exists on the iSeries server and that it has appropriate authority

There are several steps that are required to create an executable for the cursorsjsqc source code First the DB2 PRECOMPILE utility needs to be called The utility creates a bind file that is used to bind the required SQL package to the TPLX database It also converts embedded SQL statements into DB2 run-time API calls and produces a pure C source file that can be processed by an AIX C compiler

db2 CONNECT TO tplx USER db2user USING mypassworddb2 prep cursorsjsqc bindfile

Note that the connect statement is required only if the developer is not already connected to the database on an iSeries server Watch for any error or warning messages returned by the DB2 prep utility The prepare step should produce cursorsjbnd and cursorsjc files in the current directory Now the developer can invoke the bind utility to prepare the statements contained in the bind file and create the package on the target iSeries database server

db2 bind cursorsjbnd

It is assumed that Visual C++ 60 is installed and configured in the AIX partition Refer to the ldquoDeveloping and Porting C and C++ Applications on AIXrdquo redbook for more information on how to use the Visual C++ compiler httpibmcomredbooksabstractssg245674htmlOpen

Use the following commands to compile the C source generated by the precompile utility

xlc -I$INSTHOMEsqllibinclude ndashc cursorsjcxlc ndasho cursorsj cursorsjo -L$INSTHOMEsqlliblib ndashldb2

Run the program from the AIX prompt

cursorsj db2user mypassword

Distributed Join DB2 UDB Version 8 provides core federated server functionality A federated system consists of a DB2 UDB instance that operates as a federated server a database that acts as the federated database one or more data sources and clients (users and applications) that access the database and data sources Federated server permits objects stored in multiple databases to be accessed together in the same query For example a query can refer to a table that resides in DB2 UDB for iSeries and join it to a table stored in DB2 UDB for AIX Such a query would constitute so called distributed join The support for DB2 UDB for iSeries as a federated data source is provided by core federated server functionality directly implemented in DB2 UDB Enterprise Server Edition and DB2 UDB Connect Enterprise Edition All other DB2 UDB family members are also supported directly by core DB2 UDB federated server An additional software product DB2 Information Integratortrade is required to access non-DB2 UDB databases such as Oracle Sybase or Microsoftreg SQL Server Consult the following white papers for a detailed discussion on DB2 federated server support Heterogeneous data access for iSeries applications Version 2 httpibmcomserversenablesiteeducationiborecordhtmlhetdata Fundamentals of IBM DB2 Federated Server and Relational Connect httpwww7bsoftwareibmcomdmddlibrarytecharticle0206purnell0206purnellhtml

35

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Distributed Join Example In this section the steps that are required to configure DB2 UDB for iSeries as a federated data source will be illustrated Then the cursorsjsqc program will be ldquotweakedrdquo so that it executes a distributed join query that accesses data stored on an iSeries server and in the local DB2 UDB for AIX database It is assumed that the developer is familiar with the DB2 federated server concepts

Note Run the following commands from the Command Line Processor prompt Load the utility by executing the db2 command at the AIX prompt 1) First the local DB2 UDB for AIX instance needs to be enabled as a DB2 federated server

This is done by setting the database manager configuration parameter FEDERATED to YES

db2=gt update dbm cfg using FEDERATED YES

The database instance needs to be restarted for the change to take effect

NOTE A federated database is a regular database in a DB2 UDB instance that has the FEDERATED parameter enabled Therefore in this example the SAMPLE database that was created earlier is used as the federated database A new database can also be created using the CREATE DATABASE command

2) Connect to the federated database

db2=gt connect to sample

3) Use the CREATE WRAPPER statement to register a wrapper for the iSeries data source Wrappers are library routines that are used by the federated server to perform operations such as connecting to a data source and retrieving data from it The default wrapper name for DB2 UDB for iSeries is DRDA Here is the command to register the DRDA wrapper

db2=gt create wrapper drda

4) Use the CREATE SERVER statement to register a data source as a server within the federated database The server definition specifies the type and version of the data source and the wrapper used for communications with this data source For the DB2 UDB for iSeries data source the node and the database names are also needed The node and database name parameters have been configured for our TPLX database in the Configuration steps in the AIX partition section (on page 24) Use the following DB2 UDB command to lookup these parameter on the federated server

db2=gt list database directory

In this case the command produced the following output

Database alias = TPLX Database name = DCSE99E1 Node name = NDE9BF76 Database release level = a00 Comment = Directory entry type = Remote Authentication = SERVER Catalog database partition number = -1

36

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Note that the node name is set to NDE9BF76 The name was generated by the Configuration Administrator utility (db2ca)

Here is the command to register the TPLX database as a federated server

db2=gt create server tplx type db2400 version 530 wrapperdrda authorization db2user password mypassword options(nodeNDE9BF76 dbname TPLX)

The command is quite complex so make sure that the syntax is correct

5) Define the user mappings that instructs the federated server what user ID and password should be used when connecting to the iSeries data source

db2=gt create user mapping for user server tplxoptions(remote_authid db2user remote_password mypassword)

Specify the nickname for the iSeries table or view A nickname is an identifier that is used by the federated server to reference an object located at the data source The following command creates a nickname for the STAFF table located in the DB2USER schema on the TPLX database

db2=gt create nickname tplx_staff for tplxdb2userstaff

6) Test the distributed join query

db2=gt SELECT deptname name salary + COALESCE(comm0) ascompensation FROM org o tplx_staff s WHERE odeptnumb =sdept ORDER BY deptname compensation DESC

Note that the native iSeries function IFNULL has been substituted with an equivalent DB2 UDB function COALESCE COALESCE is also supported on iSeries servers For better portability IBM encourages the use of COALESCE rather than IFNULL Note also that the query runs on the federated server rather than on TPLX It accesses the ORG table in the local DB2 UDB for AIX SAMPLE database and the STAFF table that resides in TPLX The federated server performs the necessary distributed join

7) Modify the cursorsjsqc so that it executes a distributed join There are two source code modifications - Change the CONNECT TO statements Now the application needs to connect to the

federated database SAMPLE rather than to TPLX

EXEC SQL CONNECT TO SAMPLEEXEC SQL CONNECT TO SAMPLE USER userid USING passwd

- Modify the select statement so that it performs a distributed join Use the statement (shown in step 6) above Save the new source version as cursordjsqc

- Prepare bind and compile the distributed join version of the program as described in the Simple C embedded SQL application section (on page 34)

db2 prep cursordjsqc bindfiledb2 bind cursordjbndxlc -I$INSTHOMEsqllibinclude ndashc cursordjcxlc ndasho cursordj cursordjo -L$INSTHOMEsqlliblib ndashldb2

37

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

- Run the program from the AIX prompt

cursordj

Connection Pooling and Connection ConcentratorA modern Web-based application typically executes a large number of short-lived transactions Executing a transaction in this environment means establishing a database connection executing a few SQL statements and terminating this connection Creating connections to the database server is a very costly process To reduce the unnecessary workload DB2 Connect implements connection pooling and connection concentrator Connection pooling mechanism allows DB2 Connect to reuse an existing connection infrastructure for subsequent connection requests The connection concentrator is an advanced technology that allows DB2 Connect to serve a potentially very large number of clients with a limited number of database connections This is accomplished by decoupling clients from a particular database connection

Note that currently neither connection pooling nor connection concentrator support DB2 UDB for iSeries Therefore for performance reasons the author strongly recommends that the application server that obtains and drops connections very frequently implements its own database connection pooling mechanism that would assign an existing pooled database connection to a new AIX process or thread

TroubleshootingTroubleshooting a multi-tier application may be a bit tricky because the developer needs to deal with software components that reside in separate partitions The authorrsquos experience shows that two tools are particularly useful for pinning down the potential problem areas The joblog messages for a database server job usually provide enough details to isolate DB2

UDB for iSeries runtime issues The DRDA trace utility provides granular information about the data flow between the AIX

application and the iSeries server job

38

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Job Log MessagesAs mentioned earlier a DB2 client communicates with a corresponding iSeries server job This server job runs the SQL requests on behalf of the client More precisely when a DB2 client submits an SQL statement the statement is passed to a server job that in turn calls the DB2 runtime to execute the statement The results are then reformatted and marshaled to the client The iSeries DRDA server jobs are called QRWTSRVR and they run in the QUSRWRK subsystem At any given time there may be a large number of DRDA server jobs active on the system so the first step is to identify the job that serves the particular client connection The easiest method to accomplish this task is to run the following CL command from the i5OS prompt

WRKOBJLCK OBJ(DB2USER) OBJTYPE(USRPRF)

Here DB2USER is the user profile that is used to connect to the iSeries server Note that a QRWTSRVR job is assigned to a client after the connection has been established so the developer needs to set a breakpoint in the client application below the CONNECT TO statement

Once the Work with Object Locks appears key in 5 (Work with Job) next to the only QRWTSRVR job that should be listed This shows the Work with Job dialog Select option 10 to display the job log for the database server job Now the developer can search the job log for any error messages generated by the DB2 runtime

Sometimes it is also useful to include debug messages in the job log The debug messages are informational messages written to the job log about the implementation of a query They describe query implementation methods such as use of indexes join order ODP implementation (reusable versus non-reusable) and so on The easiest way to instruct the iSeries server to include the debug messages is to call the following stored procedure just after the connection to the iSeries server is established

EXEC SQL call qsysqcmdexc(STRDBGUPDPROD(YES)000000002000000)

A sample of the job log messages with debug messages enabled is shown below in Figure 20

Arrival sequence access was used for file STAFFAccess path suggestion for file STAFFQuery options used to build the OS400 query access plan Ending debug message for query ODP created Blocking used for queryCursor SQLCUR201 opened1 rows fetched from cursor SQLCUR201Row not found for SQLCUR201ODP deleted Cursor SQLCUR201 closedDESCRIBE of prepared statement STMT0201 completed

Figure 20 mdash Joblog with debug messages enabled

So the job log offers fairly detailed information on how the AIX client requests were implemented by the DB2 runtime

39

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 DRDA trace utilityThe DB2 DRDA trace utility (db2drdat) provides detailed information about the data streams exchanged between DB2 Connect and target database server The output file produced by the utility contains send and receive communications buffers TCPIP error messages and SQL Communications Area (SQLCA) information Please refer to lsquoDB2 Connect Userrsquos Guidersquo manual for in-depth discussion of the DRDA trace utility

Accessing DB2 UDB for iSeries from CLI DB2 Call Level Interface (CLI ) is based on the Microsoft Open Database Connectivity (ODBC) specification and the ISO CLI standard The DB2 CLI interface gained popularity among DB2 application providers because the developer can build an ODBC application by simply linking the application with libdb2 library on a UNIX server In other words the developer directly utilizes the DB2 ODBC driver services without a need for an ODBC driver manager Additionally in contrast to embedded SQL the developer does not need to precompile or bind DB2 CLI applications because they use packages provided with DB2 UDB The developer simply compiles and links the application

Prerequisites A DB2 CLI application running in an AIX partition will use DB2 Connect services to access DB2 UDB for iSeries therefore make sure that all components listed in Prerequisites section of this paper on page 24 are installed The developer also needs to create a remote database connection as described in the DB2 Connect configuration section of this paper on page 24

Dynamic SQL and Access Plan Caching A DB2 CLI client application uses the dynamic SQL interface and does not have the capability to utilize the extended dynamic SQL support Therefore it runs lsquopurersquo dynamic SQL statements That does not mean however that the process of parsing validating and optimizing will be repeated for every execution of a given dynamic SQL statement

The DB2 UDB for iSeries database implements an internal object called System-Wide SQL Statement Cache (SWSC) The SWSC can improve the performance of programs using dynamic SQL statements by caching the access plans in a system-wide cache When a dynamic SQL statement is submitted the SQL runtime searches the SWSC to see if this statement has been previously executed If so then DB2 retrieves and reuses the key information associated with the cached statement and thereby the processing time and the resources utilization can be significantly reduced

Simple DB2 CLI C++ ApplicationThis section covers DB2 CLI implementation details for a sample C++ program called testclicpp (the source is provided at the end of this paper in Appendix C) To compile the source with Visual C++ complier use the following command in the AIX partition

xlC ndashI$INSTHOMEsqllibinclude ndashc testclicppxlC ndasho testcli testclio ndashL$INSTHOMEsqlliblib ndashldb2

The application performs a join between STAFF and ORG tables located in DB2USER schema (library) The join statement retrieves the DEPTNAME column from ORG NAME and JOB columns from STAFF and calculates the total compensation for an employee by adding SALARY and COMM columns in STAFF The results are sorted by total compensation The selection criterion is based on the current value of the department name parameter Here is the SELECT statement used by testcli

40

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

select name job salary + coalesce(comm0) as compensationfrom org o staff swhere odeptnumb = sdeptand deptname = order by compensation desc

Figure 21 shows the software components involved in the execution of this sample application

Figure 21 How a DB2 CLI client accesses DB2 UDB on an iSeries server

Although the testcli application is fairly simple it covers some important aspects of efficient CLI programming for DB2 UDB for iSeries

Reusable Open Data Paths (ODPs)An Open Data Path (ODP) definition is an internal i5OS object that is created when certain SQL statements (such as OPEN INSERT UPDATE and DELETE) are executed for the first time in a given job (or connection) The ODP can be thought of as a runtime implementation of an access plan The access plan created at the optimization time provides a recipe or in other words a sequence of steps necessary to execute the statement The ODP on the other hand provides the executable code for all requested IO operations The process of creating new ODP objects is fairly CPU- and IO-intensive so whenever possible the iSeries DB2 runtime tries to reuse existing ODPs For instance a SQLCloseCursor() API call may close the SQL cursor but leave the ODP available to be used the next time the cursor is opened This can significantly reduce the processing and response time in running SQL statements A reusable OPD usually requires 10 to 20 times less CPU resources than a newly created ODP Therefore it is important that the applications employ programming techniques that allow the DB2 runtime to reuse ODPs

With dynamic interfaces such as CLI full opens are avoided by using a prepare once execute many programming paradigm It means that when an SQL statement is going to be executed more than once you should prepare the statement just once and then reuse the prepared

41

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

statements for consecutive executions Although DB2 UDB does try to convert literals to parameter markers so that similar statements can be reused it is a better programming practice to explicitly implement parameter markers That way the chances for reusable ODPs are quite significantly improved The code snippet in Figure 22 illustrates how to implement the prepare once execute many programming technique

Define A SELECT SQL Statementstrcpy((char ) SQLStmt select name job salary + ifnull(comm0) ascompensation )ptr = strcat( (char ) SQLStmt from org o staff s )ptr = strcat( (char ) SQLStmt where odeptnumb = sdept)ptr = strcat( (char ) SQLStmt and deptname = )ptr = strcat( (char ) SQLStmt order by compensation desc) [1]

Prepare The SQL Statementrc = SQLPrepare(ExampleStmtHandle SQLStmt SQL_NTS) [2]

Bind The Columns In The Result Data Set Returned To Application Variablesrc = SQLBindCol(ExampleStmtHandle 1 SQL_C_CHAR (SQLPOINTER)

ExampleName sizeof(ExampleName) NULL)rc = SQLBindCol(ExampleStmtHandle 2 SQL_C_CHAR (SQLPOINTER)

ExampleJob sizeof(ExampleJob) NULL)rc = SQLBindCol(ExampleStmtHandle 3 SQL_C_DOUBLE (SQLPOINTER)

ampExampleComp sizeof(ExampleComp) NULL)

for (int i = 0 i lt LOOPS i++)rc=SQLBindParameter(ExampleStmtHandle

1SQL_PARAM_INPUTSQL_C_CHARSQL_CHAR10(SQLPOINTER) currentDepartment[i8]0NULL) [3]

rc = SQLExecute(ExampleStmtHandle) [4]cout ltlt endl ltlt Current Dept ltlt currentDepartment[i8] ltlt endl Display The Results Of The SQL QueryExampleShowResults()

Figure 22 Use the prepare once execute many programming technique

The error-handling code has been removed for clarity At [1] the statement text is assigned to a variable Note that a parameter marker is used in the WHERE clause The statement is then prepared just once at [2] The current value of the parameter is bound to the prepared statement at [3] The prepared statement is executed at [4] Steps [3] and [4] are repeatedly executed in a for loop

Techniques to Further Improve DB2 CLI Performance Thus far this paper has discussed the techniques used by a sample application to tune the CLI performance However depending on the application architecture other methods of improving CLI performance may be considered

Connection PoolingCurrently the CLI application connecting through DB2 Connect to DB2 UDB for iSeries does not take advantage of the connection pooling mechanism implemented by DB2 Connect Therefore for performance reasons the author strongly recommends that the application server that obtains and drops connections very frequently implements its own database connection pooling mechanism that would assign an existing pooled database connection to a new AIX process or thread

42

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Blocking

For queries which result in returning large data blocks from the iSeries server (usually 32K of data and above) ensure that the database manager configuration parameter RQRIOBLK is set to 32767 This can be done using the Command Line Processor (CLP) as follows

db2 update database manager configuration using RQRIOBLK 32767

TroubleshootingThe experience of the author shows that two tools are particularly useful for pinning down the potential problem areas bull Joblog messages for a database server job usually provides enough details to isolate DB2

runtime issues bull CLI trace utility provides granular information about the data flow between the AIX application

and the database server job

Job Log MessagesThe process of finding and analyzing the job log for a DB2 CLI connection is identical to the process outlined for an embedded SQL application in the Job Log Message section of this paper on page 39

CLI Trace The DB2 CLIODBCJDBC trace utility provides very detailed information about the data streams exchanged between DB2 Connect and target database server Refer to the DB2 Information Center for more information on how to set up and analyze the CLI traces httppublibboulderibmcominfocenterdb2v8luwindexjsptopic=comibmdb2udbdocadc000 7959htm

43

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Trademarks

IBM eServer iSeries AIX AIX 5L i5OS WebSphere DB2 DB2 Universal Database DB2 Connect OS400 zOS OS390 Distributed Relational Database Architecture DRDA and DB2 Information Integration are trademarks or registered trademarks of International Business Machines Corporation in the United States and other countries

Java and all Java-based trademarks are trademarks of Sun Microsystems Inc in the United States other countries or both

Linux is a registered trademark of Linus Torvalds in the United States other countries or both

UNIX is a registered trademark of The Open Group in the United States and other countries

Microsoft and Windows are registered trademarks of Microsoft Corporation in the United States andor other countries

All other registered trademarks and trademarks are properties of their respective owners

IBM makes no commitment to make available any products referred to herein

References in this publication to IBM products or services do not imply that IBM intends to make them available in every country in which IBM operates

Additional Information ITSO offers a Redbook that can be helpful to those who want to learn more about i5OS AIX integration

bull AIX Integration with I5OS on the IBM eServer iSeries Server (SG24-6551)

Jarek Miszczyk is the Senior Software Engineer IBM eServer Solutions Enablement IBM Rochester

[Portions of this white paper reprinted with permission from MC Mag Online published by MC Press LLP httpwwwmcpressonlinecom]

Acknowledgments The author would like to thank the following people for their advice contributions and support on this paper

Bob Bittner IBM Rochester Jon Rush IBM Rochester Prasad Vallurupalli IBM Rochester Neil Willis IBM Rochester

44

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix A Source Listing of TestJDBCjava

package comibmiseriespwdimport javasqlimport javaxnamingimport javautilHashtableimport javautilimport javaxsqlimport comibmas400access

public class TestJDBC public static void main(javalangString[] args)

throws Exception

int numOfLoops = 5000int outerNumOfLoops = 5boolean firstExec = trueConnection conStatement sPreparedStatement psPreparedStatement pstmtdelCallableStatement cstmPreparedStatement pstmtHashtable env = new Hashtable()

envput(ContextINITIAL_CONTEXT_FACTORYcomsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env)Systemoutprintln(Deploying connection pooling data source)deployDataSource() Do the work with connection pooling onlyAS400JDBCConnectionPoolDataSource tkcpds =

(AS400JDBCConnectionPoolDataSource)ctxlookup(jdbcToolkitDataSource) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPool pool = new AS400JDBCConnectionPool(tkcpds) Adds 1 connection to the pool that can be used by theapplication (creates the physical database connections based onthe data source)poolfill(1)Systemoutprintln(nStart timing Toolkit connection pooling)long startTime = SystemcurrentTimeMillis()

for (int i = 0 i lt outerNumOfLoops i++) con = poolgetConnection()consetAutoCommit(false) deleteif ( i == 0)

long startDelete = SystemcurrentTimeMillis()cstm = cstm = conprepareCall(

CALL qsysqcmdexc(CLRPFM FILE(DB2USERCOFFEES) + 000000002800000))

cstmexecuteUpdate()cstmclose()long endDelete = SystemcurrentTimeMillis()Systemoutprintln(Delete all records +

(endDelete - startDelete) + ms elapsed)

45

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

String sqlinstrlong startInsert = SystemcurrentTimeMillis() insert

pstmt =conprepareStatement(INSERT INTO COFFEES VALUES( ))for (int j = 0 j lt numOfLoops j++) pstmtsetString(1 Kona_ + IntegertoString(i))pstmtsetInt(2 150)pstmtsetFloat(3 999f)pstmtsetInt(4 0)pstmtsetInt(5 0)pstmtaddBatch()int [] updateCounts = pstmtexecuteBatch()concommit()pstmtclose()long endInsert = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for + numOfLoops + inserts

+ (endInsert - startInsert)) selectlong startSelect = SystemcurrentTimeMillis()ps = conprepareStatement(SELECT FROM COFFEES)ResultSet rs = psexecuteQuery()rsnext()rsclose()concommit()psclose()long endSelect = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for select +

(endSelect - startSelect))consetAutoCommit(true)conclose()long endTime = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for + outerNumOfLoops +

loops + (endTime - startTime))Systemexit(0)

private static void deployDataSource()throws ExceptionString serverName = teraplex String databaseName = TERAPLEX String userName = db2user String password = db2pwd

Establish a JNDI context and bind the connection pool data sourceHashtable env = new Hashtable()envput(ContextINITIAL_CONTEXT_FACTORY

comsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPoolDataSource tkcpds = new

AS400JDBCConnectionPoolDataSource()tkcpdssetServerName(serverName) tkcpdssetDatabaseName(databaseName) tkcpdssetUser(userName) tkcpdssetPassword(password) tkcpdssetDescription(Toolkit Connection Pooling DataSource)tkcpdssetSavePasswordWhenSerialized(true)tkcpdssetExtendedDynamic(true)

46

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

tkcpdssetPackage(JDBCDS)tkcpdssetPackageCache(true)tkcpdssetPackageCriteria(select)enable the following properties as requiredcpdssetTrace(true)tkcpdssetServerTraceCategories( AS400JDBCDataSourceSERVER_TRACE_DEBUG_SERVER_JOB)

ctxrebind(jdbcToolkitDataSource tkcpds)

47

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix B mdash Source Listing of cursorsjsqc

Source File Name = cursorsjsqc Licensed Materials - Property of IBM (C) COPYRIGHT International Business Machines Corp 1995 2000 2004 All Rights Reserved US Government Users Restricted Rights - Use duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp PURPOSE This sample program demonstrates the use of a CURSOR The CURSOR is processed using static SQL EXTERNAL DEPENDENCIES - Ensure existence of database for precompile purposes - Precompile with the SQL precompiler (PREP in DB2) - Bind to a database (BIND in DB2) - Compile and link with the IBM Cset++ compiler (AIX and OS2) or the Microsoft Visual C++ compiler (Windows) or the compiler supported on your platform For more information about these samples see the README file For more information on programming in C see the - Programming in C and C++ section of the Application Development Guide For more information on building C applications see the - Building C Applications section of the Application Building Guide For more information on the SQL language see the SQL Reference

include ltstdiohgt include ltstdlibhgt include ltstringhgtinclude ltsqlhgtinclude ltsqlenvhgtinclude ltsqldahgtinclude ltsqlcahgt

int SqlInfoPrint( char struct sqlca int char )void TransRollback( void)

define EMB_SQL_CHECK( MSG_STR ) rc = SqlInfoPrint( MSG_STR ampsqlca __LINE__ __FILE__) if ( rc = 0 ) TransRollback( )

return 1

EXEC SQL INCLUDE SQLCA

int main(int argc char argv[])

EXEC SQL BEGIN DECLARE SECTIONchar dname[15]

48

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

char pname[10]double compchar userid[9]char passwd[19]

EXEC SQL END DECLARE SECTION

int rc = 0printf( Sample C program CURSORSJ n )if (argc == 1)

EXEC SQL CONNECT TO TPLXEMB_SQL_CHECK(CONNECT TO TPLX)

else if (argc == 3)

strcpy (userid argv[1])strcpy (passwd argv[2])EXEC SQL CONNECT TO TPLX USER userid USING passwdEMB_SQL_CHECK(CONNECT TO TPLX)

else

printf (nUSAGE cursor [userid passwd]nn)return 1

endif

EXEC SQL DECLARE c1 CURSOR FORselect deptname name salary + ifnull(comm0) as compensationfrom org o staff swhere odeptnumb = sdeptorder by deptname compensation desc

EXEC SQL OPEN c1EMB_SQL_CHECK(OPEN CURSOR)

printf(DEPARTMENT NAME COMPENSn)printf(-----------------------------------n)do

EXEC SQL FETCH c1 INTO dname pname compif (SQLCODE = 0) breakprintf( -1515s -1010s 72fn dname pname comp )

while ( 1 )

EXEC SQL CLOSE c1EMB_SQL_CHECK(CLOSE CURSOR)

EXEC SQL CONNECT RESETEMB_SQL_CHECK(CONNECT RESET)

exit(0)

end of program CURSORSJSQC

int SqlInfoPrint( char appMsgstruct sqlca pSqlcaint linechar file )

int rc = 0char sqlInfo[1024]char sqlInfoToken[1024]char sqlstateMsg[1024]char errorMsg[1024]

if (pSqlca-gtsqlcode = 0 ampamp pSqlca-gtsqlcode = 100)

49

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

strcpy(sqlInfo )if( pSqlca-gtsqlcode lt 0) sprintf( sqlInfoToken n---- error report ----n)

strcat( sqlInfo sqlInfoToken)else sprintf( sqlInfoToken n---- warning report ----n)

strcat( sqlInfo sqlInfoToken) endif

sprintf( sqlInfoToken app message = sn appMsg)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken line = dn line)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken file = sn file)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken SQLCODE = ldn pSqlca-gtsqlcode)strcat( sqlInfo sqlInfoToken)

get error message rc = sqlaintp( errorMsg 1024 80 pSqlca) return code is the length of the errorMsg string if( rc gt 0) sprintf( sqlInfoToken sn errorMsg)

strcat( sqlInfo sqlInfoToken)

get SQLSTATE message rc = sqlogstt( sqlstateMsg 1024 80 pSqlca-gtsqlstate)if (rc == 0) sprintf( sqlInfoToken sn sqlstateMsg)

strcat( sqlInfo sqlInfoToken)

if( pSqlca-gtsqlcode lt 0) sprintf( sqlInfoToken --- end error report ---n)

strcat( sqlInfo sqlInfoToken)printf(s sqlInfo)return 1

else sprintf( sqlInfoToken --- end warning report ---n)

strcat( sqlInfo sqlInfoToken)printf(s sqlInfo)return 0

endif endif

return 0

void TransRollback( ) struct sqlca sqlca

int rc = 0 rollback the transaction printf( nRolling back the transaction n)

EXEC SQL ROLLBACKrc = SqlInfoPrint( ROLLBACK ampsqlca __LINE__ __FILE__)if( rc == 0) printf( The transaction was rolled backn)

50

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

51

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix C mdash Source Listing of testclicpp

Include The Appropriate Header Filesinclude ltsqlclihgtinclude ltsqlcli1hgtinclude ltsqlutilhgtinclude ltsqlenvhgtinclude ltstdiohgt include ltiostreamgt include ltlocalehgt include ltstringhgtdefine SQL_SQLSTATE_SIZE 5define LOOPS 8

using namespace std

Define The CLI_Class Classclass CLI_Class

Attributespublic

SQLHANDLE EnvHandleSQLHANDLE ConHandleSQLHANDLE StmtHandleSQLRETURN rcSQLCHAR Job[6]SQLCHAR Name[10]SQLDOUBLE Comp

Operationspublic

CLI_Class()~CLI_Class()SQLRETURN ShowResults()

Constructor Destructor

SQLRETURN printError( SQLHDBC SQLHSTMT)

Define The Class ConstructorCLI_ClassCLI_Class()

setlocale( LC_ALL )

Initialize The Return Code Variablerc = SQL_SUCCESS

Allocate An Environment Handlerc = SQLAllocHandle(SQL_HANDLE_ENV SQL_NULL_HANDLE ampEnvHandle)

Allocate A Connection Handleif (rc == SQL_SUCCESS)

rc = SQLAllocHandle(SQL_HANDLE_DBC EnvHandle ampConHandle)

Define The Class DestructorCLI_Class~CLI_Class()

Free The Connection Handleif (ConHandle = NULL)

SQLFreeHandle(SQL_HANDLE_DBC ConHandle)

Free The Environment Handle

52

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

if (EnvHandle = NULL)SQLFreeHandle(SQL_HANDLE_ENV EnvHandle)

Define The ShowResults() Member FunctionSQLRETURN CLI_ClassShowResults(void)

While There Are Records In The Result Data Set Generated Retrieve And Display Themcout ltlt Name Job Compensation ltlt endlcout ltlt --------- ------ ------------ ltlt endlcoutsetf(iosleft)coutprecision(2)coutsetf(iosfixed)while (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)

rc = SQLFetch(StmtHandle)if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)

coutwidth(15)cout ltlt Name

coutwidth(10)cout ltlt Job

coutwidth(7)cout ltlt Comp ltltendl

if(rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO ampamp rc = SQL_NO_DATA)printError(ConHandle StmtHandle)

else

rc = 0SQLCloseCursor(StmtHandle)

Return The ODBC API Return Code To The Calling Functionreturn(rc)

SQLRETURN CLI_ClassprintError (SQLHDBC hdbc

SQLHSTMT hstmt)

SQLCHAR buffer[SQL_MAX_MESSAGE_LENGTH + 1]SQLCHAR sqlstate[SQL_SQLSTATE_SIZE + 1]SQLINTEGER sqlcodeSQLSMALLINT lengthSQLRETURN rcwhile ((rc = SQLError(SQL_NULL_HENV hdbc hstmt

sqlstateampsqlcodebufferSQL_MAX_MESSAGE_LENGTH + 1amplength)) == SQL_SUCCESS || rc ==

SQL_SUCCESS_WITH_INFO)

cout ltlt SQLSTATE ltlt sqlstate ltlt endlcout ltlt SQLCODE ltlt sqlcode ltlt endlcout ltlt Error msg ltlt buffer ltlt endl

53

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

cout ltlt----------------------------- ltlt endl ltlt endl

return(SQL_ERROR)

----------------------------------------------------------------- The Main Function -----------------------------------------------------------------int main()

Declare The Local Memory Variables

(SQLCHAR ) db2user SQL_NTS (SQLCHAR ) test26t SQL_NTS)

SQLRETURNSQLCHARSQLCHARSQLCHARchar

SQLCHAR

rc = SQL_SUCCESSDBName[10] = TPLXSQLStmt[255]c[10]ptrcurrentDepartment[8][15] = Head Office

New England Mid Atlantic South Atlantic Great Lakes PlainsPacificMountain

Create An Instance Of The CLI_Class ClassCLI_Class Example

Connect To iSeries Database if (ExampleConHandle = NULL)

rc = SQLConnect(ExampleConHandle DBName SQL_NTS

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)ExampleprintError(ExampleConHandle SQL_NULL_HSTMT)

return(rc)

cout ltlt Successfully connected to ltlt DBName ltlt ltlt endlrc = SQLSetConnectAttr(ExampleConHandle SQL_ATTR_AUTOCOMMIT

(SQLPOINTER) SQL_AUTOCOMMIT_OFF SQL_IS_UINTEGER) Allocate An SQL Statement Handlerc = SQLAllocHandle(SQL_HANDLE_STMT ExampleConHandle

ampExampleStmtHandle)if (rc == SQL_SUCCESS)

Define A SELECT SQL Statement

strcpy((char ) SQLStmt select name job salary + ifnull(comm0) ascompensation )

ptr = strcat( (char ) SQLStmt from org o staff s )ptr = strcat( (char ) SQLStmt where odeptnumb = sdept)ptr = strcat( (char ) SQLStmt and deptname = )ptr = strcat( (char ) SQLStmt order by compensation desc)

Prepare The SQL Statementrc = SQLPrepare(ExampleStmtHandle SQLStmt SQL_NTS)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)ExampleprintError(ExampleConHandle ExampleStmtHandle)

54

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

return(rc)

Bind The Columns In The Result Data Set Returned To Application Variables

rc = SQLBindCol(ExampleStmtHandle 1 SQL_C_CHAR (SQLPOINTER)ExampleName sizeof(ExampleName) NULL)

rc = SQLBindCol(ExampleStmtHandle 2 SQL_C_CHAR (SQLPOINTER)ExampleJob sizeof(ExampleJob) NULL)

rc = SQLBindCol(ExampleStmtHandle 3 SQL_C_DOUBLE (SQLPOINTER)ampExampleComp sizeof(ExampleComp) NULL)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO) ExampleprintError(ExampleConHandle ExampleStmtHandle)

return(rc)

while (true)

for (int i = 0 i lt LOOPS i++)

rc=SQLBindParameter(ExampleStmtHandle1SQL_PARAM_INPUTSQL_C_CHARSQL_CHAR

150(SQLPOINTER) currentDepartment[i8]0NULL)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)

ExampleprintError(ExampleConHandle ExampleStmtHandle)return(rc)

rc = SQLExecute(ExampleStmtHandle)if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)

ExampleprintError(ExampleConHandle ExampleStmtHandle)return(rc)

cout ltlt endl ltlt Current Dept ltlt currentDepartment[i8] ltlt

endl Display The Results Of The SQL QueryExampleShowResults()if(rc = 0)break

if ( i500 == 0 ampamp i gt 0 )cout ltlt Loops ltlt i ltlt ltlt endl

cout ltlt AFTER ltlt LOOPS ltlt loops Press X to exit ltlt endlcin gtgt cif (c[0] == x || c[0] == X)

break

Free The SQL Statement Handleif (ExampleStmtHandle = NULL )

SQLFreeHandle(SQL_HANDLE_STMT ExampleStmtHandle) Disconnect From The Northwind Sample Databaserc = SQLDisconnect(ExampleConHandle)

Return To The Operating Systemreturn(rc)

55

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

The JNDI registered data source is then used in the main application to initialize the connection pool

AS400JDBCConnectionPoolDataSource tkcpds = [1](AS400JDBCConnectionPoolDataSource)ctxlookup(jdbcToolkitDataSource) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPool pool = newAS400JDBCConnectionPool(tkcpds)[2] Adds 1 connection to the pool that can be used by the application(creates the physical database connections based on the datasource)poolfill(1) [3] hellip con = poolgetConnection()[4]

At [1] the JNDI service is used to instantiate the AS400JDBCConnectionPoolDataSource

Then at [2] an AS400JDBCConnectionPool object is created This object is responsible for managing the connection pool

At [3] the connection pool is initialized with one connection

The pool object is used at [4] to obtain a database connection There are several additional things the developer should know about this code snippet

bull The advantage of using JNDI to register the data source object as opposed to just instantiating it in the main method is that in a more realistic scenario the data source would be registered just once at application deployment time Additionally the data source properties do not have to be hard-coded in the main method and can be changed at any time and then rebound without affecting the application

bull The AS400JDBCConnectionPool is a proprietary JTOpen implementation of a connection pool Specifically it does not implement the Referenceable interface and thus cannot be bound through JNDI services

bull The JTOpen AS400JDBCConnectionPoolDataSource does not support statement caching as described in the JDBC 30 specification Statement caching is implemented through SQL packages This feature is covered in the following section

Note The native iSeries JDBC driver supports both connection pooling and statement caching in a JDBC 30 compliant manner

8

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Extended Dynamic SQL and Statement Caching As mentioned the JTOpen data source object supports a number of properties that can be used to fine-tune the database performance In this section properties used to enable extended dynamic SQL support (see DB2 SQL Runtime Interfaces section above) and local statement caching will be discussed

Here is a relevant code excerpt from the deployDataSource method

AS400JDBCConnectionPoolDataSource tkcpds = new AS400JDBCConnectionPoolDataSource() hellip tkcpdssetExtendedDynamic(true)[1]tkcpdssetPackage(JDBCDS) [2]tkcpdssetPackageCache(true) [3]tkcpdssetPackageCriteria(select) [4]

At [1] the extended dynamic SQL support is enabled Note that the default is disabled for JTOpen The extended dynamic SQL functionality is often referred to as SQL package support The SQL packages are server-side repositories for SQL statements Packages contain the internal structures such as parse trees and access plans which are needed to execute SQL statements Because SQL packages are a shared resource the information built when a statement is prepared is available to all the users of the package This saves processing time especially in an environment where many users are using the same or similar statements Also because SQL packages are permanent this information is saved across job initiationtermination and IPLs In fact SQL packages can be saved and restored on other servers

At [2] the SQL package is named Note that the actual package name on the iSeries server is JDBCDSBAA The package name is generated by taking the name specified on the client and appending three letters that are an encoded set of the package configuration attributes By default an SQL package does not contain unparameterized select statements This behavior is overridden at [4] by setting the PackageCriteria property to select

At [3] the local statement cache is enabled A copy of the SQL package is cached on the AIX client This may improve application performance in a way similar to JDBC 30 statement caching Note however that local statement caching is not recommended for large SQL packages The copy of an SQL package is cached when the database connection is obtained This may cause increased network traffic as well as slow down the connection setup time

Reusable Open Data Paths (ODPs)An Open Data Path (ODP) definition is an internal i5OS object that is created when certain SQL statements (such as OPEN INSERT UPDATE and DELETE) are executed for the first time in a given job (or connection) The ODP can be thought of as a runtime implementation of an access plan The access plan created at the optimization time provides a recipe or in other words a sequence of steps necessary to execute the statement The ODP on the other hand provides the executable code for all requested IO operations The process of creating new ODP objects is fairly CPU- and IO-intensive so whenever possible the iSeries DB2 runtime tries to reuse existing ODPs For instance a ResultSetclose() call may close the SQL cursor but leave the ODP available to be used the next time the cursor is opened This can significantly reduce the response time in running SQL statements A reusable OPD usually requires 10 to 20 times less CPU resources than a newly created ODP Therefore it is important that the applications employ programming techniques that allow the DB2 runtime to reuse ODPs

With dynamic programming interfaces such as JDBC the most efficient way to avoid full opens is to employ the so-called prepare once execute many programming paradigm Ideally an SQL statement that is executed more than once should be prepared just once mdashfor example in the class constructor mdash and then reused for the consecutive executions At the prepare time the

9

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 engine stores the prepared statement along with the associated statement name in the QZDASOINIT jobs statement cache On the first execution the ODP created for a given statement is associated with the appropriate entry in the statement cache On consecutive executions the prepared statement and the corresponding ODP can be quickly located in the statement cache and reused The code snippet below illustrates the prepare once execute many programming technique

PreparedStatement pstmt = conprepareStatement(INSERT INTO COFFEES VALUES( ))[1] hellip for (int i = 0 i lt outerNumOfLoops i++)

insertfor (int j = 0 j lt numOfLoops j++)

pstmtsetString(1 Lavaza_ + IntegertoString(j)) hellip pstmtaddBatch()

int [] updateCounts = pstmtexecuteBatch()[2]concommit()

At [1] a PreparedStatement pstmt object is instantiated for a parameterized INSERT statement The statement is prepared just once The PreparedStatement object is then repeatedly used at [2] to perform blocked insert

Block Inserts Occasionally the developer may need to initially populate a table or insert a modified result set into a temporary table The efficiency of the insert operation for a large set of records can be dramatically improved by using the executeBatch method rather than the executeUpdate method The JTOpen driver converts parameterized insert statements in an executeBatch method to a block insert statement This significantly reduces the data flow and system resources required to perform the insert The following code snippet shows how to take advantage of the executeBatch method

10

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

PreparedStatement pstmt =conprepareStatement(INSERT INTO COFFEES VALUES( ))[1]for (int j = 0 j lt numOfLoops j++) pstmtsetString(1 Lavaza_ + IntegertoString(j))pstmtsetInt(2 i)pstmtsetFloat(3 499f)pstmtsetInt(4 0)pstmtsetInt(5 0)pstmtaddBatch() [2]

int [] updateCounts = pstmtexecuteBatch() [3]

At [1] a parameterized insert statement is prepared Note that all columns must be parameterized Otherwise the executeBatch method may throw the SQL0221 Number of rows 1 not valid exception In other words the developer should not mix parameter markers with literals or special registers in the VALUE clause

At [2] the addBatch method is used to add a new record to the client record buffer

At [3] all locally buffered data is sent to the server which in turn performs a block insert

Figure 4 shows the performance data for the executeBatch and executeUpdate methods

Figure 4 executeBatch() versus executeUpdate() performance comparison

11

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

WebSphere Considerations In certain situations an application provider may decide to deploy WebSphere Application Server in an AIX partition rather than natively in i5OS At the same time the application uses DB2 UDB for iSeries as an back-end database server Typically the WebSphere Application Server running in the AIX partition uses the virtual LAN to communicate with DB2 UDB for iSeries The WebSphere applications will access the database through a remote JDBC connection For performance and functionality reasons IBM recommends to utilize in such environments the IBM Toolbox for Java JTOpen driver Most of the tips and techniques described so far in this document hold true for WebSphere applications accessing DB2 UDB for iSeries There are however certain JDBC access aspects that are specific to this multi-tier architecture Letrsquos have a closer look at some of these considerations

Connection Pooling and Statement Caching

WebSphere Application Server provides its own connection pooling and statement caching mechanism that is by default enabled so that WebSphere applications automatically enjoy the performance benefits of these two critical programming techniques See the following link to learn more about the optimal connection pool setting in WebSphere

httppublibboulderibmcomwas40051englishinforzaiz51adminhelpudat_conpoolsethtml

Extended Dynamic SQL

For non-JTA connections WebSphere Application Server uses the comibmas400accessAS400JDBCConnectionPoolDataSource class as the iSeries JDBC provider implementation This is the DataSource implementation that has been used in all previous coding examples As mentioned the class supports a range of iSeries specific properties that can be used to fine tune JDBC performance These properties can be set through the WebSphere Application Server admin console For example herersquos the procedure to enable the extended dynamic SQL support In the WebSphere Application Server admin console navigate to the Data Source configuration dialog by selecting JDBC Providers -gt iSeriesToolbox -gt Data Sources then scroll down to the Additional Properties section Select Custom Properties link The Custom Properties dialog opens Scroll down to find the Extended Dynamic property and select it Change the default value false to true save the new configuration by clicking Apply button This is illustrated in Figure 5

12

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 5 Enabling the extended dynamic SQL through WebSphere Application Server console

The WebSphere Application Server needs to be restarted for the change to take effect The similar procedure can be followed to set other iSeries Data Source properties

Changing the WebSphere Application Server default isolation level

WebSphere Application Server V5 uses the REPEATABLE_READ (RR) isolation level for all implicit (WebSphere Application Server managed) transactions With the RR isolation level the rows selected updated deleted and inserted are locked until the end of the transaction Under certain circumstances this fairly extensive locking policy may cause locking contention especially when a WebSphere application competes for database resources with other applications that run on iSeries server For example a legacy order entry application may share data with the e-business customer care application running in WebSphere The locking contention may sometimes be eliminated by lowering the isolation level used by WebSphere Although the iSeries Data Source supports the custom transactionIsolation property resetting this property on the Data Source object will not change the default isolation level used by WebSphere for the connection objects produced by that Data Source In other words WebSphere will override the Data Source isolation level setting at the time the connection is obtained by a WebSphere application object such as servlet or Enterprise Java Bean (EJB) In order to change the default WebSphere behavior one must use the resource referencing Resource referencing allows a programmer to lookup DataSource or EJB objects using alias names rather than JNDI names Additionally by creating a resource reference a programmer can change certain properties of the underlying object Specifically a DataSource reference can be used to set a different isolation level for the connections produced by this database resource Typically resource references are defined by a programmer in a application development tool such as WebSphere Studio Application Developer The method to specify a DataSource reference differs depending on whether a programmer plans to use the reference in a servlet or in an EJB Letrsquos start with outlining the configuration process for a servlet In WebSphere Studio Application Developer open the deployment descriptor editor for the web project that contains the servlet To do so double click on the webxml file under WEB-INF directory in the web project In the deployment editor dialog select the References tab and then select Resource tab located in the top of the dialog that appears Under Resource References section select the Add button Herersquos an example of a DataSource reference created for iSeries DataSource named TestJDBCDS Note that the reference changes the default isolation level to READ_COMMITTED

13

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 6 Defining a resource reference for a servlet

Once the resource reference has been defined and saved the servlet source code needs to be changed to reflect the fact that a resource reference is used to obtain a DataSource from the JNDI service Herersquos the relevant code snippet try

ctx = new InitialContext() ds = (DataSource)ctxlookup(javacompenvTestJDBCJ2C)

catch (Exception e) eprintStackTrace(out)

Now the ds DataSource object will produce connections that by default run with the isolation level of READ_COMMITTED (RC)

As mentioned the process of defining a resource reference for an EJB differs from the process that is used in the case of a servlet In WebSphere Studio Application Developer open the deployment descriptor editor for the EJB project that contains the EJB To do so double click on the ejb-jarxml file under WEB-INF directory in the project In the deployment editor dialog select the References tab In the references section on the left locate and select the EJB for which the developer wants to change the default isolation level Click the Add button The Add Reference dialog opens Click the Resource Reference radio button and then Next Define the reference following the example shown in Figure 7

14

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 7 Adding a resource reference for an EJB

When you click ldquoFinishrdquo the reference definition is added to the EJB descriptor The new definition needs to be further modified To do so click on the (+) sign next to the EJB in the References list Click the new reference TestJDBCJ2C in this example to open the properties for the reference Change WebSphere Bindings and WebSphere Extensions sections as illustrated in Figure 8

15

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 8 Defining a resource reference for an EJB

Save the modified definition and then change the EJB source code to use the reference rather than directly DataSource

TroubleshootingTroubleshooting a multi-tier application may be a bit tricky because the developer needs to deal with software components that reside in separate partitions Three tools are particularly useful for pinning down the potential problem areas bull Joblog messages for a database server job mdash Provides enough details to isolate DB2 UDB for

iSeries runtime issues bull JDBC trace utility mdash Provides granular information about the data flow between the AIX

application and the iSeries server job bull Database Monitor ndash Provides detailed SQL runtime trace

Job Log MessagesAs mentioned a DB2 client communicates with a corresponding iSeries server job This server job runs the SQL requests on behalf of the client The iSeries database server jobs are called QZDASOINIT and they run in the QUSRWRK subsystem At any given time a large number of database server jobs may be active on the server so the first step is to identify the job that serves the particular client connection The easiest method to accomplish this task is to run the following CL command from the i5OS prompt

WRKOBJLCK OBJ(DB2USER) OBJTYPE(USRPRF)

Here DB2USER is the user profile that is used to connect to the iSeries server Note that a QZDASONIT job is assigned to a client after the connection has been established so the developer needs to set a breakpoint in the client application after the database connection has been established

Once the Work with Object Locks appears key in 5 (Work with Job) next to the only QZDASOINIT job that should be listed This shows the Work with Job dialog Select option 10 to

16

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

display the job log for the database server job Now the job log can be searched for any error messages generated by the DB2 runtime

Sometimes it is also useful to include debug messages in the job log The debug messages are informational messages written to the job log about the implementation of a query They describe query implementation methods such as the use of indexes join order ODP implementation (reusable versus non-reusable) and so on The easiest way to instruct an iSeries server to include the debug messages is to set the ServerTraceCategories property on the data source object

tkcpdssetServerTraceCategories(AS400JDBCDataSourceSERVER_TRACE_DEBUG_SERVER_JOB)

A sample of the job log messages with debug messages enabled is shown below

SET TRANSACTION completeSTATEMENT NAME FOUND QZ868F0A458E13AF8C Starting optimizer debug message for query Arrival sequence access was used for file COFFEESODP created ODP not deleted 5000 rows inserted in COFFEES in DB2USER STATEMENT NAME FOUND QZ868F0A4C144BF12EBlocking used for queryCursor CRSR0001 opened606 rows fetched from cursor CRSR0001 ODP not deleted Cursor CRSR0001 closed

So the job log offers fairly detailed information on how the AIX client requests were implemented by the DB2 runtime

JDBC Trace UtilityThe JTOpen driver provides a tracing utility which can be used to collect detailed client-side traces The JDBC tracing is turned off by default It can be enabled by setting the Trace property to true Heres an example of how to switch on tracing using the setTrace method on the data source object

tkcpdssetTrace(true)

The trace can also be enabled when using the DriverManagergetConnection() method for obtaining a connection to DB2 UDB for iSeries In this case the developer could add the trace property to the connection string This approach is illustrated in the following code snippet

ClassforName(comibmas400accessAS400JDBCDriver) [1] hellip con = DriverManagergetConnection(jdbcas400teraplextrace=true

db2userdb2pwd) [2]

At [1] an instance of the JTOpen JDBC Driver is initiated Then at [2] the driver is used to obtain a connection to the iSeries server Note how the trace property has been added to the database URL See the IBM Toolbox for Java JDBC properties documentation on the iSeries Information Center Web site for a complete list of properties supported by the JTOpen driver

Although the level of details provided by the trace utility is sufficient in most troubleshooting scenarios sometimes the developer may need to collect low-level traces scoped to a certain type

17

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

of information In V5R3 the IBM Toolbox for Java (as well as the latest JTOpen) added a comprehensive detailed trace facility The following is the complete list of detailed trace parameters and their purpose

bull None or ldquordquo ndash This setting disables the detailed trace bull datastream - This category is used by Toolbox classes to log dataflow between the local host

and the remote system It is not intended for use by application classes bull diagnostic - This category is used to log object state information bull error - This category is used to log errors that cause an exception bull information - This category is used to track the flow of control through the code bull warning - This category is used to log errors that are recoverable bull conversion - This category is used by Toolbox classes to log character set conversions

between Unicode and native code pages bull proxy - This category is used by Toolbox classes to log data flow between the client and the

proxy server bull pcml - This category is used to determine how PCML interprets the data that is sent to and

from the server bull jdbc - This category is used to track JDBC calls throughout the program bull thread - This category is used to enable tracing of thread information This is useful when

debugging multi-threaded applications bull all - This category will enable all previous categories

The detailed trace can be enabled when using the DriverManagergetConnection() method for obtaining a connection to DB2 UDB for iSeries In this case the developer could add the toolbox trace property to the connection string This is illustrated in the following code sample

String dbUrl = jdbcas400pwd1toolbox trace=diagnostic con = DriverManagergetConnection(dbUrl dbUser dbPassword)

Note that currently the driverrsquos DataSource interfaces do not allow the developer to directly activate the detailed tracing However they could set the server from the command line at the time the java program is launched The example below shows how the detailed trace properties could be enabled at the command line

java -Dcomibmas400accessTracecategory=diagnostic TestJDBC

The -D switch indicates to the java interpreter that the information following it will be a system property

In case of a WebSphere application the trace property can be set through the admin console In the console select Application Servers-gt server1-gt Process Definition -gt Java Virtual Machine Figure 9 shows how to set the Generic JVM Arguments for an application server instance

18

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 9 Setting JVM arguments to enable detailed Toolbox tracing

Database Monitor

The database monitor is the ultimate tool available on DB2 UDB for iSeries to collect low-level SQL traces It is mainly used to pin down the SQL performance problems Refer to the lsquoUsing iSeries Database Monitor to Identify and Tune SQL Queriesrsquo white paper for a detailed discussion on how to collect and analyze the database monitor traces httpibmcomserversenablesiteeducationiborecordhtmldtmon

IBM DB2 JDBC Universal Driver DB2 JDBC Universal Driver is one of the new features delivered with DB2 UDB Version 8 DB2 JDBC Universal Driver has been designed to eliminate the dependency on DB2 CLI runtime modules as well as to enable direct Type 4 connectivity to DB2 UDB for iSeries and DB2 UDB for zOSreg

The pure-Java (Type 4) remote connectivity is based on the DRDA open distributed protocol for cross-platform access to DB2 DRDA defines the rules the protocols and the semantics for accessing distributed data Applications can access data in a distributed relational environment by using SQL statements The iSeries DRDA application server implementation is based on multiple connection-oriented server jobs running in the QSYSWRK subsystem A DRDA listener job (QRWTLSTN) listens for TCP connect requests on port 446 Once an application requester connects to the listener job the listener wakes up one of the QRWTSRVR prestart jobs and assigns it to a given client connection Any further communication occurs directly between the client application and the QRWTSRVR job These concepts are illustrated in Figure 10

19

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 10 Accessing DB2 UDB for iSeries with DB2 Universal Driver

The DB2 Universal Driver can be loaded in an AIX partition by installing one of the DB2 Connect for AIX products (see the Additional Information section for details) It is also a part of a DB2 Enterprise Server Edition for AIX install Specifically the developer needs three JAR files in a AIX partition to successfully connect to an iSeries server db2jccjar db2jcc_license_cisuzjar and db2jcc_license_cujar The iSeries license is contained in db2jcc_license_cisuzjar Note that this file is not a part of DB2 Client In other words a DB2 Connect license is required to use the driver in production environments The location of the JAR files needs to be added to the CLASSPATH environment variable For instance the following entry could be added to the AIX profile script

CLASSPATH=homedb2inst2sqllibjavadb2jccjarCLASSPATH=$CLASSPATHhomedb2inst2sqllibjavadb2jcc_license_cujarCLASSPATH=$CLASSPATHhomedb2inst2sqllibjavadb2jcc_license_cisuzjarexport CLASSPATH

Java Runtime 131 is a prerequisite

Additionally the developer should install the latest database group PTF (SF99503 for i5OS V5R3) on the iSeries server The Informational APAR ii13348 is keeping track of any fixes relevant to DRDA above and beyond the current database group PTF

Obtaining a Connection to DB2 UDB for iSeries When Type 4 connectivity is used the DB2 Universal Driver connects directly to the DB2 on iSeries through TCPIP Note that this is different from the legacy DB2 Type 2 JDBC driver that requires a DB2 node and remote database configurations on the client accessing iSeries The following code snippet illustrates how to use the DB2 JDBC Universal Driver to obtain a connection to DB2 UDB for iSeries

20

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

try ClassforName(comibmdb2jccDB2Driver) [1] catch(javalangClassNotFoundException e) Systemerrprint(ClassNotFoundException )Systemerrprintln(egetMessage())

try DriverManagergetConnection(jdbcdb2teraplex446TERAPLEX[2]

db2userdb2pwd) hellip catch(SQLException ex) Systemerrprintln(

SQLException + exgetMessage())

At [1] an instance of the DB2 JDBC Universal Driver is instantiated Then at [2] the driver is used to obtain a connection to the iSeries server Note the proper form of the database URL required by the driver

Considerations There are several advantages of DB2 JDBC Universal Driver bull Ease of cross-platform development mdash Consistent coding techniques and consistent error

codes and messages bull Ease of deployment mdash Pure Java (no runtime client required) and a single driver for accessing

DB2 on different platforms

The ease of use comes at a price though The iSeries JTOpen driver is optimized for accessing DB2 UDB for iSeries data and it uses native iSeries protocol to communicate with the back-end database server job This usually results in better performance and more-efficient system resources utilization For instance when using the DB2 JDBC Universal Driver to access an iSeries server the executeBatch method results in a single record insert There are also some restrictions when using DB2 Universal JDBC Driver with Type 4 connectivity

bull Support for distributed transactions (JTA) is not enabled bull Driver built-in connection pooling is not supported

Refer to Java application support in DB2 for more details on DB2 JDBC Universal Driver

21

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 Connect data access This section will explore the most important aspects of DB2 Connect ndash iSeries integration - including configuration tips and coding examples

DB2 Connect provides functionality for accessing data stored in DB2 UDB for iSeries as well as DB2 UDB for zOS and DB2 UDB for OS390reg DB2 Connect offers capabilities to access DB2 family members via several SQL interfaces gateway functions such as connection pooling and federated database functionality Many applications supporting the DB2 family of products leverage DB2 Connect as a key middleware component DB2 Connect is offered as separate AIX license products

Enterprise Edition Application Server Edition

In addition to DB2 Connect there are several other DB2 UDB Version 81 products that are supported on AIX

DB2 Universal Database Enterprise Server Edition DB2 Universal Database Workgroup Server Unlimited Edition DB2 Universal Database Workgroup Server Edition DB2 Universal Database Universal Developers Edition All Clients

The DB2 Connect Enterprise Edition functionality is also contained in DB2 Enterprise Server Edition for AIX

22

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 Connect in a nutshell In the scenario described in this paper the DB2 Connect functions contained in DB2 Enterprise Edition for AIX are utilized DB2 Connect Enterprise Edition provides support for both local and remote DB2 clients This is illustrated in Figure 11 Accessing DB2 UDB for iSeries with DB2 Connect

Figure 11 Accessing DB2 UDB for iSeries with DB2 Connect

DB2 Connect implements the Distributed Relational Database Architecturetrade (DRDAreg) to reduce the cost and complexity of accessing data stored in DB2 UDB for iSeries and other DRDA-compliant database servers DRDA defines the rules the protocols and the semantics for accessing distributed data Applications can access data in a distributed relational environment by using SQL statements In a distributed environment the system running the application and sending the SQL requests across the network is called the application requester (AR) A remote database server that executes SQL requests submitted by an application requester is known as the application server (AS) In the example shown in Figure 11 (above) DB2 Connect plays the role of an application requester while DB2 UDB for iSeries is an application server In this case DB2 Connect communicates with the iSeries database through TCPIP The iSeries DRDA application server implementation is based on multiple connection-oriented server jobs running in the QSYSWRK subsystem A DRDA listener job (QRWTLSTN) listens for TCP connect requests on port 446 Once an application requester connects to the listener job the listener wakes up one of the QRWTSRVR prestart jobs and assigns it to a given client connection Any further communication occurs directly between the client application and the QRWTSRVR job

DB2 Connect supports a wide range of programming interfaces that can be used by AIX applications to access the iSeries database Embedded SQL frac34 Both static and dynamic SQL frac34 Various programming languages (Java CC++ Cobol Fortran REXX)

DB2 Call Level Interface (DB2 CLI) ODBC JDBC frac34 DB2 JDBC Type 2 Driver frac34 DB2 JDBC Type 4 Driver (Universal JDBC Driver)

23

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Note that DB2 Connect supports access to DB2 UDB for iSeries through DB2 JDBC Universal driver However for performance and ease of maintenance reasons IBM recommends that Java applications running in AIX use native iSeries Toolbox JDBC driver See the JDBC Data Access section of this paper (above) for more details On the other hand DB2 Connect is a very efficient and robust connectivity option for AIX applications especially in the environments that are not directly supported by the native iSeries JDBC driver Here are several possible scenarios that would require DB2 Connect installed in a AIX partition

Embedded SQL interface is used to access DB2 CLI or ODBC interface is used to access DB2 A single SQL interface is needed to access multiple back end DB2 server Specific DB2 Connect functionality is needed such as distributed join or connection

pooling

Prerequisites One of the DB2 Connect products or DB2 Enterprise Server Edition for AIX V81 is needed Additionally DB2 Application Development Client is required in the AIX partition to compile DB2 applications

For maximum database server stability the developer should install the latest database group PTF (SF99503 for i5OS V5R3) on the iSeries server The Informational APAR ii13348 is keeping track of any fixes relevant to DRDA above and beyond the current database group PTF

DB2 Connect configuration The following example employs i5OS V5R3 and DB2 UDB Enterprise Server Edition for AIX Version 81 FixPak 6

Configuration steps in the iSeries partition The following process lists the necessary steps to be performed on the iSeries server 1) Verify that the TCPIP stack is working correctly It is assumed that the Virtual LAN is used to

communicate with the i5OS partition First obtain the IP address of the iSeries server or its hostname and ping the iSeries server from the AIX partition

2) Create a relational database (RDB) entry for the iSeries database in the i5OS partition If this has already been created it can be displayed by using the DSPRDBDIRE command Make sure that the RDB entry with a location of LOCAL exists on the iSeries server If it does not exist use the ADDRDBDIRE command to add the appropriate RDB entry For example the following command would add an RDB entry named TPLX For simplicity it is recommended that the TCPIP host name and RDB entry remain the same

ADDRDBDIRE RDB(TPLX) RMTLOCNAME(LOCAL)

3) Create a collection called NULLID This is necessary because the utilities shipped with DB2 Connect and DB2 UDB for AIX store their packages in the NULLID collection Since it does not exist by default in the iSeries server you must create it using the following command

CRTLIB LIB(NULLID)

4) Products that support DRDA automatically perform any necessary code page conversions at the receiving system For this to happen both systems need a translation table from their code page to the partner code page The default Coded Character Set Identifier (CCSID) on the iSeries server is 65535 Since DB2 Connect does not have a translation table for this code page the developer needs to change the individual user profiles to contain a CCSID that can be converted properly by DB2 Connect For US English this is 037 For other languages see DB2 Connect Personal Edition Quick Beginning GC09-2967 The following command changes the CCSID for an individual user profile to 037

24

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

CHGUSRPRF userid CCSID(037)

5) Verify that the default port 446 for DRDA service is being used To do this go to the Configure TCPIP menu (CFGTCP) select Configure Related Tables and then select Work with service table entries Verify that the DRDA service is set for port 446

6) The Distributed Data Management (DDM) job must be started for DRDA to work If you want the DDM job to be automatically started whenever TCPIP is started change the attributes of the DDM job using the CHGDDMTCPA command and set the Autostart server parameter to YES

7) If the system administrator chooses not to autostart the server issue the following command to start the DDM server job

STRTCPSVR SERVER(DDM)

8) Make sure that the user profiles that will be used to connect to the iSeries server exist on the server

25

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Configuration steps in the AIX partition The following steps are required for DB2 Connect to be configured in the AIX partition 1) Sign on to the AIX partition as the DB2 administrator 2) Launch Client Configuration Assistant (db2ca from the command prompt) It is assumed that

VNC or an X-Windows server are being used on the workstation so that the db2ca GUI can be properly rendered

3) From the Selected pull-down menu select the Add Database using Wizard option The Select how you want to setup a connection dialog appears Select Manually configure a connection to a database and click Next This is shown in Figure 12

Figure 12 Accessing DB2 UDB for iSeries with DB2 Connect

26

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

4) On the Select a communications protocol choose TCPIP and select The database physical resides on a host or OS400 system Then select the option Connect directly to the server as shown in Figure 13 Click Next

Figure 13 mdash Selecting communications protocol

27

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

5) On the TCPIP tab fill in the host name of the iSeries server The port number should be 446 This is shown in Figure 14 Click Next

Figure 14 mdash Specifying TCPIP communication parameters

28

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

6) On the Database tab fill in the Relational Database name Use the RDB entry name (specified in step 2) in the Configuration steps in the iSeries partition section as shown in Figure 15 Click Next

Figure 15 mdash Specifying the remote database

7) If you plan to use the ODBC applications select Register this database for ODBC as a system data source on the ODBC tab Click Next

29

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

8) On the Specify the node option dialog select OS400 from the Operating System pull-down menu This is shown in Figure 16 Click Finish

Figure 16 mdash Specifying the node options

30

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

9) The Test Connection dialog appears This allows the developer to verify that the connection works Select both CLI and JDBC check boxes You are also prompted for an iSeries user ID and password as shown in Figure 17

Figure 17 mdash Testing the connection

31

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

10) The successful connection to the database server is confirmed by the message box shown in Figure 18

Figure 18 mdash Test Connection results 11) At this time a newly configured database connection should appear in the main DB2

Configuration Assistant window It is recommended that the DB2 utilities are also bound to the iSeries database The bind process creates the necessary SQL packages on the remote database In the main Configuration Assistant window click the TPLX database entry and then select Selected-gtBindhellip

32

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

12) The Bind dialog appears Click Select All and then enter the connection information as shown in Figure 19 Click Bind The Results message box appears This allows the developer to monitor the progress of the binding process Watch for any error and warning messages

Figure 19 mdash Binding the DB2 utilities This concludes the DB2 Connect configuration steps

33

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Accessing DB2 UDB for iSeries from C embedded SQL

As mentioned earlier DB2 Connect allows developers to compile and run embedded SQL applications that access DB2 UDB for iSeries data This section covers implementation details for a C embedded SQL application called cursorsjsqc (see Appendix B for source code)

Prerequisites An embedded SQL application running in an AIX partition will use DB2 Connect services to access DB2 UDB for iSeries therefore the developer needs to make sure that all components listed in section Prerequisites on page 24 are installed The developer also needs to create a remote database connection as described in the DB2 Connect configuration section of this paper on page 24

Static SQL and SQL packages To successfully run against a DB2 UDB for iSeries database an embedded SQL application needs to be first precompiled and bound to the back-end database This process creates an SQL package on the target iSeries server The SQL package contains the access plan information for the SQL statements executed by the application The internal structure of the package as well as the method how its content is used by the SQL runtime to facilitate the access plan reuse is similar to the Extended Dynamic SQL support covered in detail in the Extended Dynamic SQL and Statement Caching section of this paper (on page 9) There are however important differences between the packages created by the extended dynamic SQL support and the packages created for embedded SQL DRDA client applications The extended dynamic SQL packages support dynamic SQL interfaces such as JDBC

that can submit ad hoc SQL statements at the run time The SQL runtime can prepare the dynamic statements and add them to the package On the other hand the DRDA packages are created at the precompile time and contain static SQL In order to add new statements to the package the application needs to be precompiled and rebound again

The extended dynamic SQL package can dynamically grow up to 500MB by allocating new space as required The DRDA packages since they are created at the precompile time have a fix size and do not grow over their life time

Simple embedded SQL application The application is based on a source code provided in the DB2 UDB samples directory typically to be found at homedb2inst1sqllibsamples The cursorsjsqc performs a join between STAFF and ORG tables located in DB2USER schema (library) on the TPLX database server (the source is provided at the end of this paper in Appendix B) The join statement retrieves the DEPTNAME column from ORG NAME column from STAFF and calculates the total compensation for an employee by adding SALARY and COMM columns in STAFF The results are sorted by department name and total compensation Here is the SELECT statement used by the application

SELECT deptname name salary + IFNULL(comm0) as compensationFROM org o staff sWHERE odeptnumb = sdeptORDER BY deptname compensation DESC

The application iterates through the selected records and prints out the data to the standard output device The sample DB2USER schema was created with the following SQL statements

db2 CONNECT TO tplx USER db2user USING mypassworddb2 CALL QSYSCREATE_SQL_SAMPLE(DB2USER)

34

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Make sure that the AIX partition is logged into with the DB2 admin user profile If the defaults were selected at the DB2 installation time this profile name is db2inst1 It is also assumed that DB2USER user exists on the iSeries server and that it has appropriate authority

There are several steps that are required to create an executable for the cursorsjsqc source code First the DB2 PRECOMPILE utility needs to be called The utility creates a bind file that is used to bind the required SQL package to the TPLX database It also converts embedded SQL statements into DB2 run-time API calls and produces a pure C source file that can be processed by an AIX C compiler

db2 CONNECT TO tplx USER db2user USING mypassworddb2 prep cursorsjsqc bindfile

Note that the connect statement is required only if the developer is not already connected to the database on an iSeries server Watch for any error or warning messages returned by the DB2 prep utility The prepare step should produce cursorsjbnd and cursorsjc files in the current directory Now the developer can invoke the bind utility to prepare the statements contained in the bind file and create the package on the target iSeries database server

db2 bind cursorsjbnd

It is assumed that Visual C++ 60 is installed and configured in the AIX partition Refer to the ldquoDeveloping and Porting C and C++ Applications on AIXrdquo redbook for more information on how to use the Visual C++ compiler httpibmcomredbooksabstractssg245674htmlOpen

Use the following commands to compile the C source generated by the precompile utility

xlc -I$INSTHOMEsqllibinclude ndashc cursorsjcxlc ndasho cursorsj cursorsjo -L$INSTHOMEsqlliblib ndashldb2

Run the program from the AIX prompt

cursorsj db2user mypassword

Distributed Join DB2 UDB Version 8 provides core federated server functionality A federated system consists of a DB2 UDB instance that operates as a federated server a database that acts as the federated database one or more data sources and clients (users and applications) that access the database and data sources Federated server permits objects stored in multiple databases to be accessed together in the same query For example a query can refer to a table that resides in DB2 UDB for iSeries and join it to a table stored in DB2 UDB for AIX Such a query would constitute so called distributed join The support for DB2 UDB for iSeries as a federated data source is provided by core federated server functionality directly implemented in DB2 UDB Enterprise Server Edition and DB2 UDB Connect Enterprise Edition All other DB2 UDB family members are also supported directly by core DB2 UDB federated server An additional software product DB2 Information Integratortrade is required to access non-DB2 UDB databases such as Oracle Sybase or Microsoftreg SQL Server Consult the following white papers for a detailed discussion on DB2 federated server support Heterogeneous data access for iSeries applications Version 2 httpibmcomserversenablesiteeducationiborecordhtmlhetdata Fundamentals of IBM DB2 Federated Server and Relational Connect httpwww7bsoftwareibmcomdmddlibrarytecharticle0206purnell0206purnellhtml

35

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Distributed Join Example In this section the steps that are required to configure DB2 UDB for iSeries as a federated data source will be illustrated Then the cursorsjsqc program will be ldquotweakedrdquo so that it executes a distributed join query that accesses data stored on an iSeries server and in the local DB2 UDB for AIX database It is assumed that the developer is familiar with the DB2 federated server concepts

Note Run the following commands from the Command Line Processor prompt Load the utility by executing the db2 command at the AIX prompt 1) First the local DB2 UDB for AIX instance needs to be enabled as a DB2 federated server

This is done by setting the database manager configuration parameter FEDERATED to YES

db2=gt update dbm cfg using FEDERATED YES

The database instance needs to be restarted for the change to take effect

NOTE A federated database is a regular database in a DB2 UDB instance that has the FEDERATED parameter enabled Therefore in this example the SAMPLE database that was created earlier is used as the federated database A new database can also be created using the CREATE DATABASE command

2) Connect to the federated database

db2=gt connect to sample

3) Use the CREATE WRAPPER statement to register a wrapper for the iSeries data source Wrappers are library routines that are used by the federated server to perform operations such as connecting to a data source and retrieving data from it The default wrapper name for DB2 UDB for iSeries is DRDA Here is the command to register the DRDA wrapper

db2=gt create wrapper drda

4) Use the CREATE SERVER statement to register a data source as a server within the federated database The server definition specifies the type and version of the data source and the wrapper used for communications with this data source For the DB2 UDB for iSeries data source the node and the database names are also needed The node and database name parameters have been configured for our TPLX database in the Configuration steps in the AIX partition section (on page 24) Use the following DB2 UDB command to lookup these parameter on the federated server

db2=gt list database directory

In this case the command produced the following output

Database alias = TPLX Database name = DCSE99E1 Node name = NDE9BF76 Database release level = a00 Comment = Directory entry type = Remote Authentication = SERVER Catalog database partition number = -1

36

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Note that the node name is set to NDE9BF76 The name was generated by the Configuration Administrator utility (db2ca)

Here is the command to register the TPLX database as a federated server

db2=gt create server tplx type db2400 version 530 wrapperdrda authorization db2user password mypassword options(nodeNDE9BF76 dbname TPLX)

The command is quite complex so make sure that the syntax is correct

5) Define the user mappings that instructs the federated server what user ID and password should be used when connecting to the iSeries data source

db2=gt create user mapping for user server tplxoptions(remote_authid db2user remote_password mypassword)

Specify the nickname for the iSeries table or view A nickname is an identifier that is used by the federated server to reference an object located at the data source The following command creates a nickname for the STAFF table located in the DB2USER schema on the TPLX database

db2=gt create nickname tplx_staff for tplxdb2userstaff

6) Test the distributed join query

db2=gt SELECT deptname name salary + COALESCE(comm0) ascompensation FROM org o tplx_staff s WHERE odeptnumb =sdept ORDER BY deptname compensation DESC

Note that the native iSeries function IFNULL has been substituted with an equivalent DB2 UDB function COALESCE COALESCE is also supported on iSeries servers For better portability IBM encourages the use of COALESCE rather than IFNULL Note also that the query runs on the federated server rather than on TPLX It accesses the ORG table in the local DB2 UDB for AIX SAMPLE database and the STAFF table that resides in TPLX The federated server performs the necessary distributed join

7) Modify the cursorsjsqc so that it executes a distributed join There are two source code modifications - Change the CONNECT TO statements Now the application needs to connect to the

federated database SAMPLE rather than to TPLX

EXEC SQL CONNECT TO SAMPLEEXEC SQL CONNECT TO SAMPLE USER userid USING passwd

- Modify the select statement so that it performs a distributed join Use the statement (shown in step 6) above Save the new source version as cursordjsqc

- Prepare bind and compile the distributed join version of the program as described in the Simple C embedded SQL application section (on page 34)

db2 prep cursordjsqc bindfiledb2 bind cursordjbndxlc -I$INSTHOMEsqllibinclude ndashc cursordjcxlc ndasho cursordj cursordjo -L$INSTHOMEsqlliblib ndashldb2

37

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

- Run the program from the AIX prompt

cursordj

Connection Pooling and Connection ConcentratorA modern Web-based application typically executes a large number of short-lived transactions Executing a transaction in this environment means establishing a database connection executing a few SQL statements and terminating this connection Creating connections to the database server is a very costly process To reduce the unnecessary workload DB2 Connect implements connection pooling and connection concentrator Connection pooling mechanism allows DB2 Connect to reuse an existing connection infrastructure for subsequent connection requests The connection concentrator is an advanced technology that allows DB2 Connect to serve a potentially very large number of clients with a limited number of database connections This is accomplished by decoupling clients from a particular database connection

Note that currently neither connection pooling nor connection concentrator support DB2 UDB for iSeries Therefore for performance reasons the author strongly recommends that the application server that obtains and drops connections very frequently implements its own database connection pooling mechanism that would assign an existing pooled database connection to a new AIX process or thread

TroubleshootingTroubleshooting a multi-tier application may be a bit tricky because the developer needs to deal with software components that reside in separate partitions The authorrsquos experience shows that two tools are particularly useful for pinning down the potential problem areas The joblog messages for a database server job usually provide enough details to isolate DB2

UDB for iSeries runtime issues The DRDA trace utility provides granular information about the data flow between the AIX

application and the iSeries server job

38

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Job Log MessagesAs mentioned earlier a DB2 client communicates with a corresponding iSeries server job This server job runs the SQL requests on behalf of the client More precisely when a DB2 client submits an SQL statement the statement is passed to a server job that in turn calls the DB2 runtime to execute the statement The results are then reformatted and marshaled to the client The iSeries DRDA server jobs are called QRWTSRVR and they run in the QUSRWRK subsystem At any given time there may be a large number of DRDA server jobs active on the system so the first step is to identify the job that serves the particular client connection The easiest method to accomplish this task is to run the following CL command from the i5OS prompt

WRKOBJLCK OBJ(DB2USER) OBJTYPE(USRPRF)

Here DB2USER is the user profile that is used to connect to the iSeries server Note that a QRWTSRVR job is assigned to a client after the connection has been established so the developer needs to set a breakpoint in the client application below the CONNECT TO statement

Once the Work with Object Locks appears key in 5 (Work with Job) next to the only QRWTSRVR job that should be listed This shows the Work with Job dialog Select option 10 to display the job log for the database server job Now the developer can search the job log for any error messages generated by the DB2 runtime

Sometimes it is also useful to include debug messages in the job log The debug messages are informational messages written to the job log about the implementation of a query They describe query implementation methods such as use of indexes join order ODP implementation (reusable versus non-reusable) and so on The easiest way to instruct the iSeries server to include the debug messages is to call the following stored procedure just after the connection to the iSeries server is established

EXEC SQL call qsysqcmdexc(STRDBGUPDPROD(YES)000000002000000)

A sample of the job log messages with debug messages enabled is shown below in Figure 20

Arrival sequence access was used for file STAFFAccess path suggestion for file STAFFQuery options used to build the OS400 query access plan Ending debug message for query ODP created Blocking used for queryCursor SQLCUR201 opened1 rows fetched from cursor SQLCUR201Row not found for SQLCUR201ODP deleted Cursor SQLCUR201 closedDESCRIBE of prepared statement STMT0201 completed

Figure 20 mdash Joblog with debug messages enabled

So the job log offers fairly detailed information on how the AIX client requests were implemented by the DB2 runtime

39

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 DRDA trace utilityThe DB2 DRDA trace utility (db2drdat) provides detailed information about the data streams exchanged between DB2 Connect and target database server The output file produced by the utility contains send and receive communications buffers TCPIP error messages and SQL Communications Area (SQLCA) information Please refer to lsquoDB2 Connect Userrsquos Guidersquo manual for in-depth discussion of the DRDA trace utility

Accessing DB2 UDB for iSeries from CLI DB2 Call Level Interface (CLI ) is based on the Microsoft Open Database Connectivity (ODBC) specification and the ISO CLI standard The DB2 CLI interface gained popularity among DB2 application providers because the developer can build an ODBC application by simply linking the application with libdb2 library on a UNIX server In other words the developer directly utilizes the DB2 ODBC driver services without a need for an ODBC driver manager Additionally in contrast to embedded SQL the developer does not need to precompile or bind DB2 CLI applications because they use packages provided with DB2 UDB The developer simply compiles and links the application

Prerequisites A DB2 CLI application running in an AIX partition will use DB2 Connect services to access DB2 UDB for iSeries therefore make sure that all components listed in Prerequisites section of this paper on page 24 are installed The developer also needs to create a remote database connection as described in the DB2 Connect configuration section of this paper on page 24

Dynamic SQL and Access Plan Caching A DB2 CLI client application uses the dynamic SQL interface and does not have the capability to utilize the extended dynamic SQL support Therefore it runs lsquopurersquo dynamic SQL statements That does not mean however that the process of parsing validating and optimizing will be repeated for every execution of a given dynamic SQL statement

The DB2 UDB for iSeries database implements an internal object called System-Wide SQL Statement Cache (SWSC) The SWSC can improve the performance of programs using dynamic SQL statements by caching the access plans in a system-wide cache When a dynamic SQL statement is submitted the SQL runtime searches the SWSC to see if this statement has been previously executed If so then DB2 retrieves and reuses the key information associated with the cached statement and thereby the processing time and the resources utilization can be significantly reduced

Simple DB2 CLI C++ ApplicationThis section covers DB2 CLI implementation details for a sample C++ program called testclicpp (the source is provided at the end of this paper in Appendix C) To compile the source with Visual C++ complier use the following command in the AIX partition

xlC ndashI$INSTHOMEsqllibinclude ndashc testclicppxlC ndasho testcli testclio ndashL$INSTHOMEsqlliblib ndashldb2

The application performs a join between STAFF and ORG tables located in DB2USER schema (library) The join statement retrieves the DEPTNAME column from ORG NAME and JOB columns from STAFF and calculates the total compensation for an employee by adding SALARY and COMM columns in STAFF The results are sorted by total compensation The selection criterion is based on the current value of the department name parameter Here is the SELECT statement used by testcli

40

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

select name job salary + coalesce(comm0) as compensationfrom org o staff swhere odeptnumb = sdeptand deptname = order by compensation desc

Figure 21 shows the software components involved in the execution of this sample application

Figure 21 How a DB2 CLI client accesses DB2 UDB on an iSeries server

Although the testcli application is fairly simple it covers some important aspects of efficient CLI programming for DB2 UDB for iSeries

Reusable Open Data Paths (ODPs)An Open Data Path (ODP) definition is an internal i5OS object that is created when certain SQL statements (such as OPEN INSERT UPDATE and DELETE) are executed for the first time in a given job (or connection) The ODP can be thought of as a runtime implementation of an access plan The access plan created at the optimization time provides a recipe or in other words a sequence of steps necessary to execute the statement The ODP on the other hand provides the executable code for all requested IO operations The process of creating new ODP objects is fairly CPU- and IO-intensive so whenever possible the iSeries DB2 runtime tries to reuse existing ODPs For instance a SQLCloseCursor() API call may close the SQL cursor but leave the ODP available to be used the next time the cursor is opened This can significantly reduce the processing and response time in running SQL statements A reusable OPD usually requires 10 to 20 times less CPU resources than a newly created ODP Therefore it is important that the applications employ programming techniques that allow the DB2 runtime to reuse ODPs

With dynamic interfaces such as CLI full opens are avoided by using a prepare once execute many programming paradigm It means that when an SQL statement is going to be executed more than once you should prepare the statement just once and then reuse the prepared

41

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

statements for consecutive executions Although DB2 UDB does try to convert literals to parameter markers so that similar statements can be reused it is a better programming practice to explicitly implement parameter markers That way the chances for reusable ODPs are quite significantly improved The code snippet in Figure 22 illustrates how to implement the prepare once execute many programming technique

Define A SELECT SQL Statementstrcpy((char ) SQLStmt select name job salary + ifnull(comm0) ascompensation )ptr = strcat( (char ) SQLStmt from org o staff s )ptr = strcat( (char ) SQLStmt where odeptnumb = sdept)ptr = strcat( (char ) SQLStmt and deptname = )ptr = strcat( (char ) SQLStmt order by compensation desc) [1]

Prepare The SQL Statementrc = SQLPrepare(ExampleStmtHandle SQLStmt SQL_NTS) [2]

Bind The Columns In The Result Data Set Returned To Application Variablesrc = SQLBindCol(ExampleStmtHandle 1 SQL_C_CHAR (SQLPOINTER)

ExampleName sizeof(ExampleName) NULL)rc = SQLBindCol(ExampleStmtHandle 2 SQL_C_CHAR (SQLPOINTER)

ExampleJob sizeof(ExampleJob) NULL)rc = SQLBindCol(ExampleStmtHandle 3 SQL_C_DOUBLE (SQLPOINTER)

ampExampleComp sizeof(ExampleComp) NULL)

for (int i = 0 i lt LOOPS i++)rc=SQLBindParameter(ExampleStmtHandle

1SQL_PARAM_INPUTSQL_C_CHARSQL_CHAR10(SQLPOINTER) currentDepartment[i8]0NULL) [3]

rc = SQLExecute(ExampleStmtHandle) [4]cout ltlt endl ltlt Current Dept ltlt currentDepartment[i8] ltlt endl Display The Results Of The SQL QueryExampleShowResults()

Figure 22 Use the prepare once execute many programming technique

The error-handling code has been removed for clarity At [1] the statement text is assigned to a variable Note that a parameter marker is used in the WHERE clause The statement is then prepared just once at [2] The current value of the parameter is bound to the prepared statement at [3] The prepared statement is executed at [4] Steps [3] and [4] are repeatedly executed in a for loop

Techniques to Further Improve DB2 CLI Performance Thus far this paper has discussed the techniques used by a sample application to tune the CLI performance However depending on the application architecture other methods of improving CLI performance may be considered

Connection PoolingCurrently the CLI application connecting through DB2 Connect to DB2 UDB for iSeries does not take advantage of the connection pooling mechanism implemented by DB2 Connect Therefore for performance reasons the author strongly recommends that the application server that obtains and drops connections very frequently implements its own database connection pooling mechanism that would assign an existing pooled database connection to a new AIX process or thread

42

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Blocking

For queries which result in returning large data blocks from the iSeries server (usually 32K of data and above) ensure that the database manager configuration parameter RQRIOBLK is set to 32767 This can be done using the Command Line Processor (CLP) as follows

db2 update database manager configuration using RQRIOBLK 32767

TroubleshootingThe experience of the author shows that two tools are particularly useful for pinning down the potential problem areas bull Joblog messages for a database server job usually provides enough details to isolate DB2

runtime issues bull CLI trace utility provides granular information about the data flow between the AIX application

and the database server job

Job Log MessagesThe process of finding and analyzing the job log for a DB2 CLI connection is identical to the process outlined for an embedded SQL application in the Job Log Message section of this paper on page 39

CLI Trace The DB2 CLIODBCJDBC trace utility provides very detailed information about the data streams exchanged between DB2 Connect and target database server Refer to the DB2 Information Center for more information on how to set up and analyze the CLI traces httppublibboulderibmcominfocenterdb2v8luwindexjsptopic=comibmdb2udbdocadc000 7959htm

43

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Trademarks

IBM eServer iSeries AIX AIX 5L i5OS WebSphere DB2 DB2 Universal Database DB2 Connect OS400 zOS OS390 Distributed Relational Database Architecture DRDA and DB2 Information Integration are trademarks or registered trademarks of International Business Machines Corporation in the United States and other countries

Java and all Java-based trademarks are trademarks of Sun Microsystems Inc in the United States other countries or both

Linux is a registered trademark of Linus Torvalds in the United States other countries or both

UNIX is a registered trademark of The Open Group in the United States and other countries

Microsoft and Windows are registered trademarks of Microsoft Corporation in the United States andor other countries

All other registered trademarks and trademarks are properties of their respective owners

IBM makes no commitment to make available any products referred to herein

References in this publication to IBM products or services do not imply that IBM intends to make them available in every country in which IBM operates

Additional Information ITSO offers a Redbook that can be helpful to those who want to learn more about i5OS AIX integration

bull AIX Integration with I5OS on the IBM eServer iSeries Server (SG24-6551)

Jarek Miszczyk is the Senior Software Engineer IBM eServer Solutions Enablement IBM Rochester

[Portions of this white paper reprinted with permission from MC Mag Online published by MC Press LLP httpwwwmcpressonlinecom]

Acknowledgments The author would like to thank the following people for their advice contributions and support on this paper

Bob Bittner IBM Rochester Jon Rush IBM Rochester Prasad Vallurupalli IBM Rochester Neil Willis IBM Rochester

44

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix A Source Listing of TestJDBCjava

package comibmiseriespwdimport javasqlimport javaxnamingimport javautilHashtableimport javautilimport javaxsqlimport comibmas400access

public class TestJDBC public static void main(javalangString[] args)

throws Exception

int numOfLoops = 5000int outerNumOfLoops = 5boolean firstExec = trueConnection conStatement sPreparedStatement psPreparedStatement pstmtdelCallableStatement cstmPreparedStatement pstmtHashtable env = new Hashtable()

envput(ContextINITIAL_CONTEXT_FACTORYcomsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env)Systemoutprintln(Deploying connection pooling data source)deployDataSource() Do the work with connection pooling onlyAS400JDBCConnectionPoolDataSource tkcpds =

(AS400JDBCConnectionPoolDataSource)ctxlookup(jdbcToolkitDataSource) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPool pool = new AS400JDBCConnectionPool(tkcpds) Adds 1 connection to the pool that can be used by theapplication (creates the physical database connections based onthe data source)poolfill(1)Systemoutprintln(nStart timing Toolkit connection pooling)long startTime = SystemcurrentTimeMillis()

for (int i = 0 i lt outerNumOfLoops i++) con = poolgetConnection()consetAutoCommit(false) deleteif ( i == 0)

long startDelete = SystemcurrentTimeMillis()cstm = cstm = conprepareCall(

CALL qsysqcmdexc(CLRPFM FILE(DB2USERCOFFEES) + 000000002800000))

cstmexecuteUpdate()cstmclose()long endDelete = SystemcurrentTimeMillis()Systemoutprintln(Delete all records +

(endDelete - startDelete) + ms elapsed)

45

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

String sqlinstrlong startInsert = SystemcurrentTimeMillis() insert

pstmt =conprepareStatement(INSERT INTO COFFEES VALUES( ))for (int j = 0 j lt numOfLoops j++) pstmtsetString(1 Kona_ + IntegertoString(i))pstmtsetInt(2 150)pstmtsetFloat(3 999f)pstmtsetInt(4 0)pstmtsetInt(5 0)pstmtaddBatch()int [] updateCounts = pstmtexecuteBatch()concommit()pstmtclose()long endInsert = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for + numOfLoops + inserts

+ (endInsert - startInsert)) selectlong startSelect = SystemcurrentTimeMillis()ps = conprepareStatement(SELECT FROM COFFEES)ResultSet rs = psexecuteQuery()rsnext()rsclose()concommit()psclose()long endSelect = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for select +

(endSelect - startSelect))consetAutoCommit(true)conclose()long endTime = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for + outerNumOfLoops +

loops + (endTime - startTime))Systemexit(0)

private static void deployDataSource()throws ExceptionString serverName = teraplex String databaseName = TERAPLEX String userName = db2user String password = db2pwd

Establish a JNDI context and bind the connection pool data sourceHashtable env = new Hashtable()envput(ContextINITIAL_CONTEXT_FACTORY

comsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPoolDataSource tkcpds = new

AS400JDBCConnectionPoolDataSource()tkcpdssetServerName(serverName) tkcpdssetDatabaseName(databaseName) tkcpdssetUser(userName) tkcpdssetPassword(password) tkcpdssetDescription(Toolkit Connection Pooling DataSource)tkcpdssetSavePasswordWhenSerialized(true)tkcpdssetExtendedDynamic(true)

46

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

tkcpdssetPackage(JDBCDS)tkcpdssetPackageCache(true)tkcpdssetPackageCriteria(select)enable the following properties as requiredcpdssetTrace(true)tkcpdssetServerTraceCategories( AS400JDBCDataSourceSERVER_TRACE_DEBUG_SERVER_JOB)

ctxrebind(jdbcToolkitDataSource tkcpds)

47

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix B mdash Source Listing of cursorsjsqc

Source File Name = cursorsjsqc Licensed Materials - Property of IBM (C) COPYRIGHT International Business Machines Corp 1995 2000 2004 All Rights Reserved US Government Users Restricted Rights - Use duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp PURPOSE This sample program demonstrates the use of a CURSOR The CURSOR is processed using static SQL EXTERNAL DEPENDENCIES - Ensure existence of database for precompile purposes - Precompile with the SQL precompiler (PREP in DB2) - Bind to a database (BIND in DB2) - Compile and link with the IBM Cset++ compiler (AIX and OS2) or the Microsoft Visual C++ compiler (Windows) or the compiler supported on your platform For more information about these samples see the README file For more information on programming in C see the - Programming in C and C++ section of the Application Development Guide For more information on building C applications see the - Building C Applications section of the Application Building Guide For more information on the SQL language see the SQL Reference

include ltstdiohgt include ltstdlibhgt include ltstringhgtinclude ltsqlhgtinclude ltsqlenvhgtinclude ltsqldahgtinclude ltsqlcahgt

int SqlInfoPrint( char struct sqlca int char )void TransRollback( void)

define EMB_SQL_CHECK( MSG_STR ) rc = SqlInfoPrint( MSG_STR ampsqlca __LINE__ __FILE__) if ( rc = 0 ) TransRollback( )

return 1

EXEC SQL INCLUDE SQLCA

int main(int argc char argv[])

EXEC SQL BEGIN DECLARE SECTIONchar dname[15]

48

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

char pname[10]double compchar userid[9]char passwd[19]

EXEC SQL END DECLARE SECTION

int rc = 0printf( Sample C program CURSORSJ n )if (argc == 1)

EXEC SQL CONNECT TO TPLXEMB_SQL_CHECK(CONNECT TO TPLX)

else if (argc == 3)

strcpy (userid argv[1])strcpy (passwd argv[2])EXEC SQL CONNECT TO TPLX USER userid USING passwdEMB_SQL_CHECK(CONNECT TO TPLX)

else

printf (nUSAGE cursor [userid passwd]nn)return 1

endif

EXEC SQL DECLARE c1 CURSOR FORselect deptname name salary + ifnull(comm0) as compensationfrom org o staff swhere odeptnumb = sdeptorder by deptname compensation desc

EXEC SQL OPEN c1EMB_SQL_CHECK(OPEN CURSOR)

printf(DEPARTMENT NAME COMPENSn)printf(-----------------------------------n)do

EXEC SQL FETCH c1 INTO dname pname compif (SQLCODE = 0) breakprintf( -1515s -1010s 72fn dname pname comp )

while ( 1 )

EXEC SQL CLOSE c1EMB_SQL_CHECK(CLOSE CURSOR)

EXEC SQL CONNECT RESETEMB_SQL_CHECK(CONNECT RESET)

exit(0)

end of program CURSORSJSQC

int SqlInfoPrint( char appMsgstruct sqlca pSqlcaint linechar file )

int rc = 0char sqlInfo[1024]char sqlInfoToken[1024]char sqlstateMsg[1024]char errorMsg[1024]

if (pSqlca-gtsqlcode = 0 ampamp pSqlca-gtsqlcode = 100)

49

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

strcpy(sqlInfo )if( pSqlca-gtsqlcode lt 0) sprintf( sqlInfoToken n---- error report ----n)

strcat( sqlInfo sqlInfoToken)else sprintf( sqlInfoToken n---- warning report ----n)

strcat( sqlInfo sqlInfoToken) endif

sprintf( sqlInfoToken app message = sn appMsg)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken line = dn line)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken file = sn file)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken SQLCODE = ldn pSqlca-gtsqlcode)strcat( sqlInfo sqlInfoToken)

get error message rc = sqlaintp( errorMsg 1024 80 pSqlca) return code is the length of the errorMsg string if( rc gt 0) sprintf( sqlInfoToken sn errorMsg)

strcat( sqlInfo sqlInfoToken)

get SQLSTATE message rc = sqlogstt( sqlstateMsg 1024 80 pSqlca-gtsqlstate)if (rc == 0) sprintf( sqlInfoToken sn sqlstateMsg)

strcat( sqlInfo sqlInfoToken)

if( pSqlca-gtsqlcode lt 0) sprintf( sqlInfoToken --- end error report ---n)

strcat( sqlInfo sqlInfoToken)printf(s sqlInfo)return 1

else sprintf( sqlInfoToken --- end warning report ---n)

strcat( sqlInfo sqlInfoToken)printf(s sqlInfo)return 0

endif endif

return 0

void TransRollback( ) struct sqlca sqlca

int rc = 0 rollback the transaction printf( nRolling back the transaction n)

EXEC SQL ROLLBACKrc = SqlInfoPrint( ROLLBACK ampsqlca __LINE__ __FILE__)if( rc == 0) printf( The transaction was rolled backn)

50

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

51

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix C mdash Source Listing of testclicpp

Include The Appropriate Header Filesinclude ltsqlclihgtinclude ltsqlcli1hgtinclude ltsqlutilhgtinclude ltsqlenvhgtinclude ltstdiohgt include ltiostreamgt include ltlocalehgt include ltstringhgtdefine SQL_SQLSTATE_SIZE 5define LOOPS 8

using namespace std

Define The CLI_Class Classclass CLI_Class

Attributespublic

SQLHANDLE EnvHandleSQLHANDLE ConHandleSQLHANDLE StmtHandleSQLRETURN rcSQLCHAR Job[6]SQLCHAR Name[10]SQLDOUBLE Comp

Operationspublic

CLI_Class()~CLI_Class()SQLRETURN ShowResults()

Constructor Destructor

SQLRETURN printError( SQLHDBC SQLHSTMT)

Define The Class ConstructorCLI_ClassCLI_Class()

setlocale( LC_ALL )

Initialize The Return Code Variablerc = SQL_SUCCESS

Allocate An Environment Handlerc = SQLAllocHandle(SQL_HANDLE_ENV SQL_NULL_HANDLE ampEnvHandle)

Allocate A Connection Handleif (rc == SQL_SUCCESS)

rc = SQLAllocHandle(SQL_HANDLE_DBC EnvHandle ampConHandle)

Define The Class DestructorCLI_Class~CLI_Class()

Free The Connection Handleif (ConHandle = NULL)

SQLFreeHandle(SQL_HANDLE_DBC ConHandle)

Free The Environment Handle

52

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

if (EnvHandle = NULL)SQLFreeHandle(SQL_HANDLE_ENV EnvHandle)

Define The ShowResults() Member FunctionSQLRETURN CLI_ClassShowResults(void)

While There Are Records In The Result Data Set Generated Retrieve And Display Themcout ltlt Name Job Compensation ltlt endlcout ltlt --------- ------ ------------ ltlt endlcoutsetf(iosleft)coutprecision(2)coutsetf(iosfixed)while (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)

rc = SQLFetch(StmtHandle)if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)

coutwidth(15)cout ltlt Name

coutwidth(10)cout ltlt Job

coutwidth(7)cout ltlt Comp ltltendl

if(rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO ampamp rc = SQL_NO_DATA)printError(ConHandle StmtHandle)

else

rc = 0SQLCloseCursor(StmtHandle)

Return The ODBC API Return Code To The Calling Functionreturn(rc)

SQLRETURN CLI_ClassprintError (SQLHDBC hdbc

SQLHSTMT hstmt)

SQLCHAR buffer[SQL_MAX_MESSAGE_LENGTH + 1]SQLCHAR sqlstate[SQL_SQLSTATE_SIZE + 1]SQLINTEGER sqlcodeSQLSMALLINT lengthSQLRETURN rcwhile ((rc = SQLError(SQL_NULL_HENV hdbc hstmt

sqlstateampsqlcodebufferSQL_MAX_MESSAGE_LENGTH + 1amplength)) == SQL_SUCCESS || rc ==

SQL_SUCCESS_WITH_INFO)

cout ltlt SQLSTATE ltlt sqlstate ltlt endlcout ltlt SQLCODE ltlt sqlcode ltlt endlcout ltlt Error msg ltlt buffer ltlt endl

53

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

cout ltlt----------------------------- ltlt endl ltlt endl

return(SQL_ERROR)

----------------------------------------------------------------- The Main Function -----------------------------------------------------------------int main()

Declare The Local Memory Variables

(SQLCHAR ) db2user SQL_NTS (SQLCHAR ) test26t SQL_NTS)

SQLRETURNSQLCHARSQLCHARSQLCHARchar

SQLCHAR

rc = SQL_SUCCESSDBName[10] = TPLXSQLStmt[255]c[10]ptrcurrentDepartment[8][15] = Head Office

New England Mid Atlantic South Atlantic Great Lakes PlainsPacificMountain

Create An Instance Of The CLI_Class ClassCLI_Class Example

Connect To iSeries Database if (ExampleConHandle = NULL)

rc = SQLConnect(ExampleConHandle DBName SQL_NTS

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)ExampleprintError(ExampleConHandle SQL_NULL_HSTMT)

return(rc)

cout ltlt Successfully connected to ltlt DBName ltlt ltlt endlrc = SQLSetConnectAttr(ExampleConHandle SQL_ATTR_AUTOCOMMIT

(SQLPOINTER) SQL_AUTOCOMMIT_OFF SQL_IS_UINTEGER) Allocate An SQL Statement Handlerc = SQLAllocHandle(SQL_HANDLE_STMT ExampleConHandle

ampExampleStmtHandle)if (rc == SQL_SUCCESS)

Define A SELECT SQL Statement

strcpy((char ) SQLStmt select name job salary + ifnull(comm0) ascompensation )

ptr = strcat( (char ) SQLStmt from org o staff s )ptr = strcat( (char ) SQLStmt where odeptnumb = sdept)ptr = strcat( (char ) SQLStmt and deptname = )ptr = strcat( (char ) SQLStmt order by compensation desc)

Prepare The SQL Statementrc = SQLPrepare(ExampleStmtHandle SQLStmt SQL_NTS)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)ExampleprintError(ExampleConHandle ExampleStmtHandle)

54

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

return(rc)

Bind The Columns In The Result Data Set Returned To Application Variables

rc = SQLBindCol(ExampleStmtHandle 1 SQL_C_CHAR (SQLPOINTER)ExampleName sizeof(ExampleName) NULL)

rc = SQLBindCol(ExampleStmtHandle 2 SQL_C_CHAR (SQLPOINTER)ExampleJob sizeof(ExampleJob) NULL)

rc = SQLBindCol(ExampleStmtHandle 3 SQL_C_DOUBLE (SQLPOINTER)ampExampleComp sizeof(ExampleComp) NULL)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO) ExampleprintError(ExampleConHandle ExampleStmtHandle)

return(rc)

while (true)

for (int i = 0 i lt LOOPS i++)

rc=SQLBindParameter(ExampleStmtHandle1SQL_PARAM_INPUTSQL_C_CHARSQL_CHAR

150(SQLPOINTER) currentDepartment[i8]0NULL)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)

ExampleprintError(ExampleConHandle ExampleStmtHandle)return(rc)

rc = SQLExecute(ExampleStmtHandle)if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)

ExampleprintError(ExampleConHandle ExampleStmtHandle)return(rc)

cout ltlt endl ltlt Current Dept ltlt currentDepartment[i8] ltlt

endl Display The Results Of The SQL QueryExampleShowResults()if(rc = 0)break

if ( i500 == 0 ampamp i gt 0 )cout ltlt Loops ltlt i ltlt ltlt endl

cout ltlt AFTER ltlt LOOPS ltlt loops Press X to exit ltlt endlcin gtgt cif (c[0] == x || c[0] == X)

break

Free The SQL Statement Handleif (ExampleStmtHandle = NULL )

SQLFreeHandle(SQL_HANDLE_STMT ExampleStmtHandle) Disconnect From The Northwind Sample Databaserc = SQLDisconnect(ExampleConHandle)

Return To The Operating Systemreturn(rc)

55

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Extended Dynamic SQL and Statement Caching As mentioned the JTOpen data source object supports a number of properties that can be used to fine-tune the database performance In this section properties used to enable extended dynamic SQL support (see DB2 SQL Runtime Interfaces section above) and local statement caching will be discussed

Here is a relevant code excerpt from the deployDataSource method

AS400JDBCConnectionPoolDataSource tkcpds = new AS400JDBCConnectionPoolDataSource() hellip tkcpdssetExtendedDynamic(true)[1]tkcpdssetPackage(JDBCDS) [2]tkcpdssetPackageCache(true) [3]tkcpdssetPackageCriteria(select) [4]

At [1] the extended dynamic SQL support is enabled Note that the default is disabled for JTOpen The extended dynamic SQL functionality is often referred to as SQL package support The SQL packages are server-side repositories for SQL statements Packages contain the internal structures such as parse trees and access plans which are needed to execute SQL statements Because SQL packages are a shared resource the information built when a statement is prepared is available to all the users of the package This saves processing time especially in an environment where many users are using the same or similar statements Also because SQL packages are permanent this information is saved across job initiationtermination and IPLs In fact SQL packages can be saved and restored on other servers

At [2] the SQL package is named Note that the actual package name on the iSeries server is JDBCDSBAA The package name is generated by taking the name specified on the client and appending three letters that are an encoded set of the package configuration attributes By default an SQL package does not contain unparameterized select statements This behavior is overridden at [4] by setting the PackageCriteria property to select

At [3] the local statement cache is enabled A copy of the SQL package is cached on the AIX client This may improve application performance in a way similar to JDBC 30 statement caching Note however that local statement caching is not recommended for large SQL packages The copy of an SQL package is cached when the database connection is obtained This may cause increased network traffic as well as slow down the connection setup time

Reusable Open Data Paths (ODPs)An Open Data Path (ODP) definition is an internal i5OS object that is created when certain SQL statements (such as OPEN INSERT UPDATE and DELETE) are executed for the first time in a given job (or connection) The ODP can be thought of as a runtime implementation of an access plan The access plan created at the optimization time provides a recipe or in other words a sequence of steps necessary to execute the statement The ODP on the other hand provides the executable code for all requested IO operations The process of creating new ODP objects is fairly CPU- and IO-intensive so whenever possible the iSeries DB2 runtime tries to reuse existing ODPs For instance a ResultSetclose() call may close the SQL cursor but leave the ODP available to be used the next time the cursor is opened This can significantly reduce the response time in running SQL statements A reusable OPD usually requires 10 to 20 times less CPU resources than a newly created ODP Therefore it is important that the applications employ programming techniques that allow the DB2 runtime to reuse ODPs

With dynamic programming interfaces such as JDBC the most efficient way to avoid full opens is to employ the so-called prepare once execute many programming paradigm Ideally an SQL statement that is executed more than once should be prepared just once mdashfor example in the class constructor mdash and then reused for the consecutive executions At the prepare time the

9

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 engine stores the prepared statement along with the associated statement name in the QZDASOINIT jobs statement cache On the first execution the ODP created for a given statement is associated with the appropriate entry in the statement cache On consecutive executions the prepared statement and the corresponding ODP can be quickly located in the statement cache and reused The code snippet below illustrates the prepare once execute many programming technique

PreparedStatement pstmt = conprepareStatement(INSERT INTO COFFEES VALUES( ))[1] hellip for (int i = 0 i lt outerNumOfLoops i++)

insertfor (int j = 0 j lt numOfLoops j++)

pstmtsetString(1 Lavaza_ + IntegertoString(j)) hellip pstmtaddBatch()

int [] updateCounts = pstmtexecuteBatch()[2]concommit()

At [1] a PreparedStatement pstmt object is instantiated for a parameterized INSERT statement The statement is prepared just once The PreparedStatement object is then repeatedly used at [2] to perform blocked insert

Block Inserts Occasionally the developer may need to initially populate a table or insert a modified result set into a temporary table The efficiency of the insert operation for a large set of records can be dramatically improved by using the executeBatch method rather than the executeUpdate method The JTOpen driver converts parameterized insert statements in an executeBatch method to a block insert statement This significantly reduces the data flow and system resources required to perform the insert The following code snippet shows how to take advantage of the executeBatch method

10

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

PreparedStatement pstmt =conprepareStatement(INSERT INTO COFFEES VALUES( ))[1]for (int j = 0 j lt numOfLoops j++) pstmtsetString(1 Lavaza_ + IntegertoString(j))pstmtsetInt(2 i)pstmtsetFloat(3 499f)pstmtsetInt(4 0)pstmtsetInt(5 0)pstmtaddBatch() [2]

int [] updateCounts = pstmtexecuteBatch() [3]

At [1] a parameterized insert statement is prepared Note that all columns must be parameterized Otherwise the executeBatch method may throw the SQL0221 Number of rows 1 not valid exception In other words the developer should not mix parameter markers with literals or special registers in the VALUE clause

At [2] the addBatch method is used to add a new record to the client record buffer

At [3] all locally buffered data is sent to the server which in turn performs a block insert

Figure 4 shows the performance data for the executeBatch and executeUpdate methods

Figure 4 executeBatch() versus executeUpdate() performance comparison

11

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

WebSphere Considerations In certain situations an application provider may decide to deploy WebSphere Application Server in an AIX partition rather than natively in i5OS At the same time the application uses DB2 UDB for iSeries as an back-end database server Typically the WebSphere Application Server running in the AIX partition uses the virtual LAN to communicate with DB2 UDB for iSeries The WebSphere applications will access the database through a remote JDBC connection For performance and functionality reasons IBM recommends to utilize in such environments the IBM Toolbox for Java JTOpen driver Most of the tips and techniques described so far in this document hold true for WebSphere applications accessing DB2 UDB for iSeries There are however certain JDBC access aspects that are specific to this multi-tier architecture Letrsquos have a closer look at some of these considerations

Connection Pooling and Statement Caching

WebSphere Application Server provides its own connection pooling and statement caching mechanism that is by default enabled so that WebSphere applications automatically enjoy the performance benefits of these two critical programming techniques See the following link to learn more about the optimal connection pool setting in WebSphere

httppublibboulderibmcomwas40051englishinforzaiz51adminhelpudat_conpoolsethtml

Extended Dynamic SQL

For non-JTA connections WebSphere Application Server uses the comibmas400accessAS400JDBCConnectionPoolDataSource class as the iSeries JDBC provider implementation This is the DataSource implementation that has been used in all previous coding examples As mentioned the class supports a range of iSeries specific properties that can be used to fine tune JDBC performance These properties can be set through the WebSphere Application Server admin console For example herersquos the procedure to enable the extended dynamic SQL support In the WebSphere Application Server admin console navigate to the Data Source configuration dialog by selecting JDBC Providers -gt iSeriesToolbox -gt Data Sources then scroll down to the Additional Properties section Select Custom Properties link The Custom Properties dialog opens Scroll down to find the Extended Dynamic property and select it Change the default value false to true save the new configuration by clicking Apply button This is illustrated in Figure 5

12

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 5 Enabling the extended dynamic SQL through WebSphere Application Server console

The WebSphere Application Server needs to be restarted for the change to take effect The similar procedure can be followed to set other iSeries Data Source properties

Changing the WebSphere Application Server default isolation level

WebSphere Application Server V5 uses the REPEATABLE_READ (RR) isolation level for all implicit (WebSphere Application Server managed) transactions With the RR isolation level the rows selected updated deleted and inserted are locked until the end of the transaction Under certain circumstances this fairly extensive locking policy may cause locking contention especially when a WebSphere application competes for database resources with other applications that run on iSeries server For example a legacy order entry application may share data with the e-business customer care application running in WebSphere The locking contention may sometimes be eliminated by lowering the isolation level used by WebSphere Although the iSeries Data Source supports the custom transactionIsolation property resetting this property on the Data Source object will not change the default isolation level used by WebSphere for the connection objects produced by that Data Source In other words WebSphere will override the Data Source isolation level setting at the time the connection is obtained by a WebSphere application object such as servlet or Enterprise Java Bean (EJB) In order to change the default WebSphere behavior one must use the resource referencing Resource referencing allows a programmer to lookup DataSource or EJB objects using alias names rather than JNDI names Additionally by creating a resource reference a programmer can change certain properties of the underlying object Specifically a DataSource reference can be used to set a different isolation level for the connections produced by this database resource Typically resource references are defined by a programmer in a application development tool such as WebSphere Studio Application Developer The method to specify a DataSource reference differs depending on whether a programmer plans to use the reference in a servlet or in an EJB Letrsquos start with outlining the configuration process for a servlet In WebSphere Studio Application Developer open the deployment descriptor editor for the web project that contains the servlet To do so double click on the webxml file under WEB-INF directory in the web project In the deployment editor dialog select the References tab and then select Resource tab located in the top of the dialog that appears Under Resource References section select the Add button Herersquos an example of a DataSource reference created for iSeries DataSource named TestJDBCDS Note that the reference changes the default isolation level to READ_COMMITTED

13

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 6 Defining a resource reference for a servlet

Once the resource reference has been defined and saved the servlet source code needs to be changed to reflect the fact that a resource reference is used to obtain a DataSource from the JNDI service Herersquos the relevant code snippet try

ctx = new InitialContext() ds = (DataSource)ctxlookup(javacompenvTestJDBCJ2C)

catch (Exception e) eprintStackTrace(out)

Now the ds DataSource object will produce connections that by default run with the isolation level of READ_COMMITTED (RC)

As mentioned the process of defining a resource reference for an EJB differs from the process that is used in the case of a servlet In WebSphere Studio Application Developer open the deployment descriptor editor for the EJB project that contains the EJB To do so double click on the ejb-jarxml file under WEB-INF directory in the project In the deployment editor dialog select the References tab In the references section on the left locate and select the EJB for which the developer wants to change the default isolation level Click the Add button The Add Reference dialog opens Click the Resource Reference radio button and then Next Define the reference following the example shown in Figure 7

14

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 7 Adding a resource reference for an EJB

When you click ldquoFinishrdquo the reference definition is added to the EJB descriptor The new definition needs to be further modified To do so click on the (+) sign next to the EJB in the References list Click the new reference TestJDBCJ2C in this example to open the properties for the reference Change WebSphere Bindings and WebSphere Extensions sections as illustrated in Figure 8

15

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 8 Defining a resource reference for an EJB

Save the modified definition and then change the EJB source code to use the reference rather than directly DataSource

TroubleshootingTroubleshooting a multi-tier application may be a bit tricky because the developer needs to deal with software components that reside in separate partitions Three tools are particularly useful for pinning down the potential problem areas bull Joblog messages for a database server job mdash Provides enough details to isolate DB2 UDB for

iSeries runtime issues bull JDBC trace utility mdash Provides granular information about the data flow between the AIX

application and the iSeries server job bull Database Monitor ndash Provides detailed SQL runtime trace

Job Log MessagesAs mentioned a DB2 client communicates with a corresponding iSeries server job This server job runs the SQL requests on behalf of the client The iSeries database server jobs are called QZDASOINIT and they run in the QUSRWRK subsystem At any given time a large number of database server jobs may be active on the server so the first step is to identify the job that serves the particular client connection The easiest method to accomplish this task is to run the following CL command from the i5OS prompt

WRKOBJLCK OBJ(DB2USER) OBJTYPE(USRPRF)

Here DB2USER is the user profile that is used to connect to the iSeries server Note that a QZDASONIT job is assigned to a client after the connection has been established so the developer needs to set a breakpoint in the client application after the database connection has been established

Once the Work with Object Locks appears key in 5 (Work with Job) next to the only QZDASOINIT job that should be listed This shows the Work with Job dialog Select option 10 to

16

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

display the job log for the database server job Now the job log can be searched for any error messages generated by the DB2 runtime

Sometimes it is also useful to include debug messages in the job log The debug messages are informational messages written to the job log about the implementation of a query They describe query implementation methods such as the use of indexes join order ODP implementation (reusable versus non-reusable) and so on The easiest way to instruct an iSeries server to include the debug messages is to set the ServerTraceCategories property on the data source object

tkcpdssetServerTraceCategories(AS400JDBCDataSourceSERVER_TRACE_DEBUG_SERVER_JOB)

A sample of the job log messages with debug messages enabled is shown below

SET TRANSACTION completeSTATEMENT NAME FOUND QZ868F0A458E13AF8C Starting optimizer debug message for query Arrival sequence access was used for file COFFEESODP created ODP not deleted 5000 rows inserted in COFFEES in DB2USER STATEMENT NAME FOUND QZ868F0A4C144BF12EBlocking used for queryCursor CRSR0001 opened606 rows fetched from cursor CRSR0001 ODP not deleted Cursor CRSR0001 closed

So the job log offers fairly detailed information on how the AIX client requests were implemented by the DB2 runtime

JDBC Trace UtilityThe JTOpen driver provides a tracing utility which can be used to collect detailed client-side traces The JDBC tracing is turned off by default It can be enabled by setting the Trace property to true Heres an example of how to switch on tracing using the setTrace method on the data source object

tkcpdssetTrace(true)

The trace can also be enabled when using the DriverManagergetConnection() method for obtaining a connection to DB2 UDB for iSeries In this case the developer could add the trace property to the connection string This approach is illustrated in the following code snippet

ClassforName(comibmas400accessAS400JDBCDriver) [1] hellip con = DriverManagergetConnection(jdbcas400teraplextrace=true

db2userdb2pwd) [2]

At [1] an instance of the JTOpen JDBC Driver is initiated Then at [2] the driver is used to obtain a connection to the iSeries server Note how the trace property has been added to the database URL See the IBM Toolbox for Java JDBC properties documentation on the iSeries Information Center Web site for a complete list of properties supported by the JTOpen driver

Although the level of details provided by the trace utility is sufficient in most troubleshooting scenarios sometimes the developer may need to collect low-level traces scoped to a certain type

17

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

of information In V5R3 the IBM Toolbox for Java (as well as the latest JTOpen) added a comprehensive detailed trace facility The following is the complete list of detailed trace parameters and their purpose

bull None or ldquordquo ndash This setting disables the detailed trace bull datastream - This category is used by Toolbox classes to log dataflow between the local host

and the remote system It is not intended for use by application classes bull diagnostic - This category is used to log object state information bull error - This category is used to log errors that cause an exception bull information - This category is used to track the flow of control through the code bull warning - This category is used to log errors that are recoverable bull conversion - This category is used by Toolbox classes to log character set conversions

between Unicode and native code pages bull proxy - This category is used by Toolbox classes to log data flow between the client and the

proxy server bull pcml - This category is used to determine how PCML interprets the data that is sent to and

from the server bull jdbc - This category is used to track JDBC calls throughout the program bull thread - This category is used to enable tracing of thread information This is useful when

debugging multi-threaded applications bull all - This category will enable all previous categories

The detailed trace can be enabled when using the DriverManagergetConnection() method for obtaining a connection to DB2 UDB for iSeries In this case the developer could add the toolbox trace property to the connection string This is illustrated in the following code sample

String dbUrl = jdbcas400pwd1toolbox trace=diagnostic con = DriverManagergetConnection(dbUrl dbUser dbPassword)

Note that currently the driverrsquos DataSource interfaces do not allow the developer to directly activate the detailed tracing However they could set the server from the command line at the time the java program is launched The example below shows how the detailed trace properties could be enabled at the command line

java -Dcomibmas400accessTracecategory=diagnostic TestJDBC

The -D switch indicates to the java interpreter that the information following it will be a system property

In case of a WebSphere application the trace property can be set through the admin console In the console select Application Servers-gt server1-gt Process Definition -gt Java Virtual Machine Figure 9 shows how to set the Generic JVM Arguments for an application server instance

18

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 9 Setting JVM arguments to enable detailed Toolbox tracing

Database Monitor

The database monitor is the ultimate tool available on DB2 UDB for iSeries to collect low-level SQL traces It is mainly used to pin down the SQL performance problems Refer to the lsquoUsing iSeries Database Monitor to Identify and Tune SQL Queriesrsquo white paper for a detailed discussion on how to collect and analyze the database monitor traces httpibmcomserversenablesiteeducationiborecordhtmldtmon

IBM DB2 JDBC Universal Driver DB2 JDBC Universal Driver is one of the new features delivered with DB2 UDB Version 8 DB2 JDBC Universal Driver has been designed to eliminate the dependency on DB2 CLI runtime modules as well as to enable direct Type 4 connectivity to DB2 UDB for iSeries and DB2 UDB for zOSreg

The pure-Java (Type 4) remote connectivity is based on the DRDA open distributed protocol for cross-platform access to DB2 DRDA defines the rules the protocols and the semantics for accessing distributed data Applications can access data in a distributed relational environment by using SQL statements The iSeries DRDA application server implementation is based on multiple connection-oriented server jobs running in the QSYSWRK subsystem A DRDA listener job (QRWTLSTN) listens for TCP connect requests on port 446 Once an application requester connects to the listener job the listener wakes up one of the QRWTSRVR prestart jobs and assigns it to a given client connection Any further communication occurs directly between the client application and the QRWTSRVR job These concepts are illustrated in Figure 10

19

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 10 Accessing DB2 UDB for iSeries with DB2 Universal Driver

The DB2 Universal Driver can be loaded in an AIX partition by installing one of the DB2 Connect for AIX products (see the Additional Information section for details) It is also a part of a DB2 Enterprise Server Edition for AIX install Specifically the developer needs three JAR files in a AIX partition to successfully connect to an iSeries server db2jccjar db2jcc_license_cisuzjar and db2jcc_license_cujar The iSeries license is contained in db2jcc_license_cisuzjar Note that this file is not a part of DB2 Client In other words a DB2 Connect license is required to use the driver in production environments The location of the JAR files needs to be added to the CLASSPATH environment variable For instance the following entry could be added to the AIX profile script

CLASSPATH=homedb2inst2sqllibjavadb2jccjarCLASSPATH=$CLASSPATHhomedb2inst2sqllibjavadb2jcc_license_cujarCLASSPATH=$CLASSPATHhomedb2inst2sqllibjavadb2jcc_license_cisuzjarexport CLASSPATH

Java Runtime 131 is a prerequisite

Additionally the developer should install the latest database group PTF (SF99503 for i5OS V5R3) on the iSeries server The Informational APAR ii13348 is keeping track of any fixes relevant to DRDA above and beyond the current database group PTF

Obtaining a Connection to DB2 UDB for iSeries When Type 4 connectivity is used the DB2 Universal Driver connects directly to the DB2 on iSeries through TCPIP Note that this is different from the legacy DB2 Type 2 JDBC driver that requires a DB2 node and remote database configurations on the client accessing iSeries The following code snippet illustrates how to use the DB2 JDBC Universal Driver to obtain a connection to DB2 UDB for iSeries

20

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

try ClassforName(comibmdb2jccDB2Driver) [1] catch(javalangClassNotFoundException e) Systemerrprint(ClassNotFoundException )Systemerrprintln(egetMessage())

try DriverManagergetConnection(jdbcdb2teraplex446TERAPLEX[2]

db2userdb2pwd) hellip catch(SQLException ex) Systemerrprintln(

SQLException + exgetMessage())

At [1] an instance of the DB2 JDBC Universal Driver is instantiated Then at [2] the driver is used to obtain a connection to the iSeries server Note the proper form of the database URL required by the driver

Considerations There are several advantages of DB2 JDBC Universal Driver bull Ease of cross-platform development mdash Consistent coding techniques and consistent error

codes and messages bull Ease of deployment mdash Pure Java (no runtime client required) and a single driver for accessing

DB2 on different platforms

The ease of use comes at a price though The iSeries JTOpen driver is optimized for accessing DB2 UDB for iSeries data and it uses native iSeries protocol to communicate with the back-end database server job This usually results in better performance and more-efficient system resources utilization For instance when using the DB2 JDBC Universal Driver to access an iSeries server the executeBatch method results in a single record insert There are also some restrictions when using DB2 Universal JDBC Driver with Type 4 connectivity

bull Support for distributed transactions (JTA) is not enabled bull Driver built-in connection pooling is not supported

Refer to Java application support in DB2 for more details on DB2 JDBC Universal Driver

21

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 Connect data access This section will explore the most important aspects of DB2 Connect ndash iSeries integration - including configuration tips and coding examples

DB2 Connect provides functionality for accessing data stored in DB2 UDB for iSeries as well as DB2 UDB for zOS and DB2 UDB for OS390reg DB2 Connect offers capabilities to access DB2 family members via several SQL interfaces gateway functions such as connection pooling and federated database functionality Many applications supporting the DB2 family of products leverage DB2 Connect as a key middleware component DB2 Connect is offered as separate AIX license products

Enterprise Edition Application Server Edition

In addition to DB2 Connect there are several other DB2 UDB Version 81 products that are supported on AIX

DB2 Universal Database Enterprise Server Edition DB2 Universal Database Workgroup Server Unlimited Edition DB2 Universal Database Workgroup Server Edition DB2 Universal Database Universal Developers Edition All Clients

The DB2 Connect Enterprise Edition functionality is also contained in DB2 Enterprise Server Edition for AIX

22

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 Connect in a nutshell In the scenario described in this paper the DB2 Connect functions contained in DB2 Enterprise Edition for AIX are utilized DB2 Connect Enterprise Edition provides support for both local and remote DB2 clients This is illustrated in Figure 11 Accessing DB2 UDB for iSeries with DB2 Connect

Figure 11 Accessing DB2 UDB for iSeries with DB2 Connect

DB2 Connect implements the Distributed Relational Database Architecturetrade (DRDAreg) to reduce the cost and complexity of accessing data stored in DB2 UDB for iSeries and other DRDA-compliant database servers DRDA defines the rules the protocols and the semantics for accessing distributed data Applications can access data in a distributed relational environment by using SQL statements In a distributed environment the system running the application and sending the SQL requests across the network is called the application requester (AR) A remote database server that executes SQL requests submitted by an application requester is known as the application server (AS) In the example shown in Figure 11 (above) DB2 Connect plays the role of an application requester while DB2 UDB for iSeries is an application server In this case DB2 Connect communicates with the iSeries database through TCPIP The iSeries DRDA application server implementation is based on multiple connection-oriented server jobs running in the QSYSWRK subsystem A DRDA listener job (QRWTLSTN) listens for TCP connect requests on port 446 Once an application requester connects to the listener job the listener wakes up one of the QRWTSRVR prestart jobs and assigns it to a given client connection Any further communication occurs directly between the client application and the QRWTSRVR job

DB2 Connect supports a wide range of programming interfaces that can be used by AIX applications to access the iSeries database Embedded SQL frac34 Both static and dynamic SQL frac34 Various programming languages (Java CC++ Cobol Fortran REXX)

DB2 Call Level Interface (DB2 CLI) ODBC JDBC frac34 DB2 JDBC Type 2 Driver frac34 DB2 JDBC Type 4 Driver (Universal JDBC Driver)

23

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Note that DB2 Connect supports access to DB2 UDB for iSeries through DB2 JDBC Universal driver However for performance and ease of maintenance reasons IBM recommends that Java applications running in AIX use native iSeries Toolbox JDBC driver See the JDBC Data Access section of this paper (above) for more details On the other hand DB2 Connect is a very efficient and robust connectivity option for AIX applications especially in the environments that are not directly supported by the native iSeries JDBC driver Here are several possible scenarios that would require DB2 Connect installed in a AIX partition

Embedded SQL interface is used to access DB2 CLI or ODBC interface is used to access DB2 A single SQL interface is needed to access multiple back end DB2 server Specific DB2 Connect functionality is needed such as distributed join or connection

pooling

Prerequisites One of the DB2 Connect products or DB2 Enterprise Server Edition for AIX V81 is needed Additionally DB2 Application Development Client is required in the AIX partition to compile DB2 applications

For maximum database server stability the developer should install the latest database group PTF (SF99503 for i5OS V5R3) on the iSeries server The Informational APAR ii13348 is keeping track of any fixes relevant to DRDA above and beyond the current database group PTF

DB2 Connect configuration The following example employs i5OS V5R3 and DB2 UDB Enterprise Server Edition for AIX Version 81 FixPak 6

Configuration steps in the iSeries partition The following process lists the necessary steps to be performed on the iSeries server 1) Verify that the TCPIP stack is working correctly It is assumed that the Virtual LAN is used to

communicate with the i5OS partition First obtain the IP address of the iSeries server or its hostname and ping the iSeries server from the AIX partition

2) Create a relational database (RDB) entry for the iSeries database in the i5OS partition If this has already been created it can be displayed by using the DSPRDBDIRE command Make sure that the RDB entry with a location of LOCAL exists on the iSeries server If it does not exist use the ADDRDBDIRE command to add the appropriate RDB entry For example the following command would add an RDB entry named TPLX For simplicity it is recommended that the TCPIP host name and RDB entry remain the same

ADDRDBDIRE RDB(TPLX) RMTLOCNAME(LOCAL)

3) Create a collection called NULLID This is necessary because the utilities shipped with DB2 Connect and DB2 UDB for AIX store their packages in the NULLID collection Since it does not exist by default in the iSeries server you must create it using the following command

CRTLIB LIB(NULLID)

4) Products that support DRDA automatically perform any necessary code page conversions at the receiving system For this to happen both systems need a translation table from their code page to the partner code page The default Coded Character Set Identifier (CCSID) on the iSeries server is 65535 Since DB2 Connect does not have a translation table for this code page the developer needs to change the individual user profiles to contain a CCSID that can be converted properly by DB2 Connect For US English this is 037 For other languages see DB2 Connect Personal Edition Quick Beginning GC09-2967 The following command changes the CCSID for an individual user profile to 037

24

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

CHGUSRPRF userid CCSID(037)

5) Verify that the default port 446 for DRDA service is being used To do this go to the Configure TCPIP menu (CFGTCP) select Configure Related Tables and then select Work with service table entries Verify that the DRDA service is set for port 446

6) The Distributed Data Management (DDM) job must be started for DRDA to work If you want the DDM job to be automatically started whenever TCPIP is started change the attributes of the DDM job using the CHGDDMTCPA command and set the Autostart server parameter to YES

7) If the system administrator chooses not to autostart the server issue the following command to start the DDM server job

STRTCPSVR SERVER(DDM)

8) Make sure that the user profiles that will be used to connect to the iSeries server exist on the server

25

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Configuration steps in the AIX partition The following steps are required for DB2 Connect to be configured in the AIX partition 1) Sign on to the AIX partition as the DB2 administrator 2) Launch Client Configuration Assistant (db2ca from the command prompt) It is assumed that

VNC or an X-Windows server are being used on the workstation so that the db2ca GUI can be properly rendered

3) From the Selected pull-down menu select the Add Database using Wizard option The Select how you want to setup a connection dialog appears Select Manually configure a connection to a database and click Next This is shown in Figure 12

Figure 12 Accessing DB2 UDB for iSeries with DB2 Connect

26

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

4) On the Select a communications protocol choose TCPIP and select The database physical resides on a host or OS400 system Then select the option Connect directly to the server as shown in Figure 13 Click Next

Figure 13 mdash Selecting communications protocol

27

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

5) On the TCPIP tab fill in the host name of the iSeries server The port number should be 446 This is shown in Figure 14 Click Next

Figure 14 mdash Specifying TCPIP communication parameters

28

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

6) On the Database tab fill in the Relational Database name Use the RDB entry name (specified in step 2) in the Configuration steps in the iSeries partition section as shown in Figure 15 Click Next

Figure 15 mdash Specifying the remote database

7) If you plan to use the ODBC applications select Register this database for ODBC as a system data source on the ODBC tab Click Next

29

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

8) On the Specify the node option dialog select OS400 from the Operating System pull-down menu This is shown in Figure 16 Click Finish

Figure 16 mdash Specifying the node options

30

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

9) The Test Connection dialog appears This allows the developer to verify that the connection works Select both CLI and JDBC check boxes You are also prompted for an iSeries user ID and password as shown in Figure 17

Figure 17 mdash Testing the connection

31

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

10) The successful connection to the database server is confirmed by the message box shown in Figure 18

Figure 18 mdash Test Connection results 11) At this time a newly configured database connection should appear in the main DB2

Configuration Assistant window It is recommended that the DB2 utilities are also bound to the iSeries database The bind process creates the necessary SQL packages on the remote database In the main Configuration Assistant window click the TPLX database entry and then select Selected-gtBindhellip

32

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

12) The Bind dialog appears Click Select All and then enter the connection information as shown in Figure 19 Click Bind The Results message box appears This allows the developer to monitor the progress of the binding process Watch for any error and warning messages

Figure 19 mdash Binding the DB2 utilities This concludes the DB2 Connect configuration steps

33

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Accessing DB2 UDB for iSeries from C embedded SQL

As mentioned earlier DB2 Connect allows developers to compile and run embedded SQL applications that access DB2 UDB for iSeries data This section covers implementation details for a C embedded SQL application called cursorsjsqc (see Appendix B for source code)

Prerequisites An embedded SQL application running in an AIX partition will use DB2 Connect services to access DB2 UDB for iSeries therefore the developer needs to make sure that all components listed in section Prerequisites on page 24 are installed The developer also needs to create a remote database connection as described in the DB2 Connect configuration section of this paper on page 24

Static SQL and SQL packages To successfully run against a DB2 UDB for iSeries database an embedded SQL application needs to be first precompiled and bound to the back-end database This process creates an SQL package on the target iSeries server The SQL package contains the access plan information for the SQL statements executed by the application The internal structure of the package as well as the method how its content is used by the SQL runtime to facilitate the access plan reuse is similar to the Extended Dynamic SQL support covered in detail in the Extended Dynamic SQL and Statement Caching section of this paper (on page 9) There are however important differences between the packages created by the extended dynamic SQL support and the packages created for embedded SQL DRDA client applications The extended dynamic SQL packages support dynamic SQL interfaces such as JDBC

that can submit ad hoc SQL statements at the run time The SQL runtime can prepare the dynamic statements and add them to the package On the other hand the DRDA packages are created at the precompile time and contain static SQL In order to add new statements to the package the application needs to be precompiled and rebound again

The extended dynamic SQL package can dynamically grow up to 500MB by allocating new space as required The DRDA packages since they are created at the precompile time have a fix size and do not grow over their life time

Simple embedded SQL application The application is based on a source code provided in the DB2 UDB samples directory typically to be found at homedb2inst1sqllibsamples The cursorsjsqc performs a join between STAFF and ORG tables located in DB2USER schema (library) on the TPLX database server (the source is provided at the end of this paper in Appendix B) The join statement retrieves the DEPTNAME column from ORG NAME column from STAFF and calculates the total compensation for an employee by adding SALARY and COMM columns in STAFF The results are sorted by department name and total compensation Here is the SELECT statement used by the application

SELECT deptname name salary + IFNULL(comm0) as compensationFROM org o staff sWHERE odeptnumb = sdeptORDER BY deptname compensation DESC

The application iterates through the selected records and prints out the data to the standard output device The sample DB2USER schema was created with the following SQL statements

db2 CONNECT TO tplx USER db2user USING mypassworddb2 CALL QSYSCREATE_SQL_SAMPLE(DB2USER)

34

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Make sure that the AIX partition is logged into with the DB2 admin user profile If the defaults were selected at the DB2 installation time this profile name is db2inst1 It is also assumed that DB2USER user exists on the iSeries server and that it has appropriate authority

There are several steps that are required to create an executable for the cursorsjsqc source code First the DB2 PRECOMPILE utility needs to be called The utility creates a bind file that is used to bind the required SQL package to the TPLX database It also converts embedded SQL statements into DB2 run-time API calls and produces a pure C source file that can be processed by an AIX C compiler

db2 CONNECT TO tplx USER db2user USING mypassworddb2 prep cursorsjsqc bindfile

Note that the connect statement is required only if the developer is not already connected to the database on an iSeries server Watch for any error or warning messages returned by the DB2 prep utility The prepare step should produce cursorsjbnd and cursorsjc files in the current directory Now the developer can invoke the bind utility to prepare the statements contained in the bind file and create the package on the target iSeries database server

db2 bind cursorsjbnd

It is assumed that Visual C++ 60 is installed and configured in the AIX partition Refer to the ldquoDeveloping and Porting C and C++ Applications on AIXrdquo redbook for more information on how to use the Visual C++ compiler httpibmcomredbooksabstractssg245674htmlOpen

Use the following commands to compile the C source generated by the precompile utility

xlc -I$INSTHOMEsqllibinclude ndashc cursorsjcxlc ndasho cursorsj cursorsjo -L$INSTHOMEsqlliblib ndashldb2

Run the program from the AIX prompt

cursorsj db2user mypassword

Distributed Join DB2 UDB Version 8 provides core federated server functionality A federated system consists of a DB2 UDB instance that operates as a federated server a database that acts as the federated database one or more data sources and clients (users and applications) that access the database and data sources Federated server permits objects stored in multiple databases to be accessed together in the same query For example a query can refer to a table that resides in DB2 UDB for iSeries and join it to a table stored in DB2 UDB for AIX Such a query would constitute so called distributed join The support for DB2 UDB for iSeries as a federated data source is provided by core federated server functionality directly implemented in DB2 UDB Enterprise Server Edition and DB2 UDB Connect Enterprise Edition All other DB2 UDB family members are also supported directly by core DB2 UDB federated server An additional software product DB2 Information Integratortrade is required to access non-DB2 UDB databases such as Oracle Sybase or Microsoftreg SQL Server Consult the following white papers for a detailed discussion on DB2 federated server support Heterogeneous data access for iSeries applications Version 2 httpibmcomserversenablesiteeducationiborecordhtmlhetdata Fundamentals of IBM DB2 Federated Server and Relational Connect httpwww7bsoftwareibmcomdmddlibrarytecharticle0206purnell0206purnellhtml

35

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Distributed Join Example In this section the steps that are required to configure DB2 UDB for iSeries as a federated data source will be illustrated Then the cursorsjsqc program will be ldquotweakedrdquo so that it executes a distributed join query that accesses data stored on an iSeries server and in the local DB2 UDB for AIX database It is assumed that the developer is familiar with the DB2 federated server concepts

Note Run the following commands from the Command Line Processor prompt Load the utility by executing the db2 command at the AIX prompt 1) First the local DB2 UDB for AIX instance needs to be enabled as a DB2 federated server

This is done by setting the database manager configuration parameter FEDERATED to YES

db2=gt update dbm cfg using FEDERATED YES

The database instance needs to be restarted for the change to take effect

NOTE A federated database is a regular database in a DB2 UDB instance that has the FEDERATED parameter enabled Therefore in this example the SAMPLE database that was created earlier is used as the federated database A new database can also be created using the CREATE DATABASE command

2) Connect to the federated database

db2=gt connect to sample

3) Use the CREATE WRAPPER statement to register a wrapper for the iSeries data source Wrappers are library routines that are used by the federated server to perform operations such as connecting to a data source and retrieving data from it The default wrapper name for DB2 UDB for iSeries is DRDA Here is the command to register the DRDA wrapper

db2=gt create wrapper drda

4) Use the CREATE SERVER statement to register a data source as a server within the federated database The server definition specifies the type and version of the data source and the wrapper used for communications with this data source For the DB2 UDB for iSeries data source the node and the database names are also needed The node and database name parameters have been configured for our TPLX database in the Configuration steps in the AIX partition section (on page 24) Use the following DB2 UDB command to lookup these parameter on the federated server

db2=gt list database directory

In this case the command produced the following output

Database alias = TPLX Database name = DCSE99E1 Node name = NDE9BF76 Database release level = a00 Comment = Directory entry type = Remote Authentication = SERVER Catalog database partition number = -1

36

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Note that the node name is set to NDE9BF76 The name was generated by the Configuration Administrator utility (db2ca)

Here is the command to register the TPLX database as a federated server

db2=gt create server tplx type db2400 version 530 wrapperdrda authorization db2user password mypassword options(nodeNDE9BF76 dbname TPLX)

The command is quite complex so make sure that the syntax is correct

5) Define the user mappings that instructs the federated server what user ID and password should be used when connecting to the iSeries data source

db2=gt create user mapping for user server tplxoptions(remote_authid db2user remote_password mypassword)

Specify the nickname for the iSeries table or view A nickname is an identifier that is used by the federated server to reference an object located at the data source The following command creates a nickname for the STAFF table located in the DB2USER schema on the TPLX database

db2=gt create nickname tplx_staff for tplxdb2userstaff

6) Test the distributed join query

db2=gt SELECT deptname name salary + COALESCE(comm0) ascompensation FROM org o tplx_staff s WHERE odeptnumb =sdept ORDER BY deptname compensation DESC

Note that the native iSeries function IFNULL has been substituted with an equivalent DB2 UDB function COALESCE COALESCE is also supported on iSeries servers For better portability IBM encourages the use of COALESCE rather than IFNULL Note also that the query runs on the federated server rather than on TPLX It accesses the ORG table in the local DB2 UDB for AIX SAMPLE database and the STAFF table that resides in TPLX The federated server performs the necessary distributed join

7) Modify the cursorsjsqc so that it executes a distributed join There are two source code modifications - Change the CONNECT TO statements Now the application needs to connect to the

federated database SAMPLE rather than to TPLX

EXEC SQL CONNECT TO SAMPLEEXEC SQL CONNECT TO SAMPLE USER userid USING passwd

- Modify the select statement so that it performs a distributed join Use the statement (shown in step 6) above Save the new source version as cursordjsqc

- Prepare bind and compile the distributed join version of the program as described in the Simple C embedded SQL application section (on page 34)

db2 prep cursordjsqc bindfiledb2 bind cursordjbndxlc -I$INSTHOMEsqllibinclude ndashc cursordjcxlc ndasho cursordj cursordjo -L$INSTHOMEsqlliblib ndashldb2

37

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

- Run the program from the AIX prompt

cursordj

Connection Pooling and Connection ConcentratorA modern Web-based application typically executes a large number of short-lived transactions Executing a transaction in this environment means establishing a database connection executing a few SQL statements and terminating this connection Creating connections to the database server is a very costly process To reduce the unnecessary workload DB2 Connect implements connection pooling and connection concentrator Connection pooling mechanism allows DB2 Connect to reuse an existing connection infrastructure for subsequent connection requests The connection concentrator is an advanced technology that allows DB2 Connect to serve a potentially very large number of clients with a limited number of database connections This is accomplished by decoupling clients from a particular database connection

Note that currently neither connection pooling nor connection concentrator support DB2 UDB for iSeries Therefore for performance reasons the author strongly recommends that the application server that obtains and drops connections very frequently implements its own database connection pooling mechanism that would assign an existing pooled database connection to a new AIX process or thread

TroubleshootingTroubleshooting a multi-tier application may be a bit tricky because the developer needs to deal with software components that reside in separate partitions The authorrsquos experience shows that two tools are particularly useful for pinning down the potential problem areas The joblog messages for a database server job usually provide enough details to isolate DB2

UDB for iSeries runtime issues The DRDA trace utility provides granular information about the data flow between the AIX

application and the iSeries server job

38

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Job Log MessagesAs mentioned earlier a DB2 client communicates with a corresponding iSeries server job This server job runs the SQL requests on behalf of the client More precisely when a DB2 client submits an SQL statement the statement is passed to a server job that in turn calls the DB2 runtime to execute the statement The results are then reformatted and marshaled to the client The iSeries DRDA server jobs are called QRWTSRVR and they run in the QUSRWRK subsystem At any given time there may be a large number of DRDA server jobs active on the system so the first step is to identify the job that serves the particular client connection The easiest method to accomplish this task is to run the following CL command from the i5OS prompt

WRKOBJLCK OBJ(DB2USER) OBJTYPE(USRPRF)

Here DB2USER is the user profile that is used to connect to the iSeries server Note that a QRWTSRVR job is assigned to a client after the connection has been established so the developer needs to set a breakpoint in the client application below the CONNECT TO statement

Once the Work with Object Locks appears key in 5 (Work with Job) next to the only QRWTSRVR job that should be listed This shows the Work with Job dialog Select option 10 to display the job log for the database server job Now the developer can search the job log for any error messages generated by the DB2 runtime

Sometimes it is also useful to include debug messages in the job log The debug messages are informational messages written to the job log about the implementation of a query They describe query implementation methods such as use of indexes join order ODP implementation (reusable versus non-reusable) and so on The easiest way to instruct the iSeries server to include the debug messages is to call the following stored procedure just after the connection to the iSeries server is established

EXEC SQL call qsysqcmdexc(STRDBGUPDPROD(YES)000000002000000)

A sample of the job log messages with debug messages enabled is shown below in Figure 20

Arrival sequence access was used for file STAFFAccess path suggestion for file STAFFQuery options used to build the OS400 query access plan Ending debug message for query ODP created Blocking used for queryCursor SQLCUR201 opened1 rows fetched from cursor SQLCUR201Row not found for SQLCUR201ODP deleted Cursor SQLCUR201 closedDESCRIBE of prepared statement STMT0201 completed

Figure 20 mdash Joblog with debug messages enabled

So the job log offers fairly detailed information on how the AIX client requests were implemented by the DB2 runtime

39

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 DRDA trace utilityThe DB2 DRDA trace utility (db2drdat) provides detailed information about the data streams exchanged between DB2 Connect and target database server The output file produced by the utility contains send and receive communications buffers TCPIP error messages and SQL Communications Area (SQLCA) information Please refer to lsquoDB2 Connect Userrsquos Guidersquo manual for in-depth discussion of the DRDA trace utility

Accessing DB2 UDB for iSeries from CLI DB2 Call Level Interface (CLI ) is based on the Microsoft Open Database Connectivity (ODBC) specification and the ISO CLI standard The DB2 CLI interface gained popularity among DB2 application providers because the developer can build an ODBC application by simply linking the application with libdb2 library on a UNIX server In other words the developer directly utilizes the DB2 ODBC driver services without a need for an ODBC driver manager Additionally in contrast to embedded SQL the developer does not need to precompile or bind DB2 CLI applications because they use packages provided with DB2 UDB The developer simply compiles and links the application

Prerequisites A DB2 CLI application running in an AIX partition will use DB2 Connect services to access DB2 UDB for iSeries therefore make sure that all components listed in Prerequisites section of this paper on page 24 are installed The developer also needs to create a remote database connection as described in the DB2 Connect configuration section of this paper on page 24

Dynamic SQL and Access Plan Caching A DB2 CLI client application uses the dynamic SQL interface and does not have the capability to utilize the extended dynamic SQL support Therefore it runs lsquopurersquo dynamic SQL statements That does not mean however that the process of parsing validating and optimizing will be repeated for every execution of a given dynamic SQL statement

The DB2 UDB for iSeries database implements an internal object called System-Wide SQL Statement Cache (SWSC) The SWSC can improve the performance of programs using dynamic SQL statements by caching the access plans in a system-wide cache When a dynamic SQL statement is submitted the SQL runtime searches the SWSC to see if this statement has been previously executed If so then DB2 retrieves and reuses the key information associated with the cached statement and thereby the processing time and the resources utilization can be significantly reduced

Simple DB2 CLI C++ ApplicationThis section covers DB2 CLI implementation details for a sample C++ program called testclicpp (the source is provided at the end of this paper in Appendix C) To compile the source with Visual C++ complier use the following command in the AIX partition

xlC ndashI$INSTHOMEsqllibinclude ndashc testclicppxlC ndasho testcli testclio ndashL$INSTHOMEsqlliblib ndashldb2

The application performs a join between STAFF and ORG tables located in DB2USER schema (library) The join statement retrieves the DEPTNAME column from ORG NAME and JOB columns from STAFF and calculates the total compensation for an employee by adding SALARY and COMM columns in STAFF The results are sorted by total compensation The selection criterion is based on the current value of the department name parameter Here is the SELECT statement used by testcli

40

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

select name job salary + coalesce(comm0) as compensationfrom org o staff swhere odeptnumb = sdeptand deptname = order by compensation desc

Figure 21 shows the software components involved in the execution of this sample application

Figure 21 How a DB2 CLI client accesses DB2 UDB on an iSeries server

Although the testcli application is fairly simple it covers some important aspects of efficient CLI programming for DB2 UDB for iSeries

Reusable Open Data Paths (ODPs)An Open Data Path (ODP) definition is an internal i5OS object that is created when certain SQL statements (such as OPEN INSERT UPDATE and DELETE) are executed for the first time in a given job (or connection) The ODP can be thought of as a runtime implementation of an access plan The access plan created at the optimization time provides a recipe or in other words a sequence of steps necessary to execute the statement The ODP on the other hand provides the executable code for all requested IO operations The process of creating new ODP objects is fairly CPU- and IO-intensive so whenever possible the iSeries DB2 runtime tries to reuse existing ODPs For instance a SQLCloseCursor() API call may close the SQL cursor but leave the ODP available to be used the next time the cursor is opened This can significantly reduce the processing and response time in running SQL statements A reusable OPD usually requires 10 to 20 times less CPU resources than a newly created ODP Therefore it is important that the applications employ programming techniques that allow the DB2 runtime to reuse ODPs

With dynamic interfaces such as CLI full opens are avoided by using a prepare once execute many programming paradigm It means that when an SQL statement is going to be executed more than once you should prepare the statement just once and then reuse the prepared

41

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

statements for consecutive executions Although DB2 UDB does try to convert literals to parameter markers so that similar statements can be reused it is a better programming practice to explicitly implement parameter markers That way the chances for reusable ODPs are quite significantly improved The code snippet in Figure 22 illustrates how to implement the prepare once execute many programming technique

Define A SELECT SQL Statementstrcpy((char ) SQLStmt select name job salary + ifnull(comm0) ascompensation )ptr = strcat( (char ) SQLStmt from org o staff s )ptr = strcat( (char ) SQLStmt where odeptnumb = sdept)ptr = strcat( (char ) SQLStmt and deptname = )ptr = strcat( (char ) SQLStmt order by compensation desc) [1]

Prepare The SQL Statementrc = SQLPrepare(ExampleStmtHandle SQLStmt SQL_NTS) [2]

Bind The Columns In The Result Data Set Returned To Application Variablesrc = SQLBindCol(ExampleStmtHandle 1 SQL_C_CHAR (SQLPOINTER)

ExampleName sizeof(ExampleName) NULL)rc = SQLBindCol(ExampleStmtHandle 2 SQL_C_CHAR (SQLPOINTER)

ExampleJob sizeof(ExampleJob) NULL)rc = SQLBindCol(ExampleStmtHandle 3 SQL_C_DOUBLE (SQLPOINTER)

ampExampleComp sizeof(ExampleComp) NULL)

for (int i = 0 i lt LOOPS i++)rc=SQLBindParameter(ExampleStmtHandle

1SQL_PARAM_INPUTSQL_C_CHARSQL_CHAR10(SQLPOINTER) currentDepartment[i8]0NULL) [3]

rc = SQLExecute(ExampleStmtHandle) [4]cout ltlt endl ltlt Current Dept ltlt currentDepartment[i8] ltlt endl Display The Results Of The SQL QueryExampleShowResults()

Figure 22 Use the prepare once execute many programming technique

The error-handling code has been removed for clarity At [1] the statement text is assigned to a variable Note that a parameter marker is used in the WHERE clause The statement is then prepared just once at [2] The current value of the parameter is bound to the prepared statement at [3] The prepared statement is executed at [4] Steps [3] and [4] are repeatedly executed in a for loop

Techniques to Further Improve DB2 CLI Performance Thus far this paper has discussed the techniques used by a sample application to tune the CLI performance However depending on the application architecture other methods of improving CLI performance may be considered

Connection PoolingCurrently the CLI application connecting through DB2 Connect to DB2 UDB for iSeries does not take advantage of the connection pooling mechanism implemented by DB2 Connect Therefore for performance reasons the author strongly recommends that the application server that obtains and drops connections very frequently implements its own database connection pooling mechanism that would assign an existing pooled database connection to a new AIX process or thread

42

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Blocking

For queries which result in returning large data blocks from the iSeries server (usually 32K of data and above) ensure that the database manager configuration parameter RQRIOBLK is set to 32767 This can be done using the Command Line Processor (CLP) as follows

db2 update database manager configuration using RQRIOBLK 32767

TroubleshootingThe experience of the author shows that two tools are particularly useful for pinning down the potential problem areas bull Joblog messages for a database server job usually provides enough details to isolate DB2

runtime issues bull CLI trace utility provides granular information about the data flow between the AIX application

and the database server job

Job Log MessagesThe process of finding and analyzing the job log for a DB2 CLI connection is identical to the process outlined for an embedded SQL application in the Job Log Message section of this paper on page 39

CLI Trace The DB2 CLIODBCJDBC trace utility provides very detailed information about the data streams exchanged between DB2 Connect and target database server Refer to the DB2 Information Center for more information on how to set up and analyze the CLI traces httppublibboulderibmcominfocenterdb2v8luwindexjsptopic=comibmdb2udbdocadc000 7959htm

43

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Trademarks

IBM eServer iSeries AIX AIX 5L i5OS WebSphere DB2 DB2 Universal Database DB2 Connect OS400 zOS OS390 Distributed Relational Database Architecture DRDA and DB2 Information Integration are trademarks or registered trademarks of International Business Machines Corporation in the United States and other countries

Java and all Java-based trademarks are trademarks of Sun Microsystems Inc in the United States other countries or both

Linux is a registered trademark of Linus Torvalds in the United States other countries or both

UNIX is a registered trademark of The Open Group in the United States and other countries

Microsoft and Windows are registered trademarks of Microsoft Corporation in the United States andor other countries

All other registered trademarks and trademarks are properties of their respective owners

IBM makes no commitment to make available any products referred to herein

References in this publication to IBM products or services do not imply that IBM intends to make them available in every country in which IBM operates

Additional Information ITSO offers a Redbook that can be helpful to those who want to learn more about i5OS AIX integration

bull AIX Integration with I5OS on the IBM eServer iSeries Server (SG24-6551)

Jarek Miszczyk is the Senior Software Engineer IBM eServer Solutions Enablement IBM Rochester

[Portions of this white paper reprinted with permission from MC Mag Online published by MC Press LLP httpwwwmcpressonlinecom]

Acknowledgments The author would like to thank the following people for their advice contributions and support on this paper

Bob Bittner IBM Rochester Jon Rush IBM Rochester Prasad Vallurupalli IBM Rochester Neil Willis IBM Rochester

44

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix A Source Listing of TestJDBCjava

package comibmiseriespwdimport javasqlimport javaxnamingimport javautilHashtableimport javautilimport javaxsqlimport comibmas400access

public class TestJDBC public static void main(javalangString[] args)

throws Exception

int numOfLoops = 5000int outerNumOfLoops = 5boolean firstExec = trueConnection conStatement sPreparedStatement psPreparedStatement pstmtdelCallableStatement cstmPreparedStatement pstmtHashtable env = new Hashtable()

envput(ContextINITIAL_CONTEXT_FACTORYcomsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env)Systemoutprintln(Deploying connection pooling data source)deployDataSource() Do the work with connection pooling onlyAS400JDBCConnectionPoolDataSource tkcpds =

(AS400JDBCConnectionPoolDataSource)ctxlookup(jdbcToolkitDataSource) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPool pool = new AS400JDBCConnectionPool(tkcpds) Adds 1 connection to the pool that can be used by theapplication (creates the physical database connections based onthe data source)poolfill(1)Systemoutprintln(nStart timing Toolkit connection pooling)long startTime = SystemcurrentTimeMillis()

for (int i = 0 i lt outerNumOfLoops i++) con = poolgetConnection()consetAutoCommit(false) deleteif ( i == 0)

long startDelete = SystemcurrentTimeMillis()cstm = cstm = conprepareCall(

CALL qsysqcmdexc(CLRPFM FILE(DB2USERCOFFEES) + 000000002800000))

cstmexecuteUpdate()cstmclose()long endDelete = SystemcurrentTimeMillis()Systemoutprintln(Delete all records +

(endDelete - startDelete) + ms elapsed)

45

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

String sqlinstrlong startInsert = SystemcurrentTimeMillis() insert

pstmt =conprepareStatement(INSERT INTO COFFEES VALUES( ))for (int j = 0 j lt numOfLoops j++) pstmtsetString(1 Kona_ + IntegertoString(i))pstmtsetInt(2 150)pstmtsetFloat(3 999f)pstmtsetInt(4 0)pstmtsetInt(5 0)pstmtaddBatch()int [] updateCounts = pstmtexecuteBatch()concommit()pstmtclose()long endInsert = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for + numOfLoops + inserts

+ (endInsert - startInsert)) selectlong startSelect = SystemcurrentTimeMillis()ps = conprepareStatement(SELECT FROM COFFEES)ResultSet rs = psexecuteQuery()rsnext()rsclose()concommit()psclose()long endSelect = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for select +

(endSelect - startSelect))consetAutoCommit(true)conclose()long endTime = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for + outerNumOfLoops +

loops + (endTime - startTime))Systemexit(0)

private static void deployDataSource()throws ExceptionString serverName = teraplex String databaseName = TERAPLEX String userName = db2user String password = db2pwd

Establish a JNDI context and bind the connection pool data sourceHashtable env = new Hashtable()envput(ContextINITIAL_CONTEXT_FACTORY

comsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPoolDataSource tkcpds = new

AS400JDBCConnectionPoolDataSource()tkcpdssetServerName(serverName) tkcpdssetDatabaseName(databaseName) tkcpdssetUser(userName) tkcpdssetPassword(password) tkcpdssetDescription(Toolkit Connection Pooling DataSource)tkcpdssetSavePasswordWhenSerialized(true)tkcpdssetExtendedDynamic(true)

46

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

tkcpdssetPackage(JDBCDS)tkcpdssetPackageCache(true)tkcpdssetPackageCriteria(select)enable the following properties as requiredcpdssetTrace(true)tkcpdssetServerTraceCategories( AS400JDBCDataSourceSERVER_TRACE_DEBUG_SERVER_JOB)

ctxrebind(jdbcToolkitDataSource tkcpds)

47

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix B mdash Source Listing of cursorsjsqc

Source File Name = cursorsjsqc Licensed Materials - Property of IBM (C) COPYRIGHT International Business Machines Corp 1995 2000 2004 All Rights Reserved US Government Users Restricted Rights - Use duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp PURPOSE This sample program demonstrates the use of a CURSOR The CURSOR is processed using static SQL EXTERNAL DEPENDENCIES - Ensure existence of database for precompile purposes - Precompile with the SQL precompiler (PREP in DB2) - Bind to a database (BIND in DB2) - Compile and link with the IBM Cset++ compiler (AIX and OS2) or the Microsoft Visual C++ compiler (Windows) or the compiler supported on your platform For more information about these samples see the README file For more information on programming in C see the - Programming in C and C++ section of the Application Development Guide For more information on building C applications see the - Building C Applications section of the Application Building Guide For more information on the SQL language see the SQL Reference

include ltstdiohgt include ltstdlibhgt include ltstringhgtinclude ltsqlhgtinclude ltsqlenvhgtinclude ltsqldahgtinclude ltsqlcahgt

int SqlInfoPrint( char struct sqlca int char )void TransRollback( void)

define EMB_SQL_CHECK( MSG_STR ) rc = SqlInfoPrint( MSG_STR ampsqlca __LINE__ __FILE__) if ( rc = 0 ) TransRollback( )

return 1

EXEC SQL INCLUDE SQLCA

int main(int argc char argv[])

EXEC SQL BEGIN DECLARE SECTIONchar dname[15]

48

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

char pname[10]double compchar userid[9]char passwd[19]

EXEC SQL END DECLARE SECTION

int rc = 0printf( Sample C program CURSORSJ n )if (argc == 1)

EXEC SQL CONNECT TO TPLXEMB_SQL_CHECK(CONNECT TO TPLX)

else if (argc == 3)

strcpy (userid argv[1])strcpy (passwd argv[2])EXEC SQL CONNECT TO TPLX USER userid USING passwdEMB_SQL_CHECK(CONNECT TO TPLX)

else

printf (nUSAGE cursor [userid passwd]nn)return 1

endif

EXEC SQL DECLARE c1 CURSOR FORselect deptname name salary + ifnull(comm0) as compensationfrom org o staff swhere odeptnumb = sdeptorder by deptname compensation desc

EXEC SQL OPEN c1EMB_SQL_CHECK(OPEN CURSOR)

printf(DEPARTMENT NAME COMPENSn)printf(-----------------------------------n)do

EXEC SQL FETCH c1 INTO dname pname compif (SQLCODE = 0) breakprintf( -1515s -1010s 72fn dname pname comp )

while ( 1 )

EXEC SQL CLOSE c1EMB_SQL_CHECK(CLOSE CURSOR)

EXEC SQL CONNECT RESETEMB_SQL_CHECK(CONNECT RESET)

exit(0)

end of program CURSORSJSQC

int SqlInfoPrint( char appMsgstruct sqlca pSqlcaint linechar file )

int rc = 0char sqlInfo[1024]char sqlInfoToken[1024]char sqlstateMsg[1024]char errorMsg[1024]

if (pSqlca-gtsqlcode = 0 ampamp pSqlca-gtsqlcode = 100)

49

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

strcpy(sqlInfo )if( pSqlca-gtsqlcode lt 0) sprintf( sqlInfoToken n---- error report ----n)

strcat( sqlInfo sqlInfoToken)else sprintf( sqlInfoToken n---- warning report ----n)

strcat( sqlInfo sqlInfoToken) endif

sprintf( sqlInfoToken app message = sn appMsg)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken line = dn line)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken file = sn file)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken SQLCODE = ldn pSqlca-gtsqlcode)strcat( sqlInfo sqlInfoToken)

get error message rc = sqlaintp( errorMsg 1024 80 pSqlca) return code is the length of the errorMsg string if( rc gt 0) sprintf( sqlInfoToken sn errorMsg)

strcat( sqlInfo sqlInfoToken)

get SQLSTATE message rc = sqlogstt( sqlstateMsg 1024 80 pSqlca-gtsqlstate)if (rc == 0) sprintf( sqlInfoToken sn sqlstateMsg)

strcat( sqlInfo sqlInfoToken)

if( pSqlca-gtsqlcode lt 0) sprintf( sqlInfoToken --- end error report ---n)

strcat( sqlInfo sqlInfoToken)printf(s sqlInfo)return 1

else sprintf( sqlInfoToken --- end warning report ---n)

strcat( sqlInfo sqlInfoToken)printf(s sqlInfo)return 0

endif endif

return 0

void TransRollback( ) struct sqlca sqlca

int rc = 0 rollback the transaction printf( nRolling back the transaction n)

EXEC SQL ROLLBACKrc = SqlInfoPrint( ROLLBACK ampsqlca __LINE__ __FILE__)if( rc == 0) printf( The transaction was rolled backn)

50

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

51

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix C mdash Source Listing of testclicpp

Include The Appropriate Header Filesinclude ltsqlclihgtinclude ltsqlcli1hgtinclude ltsqlutilhgtinclude ltsqlenvhgtinclude ltstdiohgt include ltiostreamgt include ltlocalehgt include ltstringhgtdefine SQL_SQLSTATE_SIZE 5define LOOPS 8

using namespace std

Define The CLI_Class Classclass CLI_Class

Attributespublic

SQLHANDLE EnvHandleSQLHANDLE ConHandleSQLHANDLE StmtHandleSQLRETURN rcSQLCHAR Job[6]SQLCHAR Name[10]SQLDOUBLE Comp

Operationspublic

CLI_Class()~CLI_Class()SQLRETURN ShowResults()

Constructor Destructor

SQLRETURN printError( SQLHDBC SQLHSTMT)

Define The Class ConstructorCLI_ClassCLI_Class()

setlocale( LC_ALL )

Initialize The Return Code Variablerc = SQL_SUCCESS

Allocate An Environment Handlerc = SQLAllocHandle(SQL_HANDLE_ENV SQL_NULL_HANDLE ampEnvHandle)

Allocate A Connection Handleif (rc == SQL_SUCCESS)

rc = SQLAllocHandle(SQL_HANDLE_DBC EnvHandle ampConHandle)

Define The Class DestructorCLI_Class~CLI_Class()

Free The Connection Handleif (ConHandle = NULL)

SQLFreeHandle(SQL_HANDLE_DBC ConHandle)

Free The Environment Handle

52

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

if (EnvHandle = NULL)SQLFreeHandle(SQL_HANDLE_ENV EnvHandle)

Define The ShowResults() Member FunctionSQLRETURN CLI_ClassShowResults(void)

While There Are Records In The Result Data Set Generated Retrieve And Display Themcout ltlt Name Job Compensation ltlt endlcout ltlt --------- ------ ------------ ltlt endlcoutsetf(iosleft)coutprecision(2)coutsetf(iosfixed)while (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)

rc = SQLFetch(StmtHandle)if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)

coutwidth(15)cout ltlt Name

coutwidth(10)cout ltlt Job

coutwidth(7)cout ltlt Comp ltltendl

if(rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO ampamp rc = SQL_NO_DATA)printError(ConHandle StmtHandle)

else

rc = 0SQLCloseCursor(StmtHandle)

Return The ODBC API Return Code To The Calling Functionreturn(rc)

SQLRETURN CLI_ClassprintError (SQLHDBC hdbc

SQLHSTMT hstmt)

SQLCHAR buffer[SQL_MAX_MESSAGE_LENGTH + 1]SQLCHAR sqlstate[SQL_SQLSTATE_SIZE + 1]SQLINTEGER sqlcodeSQLSMALLINT lengthSQLRETURN rcwhile ((rc = SQLError(SQL_NULL_HENV hdbc hstmt

sqlstateampsqlcodebufferSQL_MAX_MESSAGE_LENGTH + 1amplength)) == SQL_SUCCESS || rc ==

SQL_SUCCESS_WITH_INFO)

cout ltlt SQLSTATE ltlt sqlstate ltlt endlcout ltlt SQLCODE ltlt sqlcode ltlt endlcout ltlt Error msg ltlt buffer ltlt endl

53

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

cout ltlt----------------------------- ltlt endl ltlt endl

return(SQL_ERROR)

----------------------------------------------------------------- The Main Function -----------------------------------------------------------------int main()

Declare The Local Memory Variables

(SQLCHAR ) db2user SQL_NTS (SQLCHAR ) test26t SQL_NTS)

SQLRETURNSQLCHARSQLCHARSQLCHARchar

SQLCHAR

rc = SQL_SUCCESSDBName[10] = TPLXSQLStmt[255]c[10]ptrcurrentDepartment[8][15] = Head Office

New England Mid Atlantic South Atlantic Great Lakes PlainsPacificMountain

Create An Instance Of The CLI_Class ClassCLI_Class Example

Connect To iSeries Database if (ExampleConHandle = NULL)

rc = SQLConnect(ExampleConHandle DBName SQL_NTS

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)ExampleprintError(ExampleConHandle SQL_NULL_HSTMT)

return(rc)

cout ltlt Successfully connected to ltlt DBName ltlt ltlt endlrc = SQLSetConnectAttr(ExampleConHandle SQL_ATTR_AUTOCOMMIT

(SQLPOINTER) SQL_AUTOCOMMIT_OFF SQL_IS_UINTEGER) Allocate An SQL Statement Handlerc = SQLAllocHandle(SQL_HANDLE_STMT ExampleConHandle

ampExampleStmtHandle)if (rc == SQL_SUCCESS)

Define A SELECT SQL Statement

strcpy((char ) SQLStmt select name job salary + ifnull(comm0) ascompensation )

ptr = strcat( (char ) SQLStmt from org o staff s )ptr = strcat( (char ) SQLStmt where odeptnumb = sdept)ptr = strcat( (char ) SQLStmt and deptname = )ptr = strcat( (char ) SQLStmt order by compensation desc)

Prepare The SQL Statementrc = SQLPrepare(ExampleStmtHandle SQLStmt SQL_NTS)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)ExampleprintError(ExampleConHandle ExampleStmtHandle)

54

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

return(rc)

Bind The Columns In The Result Data Set Returned To Application Variables

rc = SQLBindCol(ExampleStmtHandle 1 SQL_C_CHAR (SQLPOINTER)ExampleName sizeof(ExampleName) NULL)

rc = SQLBindCol(ExampleStmtHandle 2 SQL_C_CHAR (SQLPOINTER)ExampleJob sizeof(ExampleJob) NULL)

rc = SQLBindCol(ExampleStmtHandle 3 SQL_C_DOUBLE (SQLPOINTER)ampExampleComp sizeof(ExampleComp) NULL)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO) ExampleprintError(ExampleConHandle ExampleStmtHandle)

return(rc)

while (true)

for (int i = 0 i lt LOOPS i++)

rc=SQLBindParameter(ExampleStmtHandle1SQL_PARAM_INPUTSQL_C_CHARSQL_CHAR

150(SQLPOINTER) currentDepartment[i8]0NULL)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)

ExampleprintError(ExampleConHandle ExampleStmtHandle)return(rc)

rc = SQLExecute(ExampleStmtHandle)if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)

ExampleprintError(ExampleConHandle ExampleStmtHandle)return(rc)

cout ltlt endl ltlt Current Dept ltlt currentDepartment[i8] ltlt

endl Display The Results Of The SQL QueryExampleShowResults()if(rc = 0)break

if ( i500 == 0 ampamp i gt 0 )cout ltlt Loops ltlt i ltlt ltlt endl

cout ltlt AFTER ltlt LOOPS ltlt loops Press X to exit ltlt endlcin gtgt cif (c[0] == x || c[0] == X)

break

Free The SQL Statement Handleif (ExampleStmtHandle = NULL )

SQLFreeHandle(SQL_HANDLE_STMT ExampleStmtHandle) Disconnect From The Northwind Sample Databaserc = SQLDisconnect(ExampleConHandle)

Return To The Operating Systemreturn(rc)

55

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 engine stores the prepared statement along with the associated statement name in the QZDASOINIT jobs statement cache On the first execution the ODP created for a given statement is associated with the appropriate entry in the statement cache On consecutive executions the prepared statement and the corresponding ODP can be quickly located in the statement cache and reused The code snippet below illustrates the prepare once execute many programming technique

PreparedStatement pstmt = conprepareStatement(INSERT INTO COFFEES VALUES( ))[1] hellip for (int i = 0 i lt outerNumOfLoops i++)

insertfor (int j = 0 j lt numOfLoops j++)

pstmtsetString(1 Lavaza_ + IntegertoString(j)) hellip pstmtaddBatch()

int [] updateCounts = pstmtexecuteBatch()[2]concommit()

At [1] a PreparedStatement pstmt object is instantiated for a parameterized INSERT statement The statement is prepared just once The PreparedStatement object is then repeatedly used at [2] to perform blocked insert

Block Inserts Occasionally the developer may need to initially populate a table or insert a modified result set into a temporary table The efficiency of the insert operation for a large set of records can be dramatically improved by using the executeBatch method rather than the executeUpdate method The JTOpen driver converts parameterized insert statements in an executeBatch method to a block insert statement This significantly reduces the data flow and system resources required to perform the insert The following code snippet shows how to take advantage of the executeBatch method

10

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

PreparedStatement pstmt =conprepareStatement(INSERT INTO COFFEES VALUES( ))[1]for (int j = 0 j lt numOfLoops j++) pstmtsetString(1 Lavaza_ + IntegertoString(j))pstmtsetInt(2 i)pstmtsetFloat(3 499f)pstmtsetInt(4 0)pstmtsetInt(5 0)pstmtaddBatch() [2]

int [] updateCounts = pstmtexecuteBatch() [3]

At [1] a parameterized insert statement is prepared Note that all columns must be parameterized Otherwise the executeBatch method may throw the SQL0221 Number of rows 1 not valid exception In other words the developer should not mix parameter markers with literals or special registers in the VALUE clause

At [2] the addBatch method is used to add a new record to the client record buffer

At [3] all locally buffered data is sent to the server which in turn performs a block insert

Figure 4 shows the performance data for the executeBatch and executeUpdate methods

Figure 4 executeBatch() versus executeUpdate() performance comparison

11

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

WebSphere Considerations In certain situations an application provider may decide to deploy WebSphere Application Server in an AIX partition rather than natively in i5OS At the same time the application uses DB2 UDB for iSeries as an back-end database server Typically the WebSphere Application Server running in the AIX partition uses the virtual LAN to communicate with DB2 UDB for iSeries The WebSphere applications will access the database through a remote JDBC connection For performance and functionality reasons IBM recommends to utilize in such environments the IBM Toolbox for Java JTOpen driver Most of the tips and techniques described so far in this document hold true for WebSphere applications accessing DB2 UDB for iSeries There are however certain JDBC access aspects that are specific to this multi-tier architecture Letrsquos have a closer look at some of these considerations

Connection Pooling and Statement Caching

WebSphere Application Server provides its own connection pooling and statement caching mechanism that is by default enabled so that WebSphere applications automatically enjoy the performance benefits of these two critical programming techniques See the following link to learn more about the optimal connection pool setting in WebSphere

httppublibboulderibmcomwas40051englishinforzaiz51adminhelpudat_conpoolsethtml

Extended Dynamic SQL

For non-JTA connections WebSphere Application Server uses the comibmas400accessAS400JDBCConnectionPoolDataSource class as the iSeries JDBC provider implementation This is the DataSource implementation that has been used in all previous coding examples As mentioned the class supports a range of iSeries specific properties that can be used to fine tune JDBC performance These properties can be set through the WebSphere Application Server admin console For example herersquos the procedure to enable the extended dynamic SQL support In the WebSphere Application Server admin console navigate to the Data Source configuration dialog by selecting JDBC Providers -gt iSeriesToolbox -gt Data Sources then scroll down to the Additional Properties section Select Custom Properties link The Custom Properties dialog opens Scroll down to find the Extended Dynamic property and select it Change the default value false to true save the new configuration by clicking Apply button This is illustrated in Figure 5

12

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 5 Enabling the extended dynamic SQL through WebSphere Application Server console

The WebSphere Application Server needs to be restarted for the change to take effect The similar procedure can be followed to set other iSeries Data Source properties

Changing the WebSphere Application Server default isolation level

WebSphere Application Server V5 uses the REPEATABLE_READ (RR) isolation level for all implicit (WebSphere Application Server managed) transactions With the RR isolation level the rows selected updated deleted and inserted are locked until the end of the transaction Under certain circumstances this fairly extensive locking policy may cause locking contention especially when a WebSphere application competes for database resources with other applications that run on iSeries server For example a legacy order entry application may share data with the e-business customer care application running in WebSphere The locking contention may sometimes be eliminated by lowering the isolation level used by WebSphere Although the iSeries Data Source supports the custom transactionIsolation property resetting this property on the Data Source object will not change the default isolation level used by WebSphere for the connection objects produced by that Data Source In other words WebSphere will override the Data Source isolation level setting at the time the connection is obtained by a WebSphere application object such as servlet or Enterprise Java Bean (EJB) In order to change the default WebSphere behavior one must use the resource referencing Resource referencing allows a programmer to lookup DataSource or EJB objects using alias names rather than JNDI names Additionally by creating a resource reference a programmer can change certain properties of the underlying object Specifically a DataSource reference can be used to set a different isolation level for the connections produced by this database resource Typically resource references are defined by a programmer in a application development tool such as WebSphere Studio Application Developer The method to specify a DataSource reference differs depending on whether a programmer plans to use the reference in a servlet or in an EJB Letrsquos start with outlining the configuration process for a servlet In WebSphere Studio Application Developer open the deployment descriptor editor for the web project that contains the servlet To do so double click on the webxml file under WEB-INF directory in the web project In the deployment editor dialog select the References tab and then select Resource tab located in the top of the dialog that appears Under Resource References section select the Add button Herersquos an example of a DataSource reference created for iSeries DataSource named TestJDBCDS Note that the reference changes the default isolation level to READ_COMMITTED

13

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 6 Defining a resource reference for a servlet

Once the resource reference has been defined and saved the servlet source code needs to be changed to reflect the fact that a resource reference is used to obtain a DataSource from the JNDI service Herersquos the relevant code snippet try

ctx = new InitialContext() ds = (DataSource)ctxlookup(javacompenvTestJDBCJ2C)

catch (Exception e) eprintStackTrace(out)

Now the ds DataSource object will produce connections that by default run with the isolation level of READ_COMMITTED (RC)

As mentioned the process of defining a resource reference for an EJB differs from the process that is used in the case of a servlet In WebSphere Studio Application Developer open the deployment descriptor editor for the EJB project that contains the EJB To do so double click on the ejb-jarxml file under WEB-INF directory in the project In the deployment editor dialog select the References tab In the references section on the left locate and select the EJB for which the developer wants to change the default isolation level Click the Add button The Add Reference dialog opens Click the Resource Reference radio button and then Next Define the reference following the example shown in Figure 7

14

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 7 Adding a resource reference for an EJB

When you click ldquoFinishrdquo the reference definition is added to the EJB descriptor The new definition needs to be further modified To do so click on the (+) sign next to the EJB in the References list Click the new reference TestJDBCJ2C in this example to open the properties for the reference Change WebSphere Bindings and WebSphere Extensions sections as illustrated in Figure 8

15

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 8 Defining a resource reference for an EJB

Save the modified definition and then change the EJB source code to use the reference rather than directly DataSource

TroubleshootingTroubleshooting a multi-tier application may be a bit tricky because the developer needs to deal with software components that reside in separate partitions Three tools are particularly useful for pinning down the potential problem areas bull Joblog messages for a database server job mdash Provides enough details to isolate DB2 UDB for

iSeries runtime issues bull JDBC trace utility mdash Provides granular information about the data flow between the AIX

application and the iSeries server job bull Database Monitor ndash Provides detailed SQL runtime trace

Job Log MessagesAs mentioned a DB2 client communicates with a corresponding iSeries server job This server job runs the SQL requests on behalf of the client The iSeries database server jobs are called QZDASOINIT and they run in the QUSRWRK subsystem At any given time a large number of database server jobs may be active on the server so the first step is to identify the job that serves the particular client connection The easiest method to accomplish this task is to run the following CL command from the i5OS prompt

WRKOBJLCK OBJ(DB2USER) OBJTYPE(USRPRF)

Here DB2USER is the user profile that is used to connect to the iSeries server Note that a QZDASONIT job is assigned to a client after the connection has been established so the developer needs to set a breakpoint in the client application after the database connection has been established

Once the Work with Object Locks appears key in 5 (Work with Job) next to the only QZDASOINIT job that should be listed This shows the Work with Job dialog Select option 10 to

16

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

display the job log for the database server job Now the job log can be searched for any error messages generated by the DB2 runtime

Sometimes it is also useful to include debug messages in the job log The debug messages are informational messages written to the job log about the implementation of a query They describe query implementation methods such as the use of indexes join order ODP implementation (reusable versus non-reusable) and so on The easiest way to instruct an iSeries server to include the debug messages is to set the ServerTraceCategories property on the data source object

tkcpdssetServerTraceCategories(AS400JDBCDataSourceSERVER_TRACE_DEBUG_SERVER_JOB)

A sample of the job log messages with debug messages enabled is shown below

SET TRANSACTION completeSTATEMENT NAME FOUND QZ868F0A458E13AF8C Starting optimizer debug message for query Arrival sequence access was used for file COFFEESODP created ODP not deleted 5000 rows inserted in COFFEES in DB2USER STATEMENT NAME FOUND QZ868F0A4C144BF12EBlocking used for queryCursor CRSR0001 opened606 rows fetched from cursor CRSR0001 ODP not deleted Cursor CRSR0001 closed

So the job log offers fairly detailed information on how the AIX client requests were implemented by the DB2 runtime

JDBC Trace UtilityThe JTOpen driver provides a tracing utility which can be used to collect detailed client-side traces The JDBC tracing is turned off by default It can be enabled by setting the Trace property to true Heres an example of how to switch on tracing using the setTrace method on the data source object

tkcpdssetTrace(true)

The trace can also be enabled when using the DriverManagergetConnection() method for obtaining a connection to DB2 UDB for iSeries In this case the developer could add the trace property to the connection string This approach is illustrated in the following code snippet

ClassforName(comibmas400accessAS400JDBCDriver) [1] hellip con = DriverManagergetConnection(jdbcas400teraplextrace=true

db2userdb2pwd) [2]

At [1] an instance of the JTOpen JDBC Driver is initiated Then at [2] the driver is used to obtain a connection to the iSeries server Note how the trace property has been added to the database URL See the IBM Toolbox for Java JDBC properties documentation on the iSeries Information Center Web site for a complete list of properties supported by the JTOpen driver

Although the level of details provided by the trace utility is sufficient in most troubleshooting scenarios sometimes the developer may need to collect low-level traces scoped to a certain type

17

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

of information In V5R3 the IBM Toolbox for Java (as well as the latest JTOpen) added a comprehensive detailed trace facility The following is the complete list of detailed trace parameters and their purpose

bull None or ldquordquo ndash This setting disables the detailed trace bull datastream - This category is used by Toolbox classes to log dataflow between the local host

and the remote system It is not intended for use by application classes bull diagnostic - This category is used to log object state information bull error - This category is used to log errors that cause an exception bull information - This category is used to track the flow of control through the code bull warning - This category is used to log errors that are recoverable bull conversion - This category is used by Toolbox classes to log character set conversions

between Unicode and native code pages bull proxy - This category is used by Toolbox classes to log data flow between the client and the

proxy server bull pcml - This category is used to determine how PCML interprets the data that is sent to and

from the server bull jdbc - This category is used to track JDBC calls throughout the program bull thread - This category is used to enable tracing of thread information This is useful when

debugging multi-threaded applications bull all - This category will enable all previous categories

The detailed trace can be enabled when using the DriverManagergetConnection() method for obtaining a connection to DB2 UDB for iSeries In this case the developer could add the toolbox trace property to the connection string This is illustrated in the following code sample

String dbUrl = jdbcas400pwd1toolbox trace=diagnostic con = DriverManagergetConnection(dbUrl dbUser dbPassword)

Note that currently the driverrsquos DataSource interfaces do not allow the developer to directly activate the detailed tracing However they could set the server from the command line at the time the java program is launched The example below shows how the detailed trace properties could be enabled at the command line

java -Dcomibmas400accessTracecategory=diagnostic TestJDBC

The -D switch indicates to the java interpreter that the information following it will be a system property

In case of a WebSphere application the trace property can be set through the admin console In the console select Application Servers-gt server1-gt Process Definition -gt Java Virtual Machine Figure 9 shows how to set the Generic JVM Arguments for an application server instance

18

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 9 Setting JVM arguments to enable detailed Toolbox tracing

Database Monitor

The database monitor is the ultimate tool available on DB2 UDB for iSeries to collect low-level SQL traces It is mainly used to pin down the SQL performance problems Refer to the lsquoUsing iSeries Database Monitor to Identify and Tune SQL Queriesrsquo white paper for a detailed discussion on how to collect and analyze the database monitor traces httpibmcomserversenablesiteeducationiborecordhtmldtmon

IBM DB2 JDBC Universal Driver DB2 JDBC Universal Driver is one of the new features delivered with DB2 UDB Version 8 DB2 JDBC Universal Driver has been designed to eliminate the dependency on DB2 CLI runtime modules as well as to enable direct Type 4 connectivity to DB2 UDB for iSeries and DB2 UDB for zOSreg

The pure-Java (Type 4) remote connectivity is based on the DRDA open distributed protocol for cross-platform access to DB2 DRDA defines the rules the protocols and the semantics for accessing distributed data Applications can access data in a distributed relational environment by using SQL statements The iSeries DRDA application server implementation is based on multiple connection-oriented server jobs running in the QSYSWRK subsystem A DRDA listener job (QRWTLSTN) listens for TCP connect requests on port 446 Once an application requester connects to the listener job the listener wakes up one of the QRWTSRVR prestart jobs and assigns it to a given client connection Any further communication occurs directly between the client application and the QRWTSRVR job These concepts are illustrated in Figure 10

19

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 10 Accessing DB2 UDB for iSeries with DB2 Universal Driver

The DB2 Universal Driver can be loaded in an AIX partition by installing one of the DB2 Connect for AIX products (see the Additional Information section for details) It is also a part of a DB2 Enterprise Server Edition for AIX install Specifically the developer needs three JAR files in a AIX partition to successfully connect to an iSeries server db2jccjar db2jcc_license_cisuzjar and db2jcc_license_cujar The iSeries license is contained in db2jcc_license_cisuzjar Note that this file is not a part of DB2 Client In other words a DB2 Connect license is required to use the driver in production environments The location of the JAR files needs to be added to the CLASSPATH environment variable For instance the following entry could be added to the AIX profile script

CLASSPATH=homedb2inst2sqllibjavadb2jccjarCLASSPATH=$CLASSPATHhomedb2inst2sqllibjavadb2jcc_license_cujarCLASSPATH=$CLASSPATHhomedb2inst2sqllibjavadb2jcc_license_cisuzjarexport CLASSPATH

Java Runtime 131 is a prerequisite

Additionally the developer should install the latest database group PTF (SF99503 for i5OS V5R3) on the iSeries server The Informational APAR ii13348 is keeping track of any fixes relevant to DRDA above and beyond the current database group PTF

Obtaining a Connection to DB2 UDB for iSeries When Type 4 connectivity is used the DB2 Universal Driver connects directly to the DB2 on iSeries through TCPIP Note that this is different from the legacy DB2 Type 2 JDBC driver that requires a DB2 node and remote database configurations on the client accessing iSeries The following code snippet illustrates how to use the DB2 JDBC Universal Driver to obtain a connection to DB2 UDB for iSeries

20

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

try ClassforName(comibmdb2jccDB2Driver) [1] catch(javalangClassNotFoundException e) Systemerrprint(ClassNotFoundException )Systemerrprintln(egetMessage())

try DriverManagergetConnection(jdbcdb2teraplex446TERAPLEX[2]

db2userdb2pwd) hellip catch(SQLException ex) Systemerrprintln(

SQLException + exgetMessage())

At [1] an instance of the DB2 JDBC Universal Driver is instantiated Then at [2] the driver is used to obtain a connection to the iSeries server Note the proper form of the database URL required by the driver

Considerations There are several advantages of DB2 JDBC Universal Driver bull Ease of cross-platform development mdash Consistent coding techniques and consistent error

codes and messages bull Ease of deployment mdash Pure Java (no runtime client required) and a single driver for accessing

DB2 on different platforms

The ease of use comes at a price though The iSeries JTOpen driver is optimized for accessing DB2 UDB for iSeries data and it uses native iSeries protocol to communicate with the back-end database server job This usually results in better performance and more-efficient system resources utilization For instance when using the DB2 JDBC Universal Driver to access an iSeries server the executeBatch method results in a single record insert There are also some restrictions when using DB2 Universal JDBC Driver with Type 4 connectivity

bull Support for distributed transactions (JTA) is not enabled bull Driver built-in connection pooling is not supported

Refer to Java application support in DB2 for more details on DB2 JDBC Universal Driver

21

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 Connect data access This section will explore the most important aspects of DB2 Connect ndash iSeries integration - including configuration tips and coding examples

DB2 Connect provides functionality for accessing data stored in DB2 UDB for iSeries as well as DB2 UDB for zOS and DB2 UDB for OS390reg DB2 Connect offers capabilities to access DB2 family members via several SQL interfaces gateway functions such as connection pooling and federated database functionality Many applications supporting the DB2 family of products leverage DB2 Connect as a key middleware component DB2 Connect is offered as separate AIX license products

Enterprise Edition Application Server Edition

In addition to DB2 Connect there are several other DB2 UDB Version 81 products that are supported on AIX

DB2 Universal Database Enterprise Server Edition DB2 Universal Database Workgroup Server Unlimited Edition DB2 Universal Database Workgroup Server Edition DB2 Universal Database Universal Developers Edition All Clients

The DB2 Connect Enterprise Edition functionality is also contained in DB2 Enterprise Server Edition for AIX

22

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 Connect in a nutshell In the scenario described in this paper the DB2 Connect functions contained in DB2 Enterprise Edition for AIX are utilized DB2 Connect Enterprise Edition provides support for both local and remote DB2 clients This is illustrated in Figure 11 Accessing DB2 UDB for iSeries with DB2 Connect

Figure 11 Accessing DB2 UDB for iSeries with DB2 Connect

DB2 Connect implements the Distributed Relational Database Architecturetrade (DRDAreg) to reduce the cost and complexity of accessing data stored in DB2 UDB for iSeries and other DRDA-compliant database servers DRDA defines the rules the protocols and the semantics for accessing distributed data Applications can access data in a distributed relational environment by using SQL statements In a distributed environment the system running the application and sending the SQL requests across the network is called the application requester (AR) A remote database server that executes SQL requests submitted by an application requester is known as the application server (AS) In the example shown in Figure 11 (above) DB2 Connect plays the role of an application requester while DB2 UDB for iSeries is an application server In this case DB2 Connect communicates with the iSeries database through TCPIP The iSeries DRDA application server implementation is based on multiple connection-oriented server jobs running in the QSYSWRK subsystem A DRDA listener job (QRWTLSTN) listens for TCP connect requests on port 446 Once an application requester connects to the listener job the listener wakes up one of the QRWTSRVR prestart jobs and assigns it to a given client connection Any further communication occurs directly between the client application and the QRWTSRVR job

DB2 Connect supports a wide range of programming interfaces that can be used by AIX applications to access the iSeries database Embedded SQL frac34 Both static and dynamic SQL frac34 Various programming languages (Java CC++ Cobol Fortran REXX)

DB2 Call Level Interface (DB2 CLI) ODBC JDBC frac34 DB2 JDBC Type 2 Driver frac34 DB2 JDBC Type 4 Driver (Universal JDBC Driver)

23

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Note that DB2 Connect supports access to DB2 UDB for iSeries through DB2 JDBC Universal driver However for performance and ease of maintenance reasons IBM recommends that Java applications running in AIX use native iSeries Toolbox JDBC driver See the JDBC Data Access section of this paper (above) for more details On the other hand DB2 Connect is a very efficient and robust connectivity option for AIX applications especially in the environments that are not directly supported by the native iSeries JDBC driver Here are several possible scenarios that would require DB2 Connect installed in a AIX partition

Embedded SQL interface is used to access DB2 CLI or ODBC interface is used to access DB2 A single SQL interface is needed to access multiple back end DB2 server Specific DB2 Connect functionality is needed such as distributed join or connection

pooling

Prerequisites One of the DB2 Connect products or DB2 Enterprise Server Edition for AIX V81 is needed Additionally DB2 Application Development Client is required in the AIX partition to compile DB2 applications

For maximum database server stability the developer should install the latest database group PTF (SF99503 for i5OS V5R3) on the iSeries server The Informational APAR ii13348 is keeping track of any fixes relevant to DRDA above and beyond the current database group PTF

DB2 Connect configuration The following example employs i5OS V5R3 and DB2 UDB Enterprise Server Edition for AIX Version 81 FixPak 6

Configuration steps in the iSeries partition The following process lists the necessary steps to be performed on the iSeries server 1) Verify that the TCPIP stack is working correctly It is assumed that the Virtual LAN is used to

communicate with the i5OS partition First obtain the IP address of the iSeries server or its hostname and ping the iSeries server from the AIX partition

2) Create a relational database (RDB) entry for the iSeries database in the i5OS partition If this has already been created it can be displayed by using the DSPRDBDIRE command Make sure that the RDB entry with a location of LOCAL exists on the iSeries server If it does not exist use the ADDRDBDIRE command to add the appropriate RDB entry For example the following command would add an RDB entry named TPLX For simplicity it is recommended that the TCPIP host name and RDB entry remain the same

ADDRDBDIRE RDB(TPLX) RMTLOCNAME(LOCAL)

3) Create a collection called NULLID This is necessary because the utilities shipped with DB2 Connect and DB2 UDB for AIX store their packages in the NULLID collection Since it does not exist by default in the iSeries server you must create it using the following command

CRTLIB LIB(NULLID)

4) Products that support DRDA automatically perform any necessary code page conversions at the receiving system For this to happen both systems need a translation table from their code page to the partner code page The default Coded Character Set Identifier (CCSID) on the iSeries server is 65535 Since DB2 Connect does not have a translation table for this code page the developer needs to change the individual user profiles to contain a CCSID that can be converted properly by DB2 Connect For US English this is 037 For other languages see DB2 Connect Personal Edition Quick Beginning GC09-2967 The following command changes the CCSID for an individual user profile to 037

24

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

CHGUSRPRF userid CCSID(037)

5) Verify that the default port 446 for DRDA service is being used To do this go to the Configure TCPIP menu (CFGTCP) select Configure Related Tables and then select Work with service table entries Verify that the DRDA service is set for port 446

6) The Distributed Data Management (DDM) job must be started for DRDA to work If you want the DDM job to be automatically started whenever TCPIP is started change the attributes of the DDM job using the CHGDDMTCPA command and set the Autostart server parameter to YES

7) If the system administrator chooses not to autostart the server issue the following command to start the DDM server job

STRTCPSVR SERVER(DDM)

8) Make sure that the user profiles that will be used to connect to the iSeries server exist on the server

25

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Configuration steps in the AIX partition The following steps are required for DB2 Connect to be configured in the AIX partition 1) Sign on to the AIX partition as the DB2 administrator 2) Launch Client Configuration Assistant (db2ca from the command prompt) It is assumed that

VNC or an X-Windows server are being used on the workstation so that the db2ca GUI can be properly rendered

3) From the Selected pull-down menu select the Add Database using Wizard option The Select how you want to setup a connection dialog appears Select Manually configure a connection to a database and click Next This is shown in Figure 12

Figure 12 Accessing DB2 UDB for iSeries with DB2 Connect

26

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

4) On the Select a communications protocol choose TCPIP and select The database physical resides on a host or OS400 system Then select the option Connect directly to the server as shown in Figure 13 Click Next

Figure 13 mdash Selecting communications protocol

27

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

5) On the TCPIP tab fill in the host name of the iSeries server The port number should be 446 This is shown in Figure 14 Click Next

Figure 14 mdash Specifying TCPIP communication parameters

28

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

6) On the Database tab fill in the Relational Database name Use the RDB entry name (specified in step 2) in the Configuration steps in the iSeries partition section as shown in Figure 15 Click Next

Figure 15 mdash Specifying the remote database

7) If you plan to use the ODBC applications select Register this database for ODBC as a system data source on the ODBC tab Click Next

29

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

8) On the Specify the node option dialog select OS400 from the Operating System pull-down menu This is shown in Figure 16 Click Finish

Figure 16 mdash Specifying the node options

30

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

9) The Test Connection dialog appears This allows the developer to verify that the connection works Select both CLI and JDBC check boxes You are also prompted for an iSeries user ID and password as shown in Figure 17

Figure 17 mdash Testing the connection

31

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

10) The successful connection to the database server is confirmed by the message box shown in Figure 18

Figure 18 mdash Test Connection results 11) At this time a newly configured database connection should appear in the main DB2

Configuration Assistant window It is recommended that the DB2 utilities are also bound to the iSeries database The bind process creates the necessary SQL packages on the remote database In the main Configuration Assistant window click the TPLX database entry and then select Selected-gtBindhellip

32

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

12) The Bind dialog appears Click Select All and then enter the connection information as shown in Figure 19 Click Bind The Results message box appears This allows the developer to monitor the progress of the binding process Watch for any error and warning messages

Figure 19 mdash Binding the DB2 utilities This concludes the DB2 Connect configuration steps

33

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Accessing DB2 UDB for iSeries from C embedded SQL

As mentioned earlier DB2 Connect allows developers to compile and run embedded SQL applications that access DB2 UDB for iSeries data This section covers implementation details for a C embedded SQL application called cursorsjsqc (see Appendix B for source code)

Prerequisites An embedded SQL application running in an AIX partition will use DB2 Connect services to access DB2 UDB for iSeries therefore the developer needs to make sure that all components listed in section Prerequisites on page 24 are installed The developer also needs to create a remote database connection as described in the DB2 Connect configuration section of this paper on page 24

Static SQL and SQL packages To successfully run against a DB2 UDB for iSeries database an embedded SQL application needs to be first precompiled and bound to the back-end database This process creates an SQL package on the target iSeries server The SQL package contains the access plan information for the SQL statements executed by the application The internal structure of the package as well as the method how its content is used by the SQL runtime to facilitate the access plan reuse is similar to the Extended Dynamic SQL support covered in detail in the Extended Dynamic SQL and Statement Caching section of this paper (on page 9) There are however important differences between the packages created by the extended dynamic SQL support and the packages created for embedded SQL DRDA client applications The extended dynamic SQL packages support dynamic SQL interfaces such as JDBC

that can submit ad hoc SQL statements at the run time The SQL runtime can prepare the dynamic statements and add them to the package On the other hand the DRDA packages are created at the precompile time and contain static SQL In order to add new statements to the package the application needs to be precompiled and rebound again

The extended dynamic SQL package can dynamically grow up to 500MB by allocating new space as required The DRDA packages since they are created at the precompile time have a fix size and do not grow over their life time

Simple embedded SQL application The application is based on a source code provided in the DB2 UDB samples directory typically to be found at homedb2inst1sqllibsamples The cursorsjsqc performs a join between STAFF and ORG tables located in DB2USER schema (library) on the TPLX database server (the source is provided at the end of this paper in Appendix B) The join statement retrieves the DEPTNAME column from ORG NAME column from STAFF and calculates the total compensation for an employee by adding SALARY and COMM columns in STAFF The results are sorted by department name and total compensation Here is the SELECT statement used by the application

SELECT deptname name salary + IFNULL(comm0) as compensationFROM org o staff sWHERE odeptnumb = sdeptORDER BY deptname compensation DESC

The application iterates through the selected records and prints out the data to the standard output device The sample DB2USER schema was created with the following SQL statements

db2 CONNECT TO tplx USER db2user USING mypassworddb2 CALL QSYSCREATE_SQL_SAMPLE(DB2USER)

34

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Make sure that the AIX partition is logged into with the DB2 admin user profile If the defaults were selected at the DB2 installation time this profile name is db2inst1 It is also assumed that DB2USER user exists on the iSeries server and that it has appropriate authority

There are several steps that are required to create an executable for the cursorsjsqc source code First the DB2 PRECOMPILE utility needs to be called The utility creates a bind file that is used to bind the required SQL package to the TPLX database It also converts embedded SQL statements into DB2 run-time API calls and produces a pure C source file that can be processed by an AIX C compiler

db2 CONNECT TO tplx USER db2user USING mypassworddb2 prep cursorsjsqc bindfile

Note that the connect statement is required only if the developer is not already connected to the database on an iSeries server Watch for any error or warning messages returned by the DB2 prep utility The prepare step should produce cursorsjbnd and cursorsjc files in the current directory Now the developer can invoke the bind utility to prepare the statements contained in the bind file and create the package on the target iSeries database server

db2 bind cursorsjbnd

It is assumed that Visual C++ 60 is installed and configured in the AIX partition Refer to the ldquoDeveloping and Porting C and C++ Applications on AIXrdquo redbook for more information on how to use the Visual C++ compiler httpibmcomredbooksabstractssg245674htmlOpen

Use the following commands to compile the C source generated by the precompile utility

xlc -I$INSTHOMEsqllibinclude ndashc cursorsjcxlc ndasho cursorsj cursorsjo -L$INSTHOMEsqlliblib ndashldb2

Run the program from the AIX prompt

cursorsj db2user mypassword

Distributed Join DB2 UDB Version 8 provides core federated server functionality A federated system consists of a DB2 UDB instance that operates as a federated server a database that acts as the federated database one or more data sources and clients (users and applications) that access the database and data sources Federated server permits objects stored in multiple databases to be accessed together in the same query For example a query can refer to a table that resides in DB2 UDB for iSeries and join it to a table stored in DB2 UDB for AIX Such a query would constitute so called distributed join The support for DB2 UDB for iSeries as a federated data source is provided by core federated server functionality directly implemented in DB2 UDB Enterprise Server Edition and DB2 UDB Connect Enterprise Edition All other DB2 UDB family members are also supported directly by core DB2 UDB federated server An additional software product DB2 Information Integratortrade is required to access non-DB2 UDB databases such as Oracle Sybase or Microsoftreg SQL Server Consult the following white papers for a detailed discussion on DB2 federated server support Heterogeneous data access for iSeries applications Version 2 httpibmcomserversenablesiteeducationiborecordhtmlhetdata Fundamentals of IBM DB2 Federated Server and Relational Connect httpwww7bsoftwareibmcomdmddlibrarytecharticle0206purnell0206purnellhtml

35

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Distributed Join Example In this section the steps that are required to configure DB2 UDB for iSeries as a federated data source will be illustrated Then the cursorsjsqc program will be ldquotweakedrdquo so that it executes a distributed join query that accesses data stored on an iSeries server and in the local DB2 UDB for AIX database It is assumed that the developer is familiar with the DB2 federated server concepts

Note Run the following commands from the Command Line Processor prompt Load the utility by executing the db2 command at the AIX prompt 1) First the local DB2 UDB for AIX instance needs to be enabled as a DB2 federated server

This is done by setting the database manager configuration parameter FEDERATED to YES

db2=gt update dbm cfg using FEDERATED YES

The database instance needs to be restarted for the change to take effect

NOTE A federated database is a regular database in a DB2 UDB instance that has the FEDERATED parameter enabled Therefore in this example the SAMPLE database that was created earlier is used as the federated database A new database can also be created using the CREATE DATABASE command

2) Connect to the federated database

db2=gt connect to sample

3) Use the CREATE WRAPPER statement to register a wrapper for the iSeries data source Wrappers are library routines that are used by the federated server to perform operations such as connecting to a data source and retrieving data from it The default wrapper name for DB2 UDB for iSeries is DRDA Here is the command to register the DRDA wrapper

db2=gt create wrapper drda

4) Use the CREATE SERVER statement to register a data source as a server within the federated database The server definition specifies the type and version of the data source and the wrapper used for communications with this data source For the DB2 UDB for iSeries data source the node and the database names are also needed The node and database name parameters have been configured for our TPLX database in the Configuration steps in the AIX partition section (on page 24) Use the following DB2 UDB command to lookup these parameter on the federated server

db2=gt list database directory

In this case the command produced the following output

Database alias = TPLX Database name = DCSE99E1 Node name = NDE9BF76 Database release level = a00 Comment = Directory entry type = Remote Authentication = SERVER Catalog database partition number = -1

36

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Note that the node name is set to NDE9BF76 The name was generated by the Configuration Administrator utility (db2ca)

Here is the command to register the TPLX database as a federated server

db2=gt create server tplx type db2400 version 530 wrapperdrda authorization db2user password mypassword options(nodeNDE9BF76 dbname TPLX)

The command is quite complex so make sure that the syntax is correct

5) Define the user mappings that instructs the federated server what user ID and password should be used when connecting to the iSeries data source

db2=gt create user mapping for user server tplxoptions(remote_authid db2user remote_password mypassword)

Specify the nickname for the iSeries table or view A nickname is an identifier that is used by the federated server to reference an object located at the data source The following command creates a nickname for the STAFF table located in the DB2USER schema on the TPLX database

db2=gt create nickname tplx_staff for tplxdb2userstaff

6) Test the distributed join query

db2=gt SELECT deptname name salary + COALESCE(comm0) ascompensation FROM org o tplx_staff s WHERE odeptnumb =sdept ORDER BY deptname compensation DESC

Note that the native iSeries function IFNULL has been substituted with an equivalent DB2 UDB function COALESCE COALESCE is also supported on iSeries servers For better portability IBM encourages the use of COALESCE rather than IFNULL Note also that the query runs on the federated server rather than on TPLX It accesses the ORG table in the local DB2 UDB for AIX SAMPLE database and the STAFF table that resides in TPLX The federated server performs the necessary distributed join

7) Modify the cursorsjsqc so that it executes a distributed join There are two source code modifications - Change the CONNECT TO statements Now the application needs to connect to the

federated database SAMPLE rather than to TPLX

EXEC SQL CONNECT TO SAMPLEEXEC SQL CONNECT TO SAMPLE USER userid USING passwd

- Modify the select statement so that it performs a distributed join Use the statement (shown in step 6) above Save the new source version as cursordjsqc

- Prepare bind and compile the distributed join version of the program as described in the Simple C embedded SQL application section (on page 34)

db2 prep cursordjsqc bindfiledb2 bind cursordjbndxlc -I$INSTHOMEsqllibinclude ndashc cursordjcxlc ndasho cursordj cursordjo -L$INSTHOMEsqlliblib ndashldb2

37

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

- Run the program from the AIX prompt

cursordj

Connection Pooling and Connection ConcentratorA modern Web-based application typically executes a large number of short-lived transactions Executing a transaction in this environment means establishing a database connection executing a few SQL statements and terminating this connection Creating connections to the database server is a very costly process To reduce the unnecessary workload DB2 Connect implements connection pooling and connection concentrator Connection pooling mechanism allows DB2 Connect to reuse an existing connection infrastructure for subsequent connection requests The connection concentrator is an advanced technology that allows DB2 Connect to serve a potentially very large number of clients with a limited number of database connections This is accomplished by decoupling clients from a particular database connection

Note that currently neither connection pooling nor connection concentrator support DB2 UDB for iSeries Therefore for performance reasons the author strongly recommends that the application server that obtains and drops connections very frequently implements its own database connection pooling mechanism that would assign an existing pooled database connection to a new AIX process or thread

TroubleshootingTroubleshooting a multi-tier application may be a bit tricky because the developer needs to deal with software components that reside in separate partitions The authorrsquos experience shows that two tools are particularly useful for pinning down the potential problem areas The joblog messages for a database server job usually provide enough details to isolate DB2

UDB for iSeries runtime issues The DRDA trace utility provides granular information about the data flow between the AIX

application and the iSeries server job

38

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Job Log MessagesAs mentioned earlier a DB2 client communicates with a corresponding iSeries server job This server job runs the SQL requests on behalf of the client More precisely when a DB2 client submits an SQL statement the statement is passed to a server job that in turn calls the DB2 runtime to execute the statement The results are then reformatted and marshaled to the client The iSeries DRDA server jobs are called QRWTSRVR and they run in the QUSRWRK subsystem At any given time there may be a large number of DRDA server jobs active on the system so the first step is to identify the job that serves the particular client connection The easiest method to accomplish this task is to run the following CL command from the i5OS prompt

WRKOBJLCK OBJ(DB2USER) OBJTYPE(USRPRF)

Here DB2USER is the user profile that is used to connect to the iSeries server Note that a QRWTSRVR job is assigned to a client after the connection has been established so the developer needs to set a breakpoint in the client application below the CONNECT TO statement

Once the Work with Object Locks appears key in 5 (Work with Job) next to the only QRWTSRVR job that should be listed This shows the Work with Job dialog Select option 10 to display the job log for the database server job Now the developer can search the job log for any error messages generated by the DB2 runtime

Sometimes it is also useful to include debug messages in the job log The debug messages are informational messages written to the job log about the implementation of a query They describe query implementation methods such as use of indexes join order ODP implementation (reusable versus non-reusable) and so on The easiest way to instruct the iSeries server to include the debug messages is to call the following stored procedure just after the connection to the iSeries server is established

EXEC SQL call qsysqcmdexc(STRDBGUPDPROD(YES)000000002000000)

A sample of the job log messages with debug messages enabled is shown below in Figure 20

Arrival sequence access was used for file STAFFAccess path suggestion for file STAFFQuery options used to build the OS400 query access plan Ending debug message for query ODP created Blocking used for queryCursor SQLCUR201 opened1 rows fetched from cursor SQLCUR201Row not found for SQLCUR201ODP deleted Cursor SQLCUR201 closedDESCRIBE of prepared statement STMT0201 completed

Figure 20 mdash Joblog with debug messages enabled

So the job log offers fairly detailed information on how the AIX client requests were implemented by the DB2 runtime

39

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 DRDA trace utilityThe DB2 DRDA trace utility (db2drdat) provides detailed information about the data streams exchanged between DB2 Connect and target database server The output file produced by the utility contains send and receive communications buffers TCPIP error messages and SQL Communications Area (SQLCA) information Please refer to lsquoDB2 Connect Userrsquos Guidersquo manual for in-depth discussion of the DRDA trace utility

Accessing DB2 UDB for iSeries from CLI DB2 Call Level Interface (CLI ) is based on the Microsoft Open Database Connectivity (ODBC) specification and the ISO CLI standard The DB2 CLI interface gained popularity among DB2 application providers because the developer can build an ODBC application by simply linking the application with libdb2 library on a UNIX server In other words the developer directly utilizes the DB2 ODBC driver services without a need for an ODBC driver manager Additionally in contrast to embedded SQL the developer does not need to precompile or bind DB2 CLI applications because they use packages provided with DB2 UDB The developer simply compiles and links the application

Prerequisites A DB2 CLI application running in an AIX partition will use DB2 Connect services to access DB2 UDB for iSeries therefore make sure that all components listed in Prerequisites section of this paper on page 24 are installed The developer also needs to create a remote database connection as described in the DB2 Connect configuration section of this paper on page 24

Dynamic SQL and Access Plan Caching A DB2 CLI client application uses the dynamic SQL interface and does not have the capability to utilize the extended dynamic SQL support Therefore it runs lsquopurersquo dynamic SQL statements That does not mean however that the process of parsing validating and optimizing will be repeated for every execution of a given dynamic SQL statement

The DB2 UDB for iSeries database implements an internal object called System-Wide SQL Statement Cache (SWSC) The SWSC can improve the performance of programs using dynamic SQL statements by caching the access plans in a system-wide cache When a dynamic SQL statement is submitted the SQL runtime searches the SWSC to see if this statement has been previously executed If so then DB2 retrieves and reuses the key information associated with the cached statement and thereby the processing time and the resources utilization can be significantly reduced

Simple DB2 CLI C++ ApplicationThis section covers DB2 CLI implementation details for a sample C++ program called testclicpp (the source is provided at the end of this paper in Appendix C) To compile the source with Visual C++ complier use the following command in the AIX partition

xlC ndashI$INSTHOMEsqllibinclude ndashc testclicppxlC ndasho testcli testclio ndashL$INSTHOMEsqlliblib ndashldb2

The application performs a join between STAFF and ORG tables located in DB2USER schema (library) The join statement retrieves the DEPTNAME column from ORG NAME and JOB columns from STAFF and calculates the total compensation for an employee by adding SALARY and COMM columns in STAFF The results are sorted by total compensation The selection criterion is based on the current value of the department name parameter Here is the SELECT statement used by testcli

40

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

select name job salary + coalesce(comm0) as compensationfrom org o staff swhere odeptnumb = sdeptand deptname = order by compensation desc

Figure 21 shows the software components involved in the execution of this sample application

Figure 21 How a DB2 CLI client accesses DB2 UDB on an iSeries server

Although the testcli application is fairly simple it covers some important aspects of efficient CLI programming for DB2 UDB for iSeries

Reusable Open Data Paths (ODPs)An Open Data Path (ODP) definition is an internal i5OS object that is created when certain SQL statements (such as OPEN INSERT UPDATE and DELETE) are executed for the first time in a given job (or connection) The ODP can be thought of as a runtime implementation of an access plan The access plan created at the optimization time provides a recipe or in other words a sequence of steps necessary to execute the statement The ODP on the other hand provides the executable code for all requested IO operations The process of creating new ODP objects is fairly CPU- and IO-intensive so whenever possible the iSeries DB2 runtime tries to reuse existing ODPs For instance a SQLCloseCursor() API call may close the SQL cursor but leave the ODP available to be used the next time the cursor is opened This can significantly reduce the processing and response time in running SQL statements A reusable OPD usually requires 10 to 20 times less CPU resources than a newly created ODP Therefore it is important that the applications employ programming techniques that allow the DB2 runtime to reuse ODPs

With dynamic interfaces such as CLI full opens are avoided by using a prepare once execute many programming paradigm It means that when an SQL statement is going to be executed more than once you should prepare the statement just once and then reuse the prepared

41

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

statements for consecutive executions Although DB2 UDB does try to convert literals to parameter markers so that similar statements can be reused it is a better programming practice to explicitly implement parameter markers That way the chances for reusable ODPs are quite significantly improved The code snippet in Figure 22 illustrates how to implement the prepare once execute many programming technique

Define A SELECT SQL Statementstrcpy((char ) SQLStmt select name job salary + ifnull(comm0) ascompensation )ptr = strcat( (char ) SQLStmt from org o staff s )ptr = strcat( (char ) SQLStmt where odeptnumb = sdept)ptr = strcat( (char ) SQLStmt and deptname = )ptr = strcat( (char ) SQLStmt order by compensation desc) [1]

Prepare The SQL Statementrc = SQLPrepare(ExampleStmtHandle SQLStmt SQL_NTS) [2]

Bind The Columns In The Result Data Set Returned To Application Variablesrc = SQLBindCol(ExampleStmtHandle 1 SQL_C_CHAR (SQLPOINTER)

ExampleName sizeof(ExampleName) NULL)rc = SQLBindCol(ExampleStmtHandle 2 SQL_C_CHAR (SQLPOINTER)

ExampleJob sizeof(ExampleJob) NULL)rc = SQLBindCol(ExampleStmtHandle 3 SQL_C_DOUBLE (SQLPOINTER)

ampExampleComp sizeof(ExampleComp) NULL)

for (int i = 0 i lt LOOPS i++)rc=SQLBindParameter(ExampleStmtHandle

1SQL_PARAM_INPUTSQL_C_CHARSQL_CHAR10(SQLPOINTER) currentDepartment[i8]0NULL) [3]

rc = SQLExecute(ExampleStmtHandle) [4]cout ltlt endl ltlt Current Dept ltlt currentDepartment[i8] ltlt endl Display The Results Of The SQL QueryExampleShowResults()

Figure 22 Use the prepare once execute many programming technique

The error-handling code has been removed for clarity At [1] the statement text is assigned to a variable Note that a parameter marker is used in the WHERE clause The statement is then prepared just once at [2] The current value of the parameter is bound to the prepared statement at [3] The prepared statement is executed at [4] Steps [3] and [4] are repeatedly executed in a for loop

Techniques to Further Improve DB2 CLI Performance Thus far this paper has discussed the techniques used by a sample application to tune the CLI performance However depending on the application architecture other methods of improving CLI performance may be considered

Connection PoolingCurrently the CLI application connecting through DB2 Connect to DB2 UDB for iSeries does not take advantage of the connection pooling mechanism implemented by DB2 Connect Therefore for performance reasons the author strongly recommends that the application server that obtains and drops connections very frequently implements its own database connection pooling mechanism that would assign an existing pooled database connection to a new AIX process or thread

42

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Blocking

For queries which result in returning large data blocks from the iSeries server (usually 32K of data and above) ensure that the database manager configuration parameter RQRIOBLK is set to 32767 This can be done using the Command Line Processor (CLP) as follows

db2 update database manager configuration using RQRIOBLK 32767

TroubleshootingThe experience of the author shows that two tools are particularly useful for pinning down the potential problem areas bull Joblog messages for a database server job usually provides enough details to isolate DB2

runtime issues bull CLI trace utility provides granular information about the data flow between the AIX application

and the database server job

Job Log MessagesThe process of finding and analyzing the job log for a DB2 CLI connection is identical to the process outlined for an embedded SQL application in the Job Log Message section of this paper on page 39

CLI Trace The DB2 CLIODBCJDBC trace utility provides very detailed information about the data streams exchanged between DB2 Connect and target database server Refer to the DB2 Information Center for more information on how to set up and analyze the CLI traces httppublibboulderibmcominfocenterdb2v8luwindexjsptopic=comibmdb2udbdocadc000 7959htm

43

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Trademarks

IBM eServer iSeries AIX AIX 5L i5OS WebSphere DB2 DB2 Universal Database DB2 Connect OS400 zOS OS390 Distributed Relational Database Architecture DRDA and DB2 Information Integration are trademarks or registered trademarks of International Business Machines Corporation in the United States and other countries

Java and all Java-based trademarks are trademarks of Sun Microsystems Inc in the United States other countries or both

Linux is a registered trademark of Linus Torvalds in the United States other countries or both

UNIX is a registered trademark of The Open Group in the United States and other countries

Microsoft and Windows are registered trademarks of Microsoft Corporation in the United States andor other countries

All other registered trademarks and trademarks are properties of their respective owners

IBM makes no commitment to make available any products referred to herein

References in this publication to IBM products or services do not imply that IBM intends to make them available in every country in which IBM operates

Additional Information ITSO offers a Redbook that can be helpful to those who want to learn more about i5OS AIX integration

bull AIX Integration with I5OS on the IBM eServer iSeries Server (SG24-6551)

Jarek Miszczyk is the Senior Software Engineer IBM eServer Solutions Enablement IBM Rochester

[Portions of this white paper reprinted with permission from MC Mag Online published by MC Press LLP httpwwwmcpressonlinecom]

Acknowledgments The author would like to thank the following people for their advice contributions and support on this paper

Bob Bittner IBM Rochester Jon Rush IBM Rochester Prasad Vallurupalli IBM Rochester Neil Willis IBM Rochester

44

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix A Source Listing of TestJDBCjava

package comibmiseriespwdimport javasqlimport javaxnamingimport javautilHashtableimport javautilimport javaxsqlimport comibmas400access

public class TestJDBC public static void main(javalangString[] args)

throws Exception

int numOfLoops = 5000int outerNumOfLoops = 5boolean firstExec = trueConnection conStatement sPreparedStatement psPreparedStatement pstmtdelCallableStatement cstmPreparedStatement pstmtHashtable env = new Hashtable()

envput(ContextINITIAL_CONTEXT_FACTORYcomsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env)Systemoutprintln(Deploying connection pooling data source)deployDataSource() Do the work with connection pooling onlyAS400JDBCConnectionPoolDataSource tkcpds =

(AS400JDBCConnectionPoolDataSource)ctxlookup(jdbcToolkitDataSource) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPool pool = new AS400JDBCConnectionPool(tkcpds) Adds 1 connection to the pool that can be used by theapplication (creates the physical database connections based onthe data source)poolfill(1)Systemoutprintln(nStart timing Toolkit connection pooling)long startTime = SystemcurrentTimeMillis()

for (int i = 0 i lt outerNumOfLoops i++) con = poolgetConnection()consetAutoCommit(false) deleteif ( i == 0)

long startDelete = SystemcurrentTimeMillis()cstm = cstm = conprepareCall(

CALL qsysqcmdexc(CLRPFM FILE(DB2USERCOFFEES) + 000000002800000))

cstmexecuteUpdate()cstmclose()long endDelete = SystemcurrentTimeMillis()Systemoutprintln(Delete all records +

(endDelete - startDelete) + ms elapsed)

45

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

String sqlinstrlong startInsert = SystemcurrentTimeMillis() insert

pstmt =conprepareStatement(INSERT INTO COFFEES VALUES( ))for (int j = 0 j lt numOfLoops j++) pstmtsetString(1 Kona_ + IntegertoString(i))pstmtsetInt(2 150)pstmtsetFloat(3 999f)pstmtsetInt(4 0)pstmtsetInt(5 0)pstmtaddBatch()int [] updateCounts = pstmtexecuteBatch()concommit()pstmtclose()long endInsert = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for + numOfLoops + inserts

+ (endInsert - startInsert)) selectlong startSelect = SystemcurrentTimeMillis()ps = conprepareStatement(SELECT FROM COFFEES)ResultSet rs = psexecuteQuery()rsnext()rsclose()concommit()psclose()long endSelect = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for select +

(endSelect - startSelect))consetAutoCommit(true)conclose()long endTime = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for + outerNumOfLoops +

loops + (endTime - startTime))Systemexit(0)

private static void deployDataSource()throws ExceptionString serverName = teraplex String databaseName = TERAPLEX String userName = db2user String password = db2pwd

Establish a JNDI context and bind the connection pool data sourceHashtable env = new Hashtable()envput(ContextINITIAL_CONTEXT_FACTORY

comsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPoolDataSource tkcpds = new

AS400JDBCConnectionPoolDataSource()tkcpdssetServerName(serverName) tkcpdssetDatabaseName(databaseName) tkcpdssetUser(userName) tkcpdssetPassword(password) tkcpdssetDescription(Toolkit Connection Pooling DataSource)tkcpdssetSavePasswordWhenSerialized(true)tkcpdssetExtendedDynamic(true)

46

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

tkcpdssetPackage(JDBCDS)tkcpdssetPackageCache(true)tkcpdssetPackageCriteria(select)enable the following properties as requiredcpdssetTrace(true)tkcpdssetServerTraceCategories( AS400JDBCDataSourceSERVER_TRACE_DEBUG_SERVER_JOB)

ctxrebind(jdbcToolkitDataSource tkcpds)

47

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix B mdash Source Listing of cursorsjsqc

Source File Name = cursorsjsqc Licensed Materials - Property of IBM (C) COPYRIGHT International Business Machines Corp 1995 2000 2004 All Rights Reserved US Government Users Restricted Rights - Use duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp PURPOSE This sample program demonstrates the use of a CURSOR The CURSOR is processed using static SQL EXTERNAL DEPENDENCIES - Ensure existence of database for precompile purposes - Precompile with the SQL precompiler (PREP in DB2) - Bind to a database (BIND in DB2) - Compile and link with the IBM Cset++ compiler (AIX and OS2) or the Microsoft Visual C++ compiler (Windows) or the compiler supported on your platform For more information about these samples see the README file For more information on programming in C see the - Programming in C and C++ section of the Application Development Guide For more information on building C applications see the - Building C Applications section of the Application Building Guide For more information on the SQL language see the SQL Reference

include ltstdiohgt include ltstdlibhgt include ltstringhgtinclude ltsqlhgtinclude ltsqlenvhgtinclude ltsqldahgtinclude ltsqlcahgt

int SqlInfoPrint( char struct sqlca int char )void TransRollback( void)

define EMB_SQL_CHECK( MSG_STR ) rc = SqlInfoPrint( MSG_STR ampsqlca __LINE__ __FILE__) if ( rc = 0 ) TransRollback( )

return 1

EXEC SQL INCLUDE SQLCA

int main(int argc char argv[])

EXEC SQL BEGIN DECLARE SECTIONchar dname[15]

48

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

char pname[10]double compchar userid[9]char passwd[19]

EXEC SQL END DECLARE SECTION

int rc = 0printf( Sample C program CURSORSJ n )if (argc == 1)

EXEC SQL CONNECT TO TPLXEMB_SQL_CHECK(CONNECT TO TPLX)

else if (argc == 3)

strcpy (userid argv[1])strcpy (passwd argv[2])EXEC SQL CONNECT TO TPLX USER userid USING passwdEMB_SQL_CHECK(CONNECT TO TPLX)

else

printf (nUSAGE cursor [userid passwd]nn)return 1

endif

EXEC SQL DECLARE c1 CURSOR FORselect deptname name salary + ifnull(comm0) as compensationfrom org o staff swhere odeptnumb = sdeptorder by deptname compensation desc

EXEC SQL OPEN c1EMB_SQL_CHECK(OPEN CURSOR)

printf(DEPARTMENT NAME COMPENSn)printf(-----------------------------------n)do

EXEC SQL FETCH c1 INTO dname pname compif (SQLCODE = 0) breakprintf( -1515s -1010s 72fn dname pname comp )

while ( 1 )

EXEC SQL CLOSE c1EMB_SQL_CHECK(CLOSE CURSOR)

EXEC SQL CONNECT RESETEMB_SQL_CHECK(CONNECT RESET)

exit(0)

end of program CURSORSJSQC

int SqlInfoPrint( char appMsgstruct sqlca pSqlcaint linechar file )

int rc = 0char sqlInfo[1024]char sqlInfoToken[1024]char sqlstateMsg[1024]char errorMsg[1024]

if (pSqlca-gtsqlcode = 0 ampamp pSqlca-gtsqlcode = 100)

49

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

strcpy(sqlInfo )if( pSqlca-gtsqlcode lt 0) sprintf( sqlInfoToken n---- error report ----n)

strcat( sqlInfo sqlInfoToken)else sprintf( sqlInfoToken n---- warning report ----n)

strcat( sqlInfo sqlInfoToken) endif

sprintf( sqlInfoToken app message = sn appMsg)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken line = dn line)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken file = sn file)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken SQLCODE = ldn pSqlca-gtsqlcode)strcat( sqlInfo sqlInfoToken)

get error message rc = sqlaintp( errorMsg 1024 80 pSqlca) return code is the length of the errorMsg string if( rc gt 0) sprintf( sqlInfoToken sn errorMsg)

strcat( sqlInfo sqlInfoToken)

get SQLSTATE message rc = sqlogstt( sqlstateMsg 1024 80 pSqlca-gtsqlstate)if (rc == 0) sprintf( sqlInfoToken sn sqlstateMsg)

strcat( sqlInfo sqlInfoToken)

if( pSqlca-gtsqlcode lt 0) sprintf( sqlInfoToken --- end error report ---n)

strcat( sqlInfo sqlInfoToken)printf(s sqlInfo)return 1

else sprintf( sqlInfoToken --- end warning report ---n)

strcat( sqlInfo sqlInfoToken)printf(s sqlInfo)return 0

endif endif

return 0

void TransRollback( ) struct sqlca sqlca

int rc = 0 rollback the transaction printf( nRolling back the transaction n)

EXEC SQL ROLLBACKrc = SqlInfoPrint( ROLLBACK ampsqlca __LINE__ __FILE__)if( rc == 0) printf( The transaction was rolled backn)

50

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

51

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix C mdash Source Listing of testclicpp

Include The Appropriate Header Filesinclude ltsqlclihgtinclude ltsqlcli1hgtinclude ltsqlutilhgtinclude ltsqlenvhgtinclude ltstdiohgt include ltiostreamgt include ltlocalehgt include ltstringhgtdefine SQL_SQLSTATE_SIZE 5define LOOPS 8

using namespace std

Define The CLI_Class Classclass CLI_Class

Attributespublic

SQLHANDLE EnvHandleSQLHANDLE ConHandleSQLHANDLE StmtHandleSQLRETURN rcSQLCHAR Job[6]SQLCHAR Name[10]SQLDOUBLE Comp

Operationspublic

CLI_Class()~CLI_Class()SQLRETURN ShowResults()

Constructor Destructor

SQLRETURN printError( SQLHDBC SQLHSTMT)

Define The Class ConstructorCLI_ClassCLI_Class()

setlocale( LC_ALL )

Initialize The Return Code Variablerc = SQL_SUCCESS

Allocate An Environment Handlerc = SQLAllocHandle(SQL_HANDLE_ENV SQL_NULL_HANDLE ampEnvHandle)

Allocate A Connection Handleif (rc == SQL_SUCCESS)

rc = SQLAllocHandle(SQL_HANDLE_DBC EnvHandle ampConHandle)

Define The Class DestructorCLI_Class~CLI_Class()

Free The Connection Handleif (ConHandle = NULL)

SQLFreeHandle(SQL_HANDLE_DBC ConHandle)

Free The Environment Handle

52

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

if (EnvHandle = NULL)SQLFreeHandle(SQL_HANDLE_ENV EnvHandle)

Define The ShowResults() Member FunctionSQLRETURN CLI_ClassShowResults(void)

While There Are Records In The Result Data Set Generated Retrieve And Display Themcout ltlt Name Job Compensation ltlt endlcout ltlt --------- ------ ------------ ltlt endlcoutsetf(iosleft)coutprecision(2)coutsetf(iosfixed)while (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)

rc = SQLFetch(StmtHandle)if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)

coutwidth(15)cout ltlt Name

coutwidth(10)cout ltlt Job

coutwidth(7)cout ltlt Comp ltltendl

if(rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO ampamp rc = SQL_NO_DATA)printError(ConHandle StmtHandle)

else

rc = 0SQLCloseCursor(StmtHandle)

Return The ODBC API Return Code To The Calling Functionreturn(rc)

SQLRETURN CLI_ClassprintError (SQLHDBC hdbc

SQLHSTMT hstmt)

SQLCHAR buffer[SQL_MAX_MESSAGE_LENGTH + 1]SQLCHAR sqlstate[SQL_SQLSTATE_SIZE + 1]SQLINTEGER sqlcodeSQLSMALLINT lengthSQLRETURN rcwhile ((rc = SQLError(SQL_NULL_HENV hdbc hstmt

sqlstateampsqlcodebufferSQL_MAX_MESSAGE_LENGTH + 1amplength)) == SQL_SUCCESS || rc ==

SQL_SUCCESS_WITH_INFO)

cout ltlt SQLSTATE ltlt sqlstate ltlt endlcout ltlt SQLCODE ltlt sqlcode ltlt endlcout ltlt Error msg ltlt buffer ltlt endl

53

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

cout ltlt----------------------------- ltlt endl ltlt endl

return(SQL_ERROR)

----------------------------------------------------------------- The Main Function -----------------------------------------------------------------int main()

Declare The Local Memory Variables

(SQLCHAR ) db2user SQL_NTS (SQLCHAR ) test26t SQL_NTS)

SQLRETURNSQLCHARSQLCHARSQLCHARchar

SQLCHAR

rc = SQL_SUCCESSDBName[10] = TPLXSQLStmt[255]c[10]ptrcurrentDepartment[8][15] = Head Office

New England Mid Atlantic South Atlantic Great Lakes PlainsPacificMountain

Create An Instance Of The CLI_Class ClassCLI_Class Example

Connect To iSeries Database if (ExampleConHandle = NULL)

rc = SQLConnect(ExampleConHandle DBName SQL_NTS

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)ExampleprintError(ExampleConHandle SQL_NULL_HSTMT)

return(rc)

cout ltlt Successfully connected to ltlt DBName ltlt ltlt endlrc = SQLSetConnectAttr(ExampleConHandle SQL_ATTR_AUTOCOMMIT

(SQLPOINTER) SQL_AUTOCOMMIT_OFF SQL_IS_UINTEGER) Allocate An SQL Statement Handlerc = SQLAllocHandle(SQL_HANDLE_STMT ExampleConHandle

ampExampleStmtHandle)if (rc == SQL_SUCCESS)

Define A SELECT SQL Statement

strcpy((char ) SQLStmt select name job salary + ifnull(comm0) ascompensation )

ptr = strcat( (char ) SQLStmt from org o staff s )ptr = strcat( (char ) SQLStmt where odeptnumb = sdept)ptr = strcat( (char ) SQLStmt and deptname = )ptr = strcat( (char ) SQLStmt order by compensation desc)

Prepare The SQL Statementrc = SQLPrepare(ExampleStmtHandle SQLStmt SQL_NTS)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)ExampleprintError(ExampleConHandle ExampleStmtHandle)

54

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

return(rc)

Bind The Columns In The Result Data Set Returned To Application Variables

rc = SQLBindCol(ExampleStmtHandle 1 SQL_C_CHAR (SQLPOINTER)ExampleName sizeof(ExampleName) NULL)

rc = SQLBindCol(ExampleStmtHandle 2 SQL_C_CHAR (SQLPOINTER)ExampleJob sizeof(ExampleJob) NULL)

rc = SQLBindCol(ExampleStmtHandle 3 SQL_C_DOUBLE (SQLPOINTER)ampExampleComp sizeof(ExampleComp) NULL)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO) ExampleprintError(ExampleConHandle ExampleStmtHandle)

return(rc)

while (true)

for (int i = 0 i lt LOOPS i++)

rc=SQLBindParameter(ExampleStmtHandle1SQL_PARAM_INPUTSQL_C_CHARSQL_CHAR

150(SQLPOINTER) currentDepartment[i8]0NULL)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)

ExampleprintError(ExampleConHandle ExampleStmtHandle)return(rc)

rc = SQLExecute(ExampleStmtHandle)if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)

ExampleprintError(ExampleConHandle ExampleStmtHandle)return(rc)

cout ltlt endl ltlt Current Dept ltlt currentDepartment[i8] ltlt

endl Display The Results Of The SQL QueryExampleShowResults()if(rc = 0)break

if ( i500 == 0 ampamp i gt 0 )cout ltlt Loops ltlt i ltlt ltlt endl

cout ltlt AFTER ltlt LOOPS ltlt loops Press X to exit ltlt endlcin gtgt cif (c[0] == x || c[0] == X)

break

Free The SQL Statement Handleif (ExampleStmtHandle = NULL )

SQLFreeHandle(SQL_HANDLE_STMT ExampleStmtHandle) Disconnect From The Northwind Sample Databaserc = SQLDisconnect(ExampleConHandle)

Return To The Operating Systemreturn(rc)

55

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

PreparedStatement pstmt =conprepareStatement(INSERT INTO COFFEES VALUES( ))[1]for (int j = 0 j lt numOfLoops j++) pstmtsetString(1 Lavaza_ + IntegertoString(j))pstmtsetInt(2 i)pstmtsetFloat(3 499f)pstmtsetInt(4 0)pstmtsetInt(5 0)pstmtaddBatch() [2]

int [] updateCounts = pstmtexecuteBatch() [3]

At [1] a parameterized insert statement is prepared Note that all columns must be parameterized Otherwise the executeBatch method may throw the SQL0221 Number of rows 1 not valid exception In other words the developer should not mix parameter markers with literals or special registers in the VALUE clause

At [2] the addBatch method is used to add a new record to the client record buffer

At [3] all locally buffered data is sent to the server which in turn performs a block insert

Figure 4 shows the performance data for the executeBatch and executeUpdate methods

Figure 4 executeBatch() versus executeUpdate() performance comparison

11

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

WebSphere Considerations In certain situations an application provider may decide to deploy WebSphere Application Server in an AIX partition rather than natively in i5OS At the same time the application uses DB2 UDB for iSeries as an back-end database server Typically the WebSphere Application Server running in the AIX partition uses the virtual LAN to communicate with DB2 UDB for iSeries The WebSphere applications will access the database through a remote JDBC connection For performance and functionality reasons IBM recommends to utilize in such environments the IBM Toolbox for Java JTOpen driver Most of the tips and techniques described so far in this document hold true for WebSphere applications accessing DB2 UDB for iSeries There are however certain JDBC access aspects that are specific to this multi-tier architecture Letrsquos have a closer look at some of these considerations

Connection Pooling and Statement Caching

WebSphere Application Server provides its own connection pooling and statement caching mechanism that is by default enabled so that WebSphere applications automatically enjoy the performance benefits of these two critical programming techniques See the following link to learn more about the optimal connection pool setting in WebSphere

httppublibboulderibmcomwas40051englishinforzaiz51adminhelpudat_conpoolsethtml

Extended Dynamic SQL

For non-JTA connections WebSphere Application Server uses the comibmas400accessAS400JDBCConnectionPoolDataSource class as the iSeries JDBC provider implementation This is the DataSource implementation that has been used in all previous coding examples As mentioned the class supports a range of iSeries specific properties that can be used to fine tune JDBC performance These properties can be set through the WebSphere Application Server admin console For example herersquos the procedure to enable the extended dynamic SQL support In the WebSphere Application Server admin console navigate to the Data Source configuration dialog by selecting JDBC Providers -gt iSeriesToolbox -gt Data Sources then scroll down to the Additional Properties section Select Custom Properties link The Custom Properties dialog opens Scroll down to find the Extended Dynamic property and select it Change the default value false to true save the new configuration by clicking Apply button This is illustrated in Figure 5

12

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 5 Enabling the extended dynamic SQL through WebSphere Application Server console

The WebSphere Application Server needs to be restarted for the change to take effect The similar procedure can be followed to set other iSeries Data Source properties

Changing the WebSphere Application Server default isolation level

WebSphere Application Server V5 uses the REPEATABLE_READ (RR) isolation level for all implicit (WebSphere Application Server managed) transactions With the RR isolation level the rows selected updated deleted and inserted are locked until the end of the transaction Under certain circumstances this fairly extensive locking policy may cause locking contention especially when a WebSphere application competes for database resources with other applications that run on iSeries server For example a legacy order entry application may share data with the e-business customer care application running in WebSphere The locking contention may sometimes be eliminated by lowering the isolation level used by WebSphere Although the iSeries Data Source supports the custom transactionIsolation property resetting this property on the Data Source object will not change the default isolation level used by WebSphere for the connection objects produced by that Data Source In other words WebSphere will override the Data Source isolation level setting at the time the connection is obtained by a WebSphere application object such as servlet or Enterprise Java Bean (EJB) In order to change the default WebSphere behavior one must use the resource referencing Resource referencing allows a programmer to lookup DataSource or EJB objects using alias names rather than JNDI names Additionally by creating a resource reference a programmer can change certain properties of the underlying object Specifically a DataSource reference can be used to set a different isolation level for the connections produced by this database resource Typically resource references are defined by a programmer in a application development tool such as WebSphere Studio Application Developer The method to specify a DataSource reference differs depending on whether a programmer plans to use the reference in a servlet or in an EJB Letrsquos start with outlining the configuration process for a servlet In WebSphere Studio Application Developer open the deployment descriptor editor for the web project that contains the servlet To do so double click on the webxml file under WEB-INF directory in the web project In the deployment editor dialog select the References tab and then select Resource tab located in the top of the dialog that appears Under Resource References section select the Add button Herersquos an example of a DataSource reference created for iSeries DataSource named TestJDBCDS Note that the reference changes the default isolation level to READ_COMMITTED

13

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 6 Defining a resource reference for a servlet

Once the resource reference has been defined and saved the servlet source code needs to be changed to reflect the fact that a resource reference is used to obtain a DataSource from the JNDI service Herersquos the relevant code snippet try

ctx = new InitialContext() ds = (DataSource)ctxlookup(javacompenvTestJDBCJ2C)

catch (Exception e) eprintStackTrace(out)

Now the ds DataSource object will produce connections that by default run with the isolation level of READ_COMMITTED (RC)

As mentioned the process of defining a resource reference for an EJB differs from the process that is used in the case of a servlet In WebSphere Studio Application Developer open the deployment descriptor editor for the EJB project that contains the EJB To do so double click on the ejb-jarxml file under WEB-INF directory in the project In the deployment editor dialog select the References tab In the references section on the left locate and select the EJB for which the developer wants to change the default isolation level Click the Add button The Add Reference dialog opens Click the Resource Reference radio button and then Next Define the reference following the example shown in Figure 7

14

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 7 Adding a resource reference for an EJB

When you click ldquoFinishrdquo the reference definition is added to the EJB descriptor The new definition needs to be further modified To do so click on the (+) sign next to the EJB in the References list Click the new reference TestJDBCJ2C in this example to open the properties for the reference Change WebSphere Bindings and WebSphere Extensions sections as illustrated in Figure 8

15

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 8 Defining a resource reference for an EJB

Save the modified definition and then change the EJB source code to use the reference rather than directly DataSource

TroubleshootingTroubleshooting a multi-tier application may be a bit tricky because the developer needs to deal with software components that reside in separate partitions Three tools are particularly useful for pinning down the potential problem areas bull Joblog messages for a database server job mdash Provides enough details to isolate DB2 UDB for

iSeries runtime issues bull JDBC trace utility mdash Provides granular information about the data flow between the AIX

application and the iSeries server job bull Database Monitor ndash Provides detailed SQL runtime trace

Job Log MessagesAs mentioned a DB2 client communicates with a corresponding iSeries server job This server job runs the SQL requests on behalf of the client The iSeries database server jobs are called QZDASOINIT and they run in the QUSRWRK subsystem At any given time a large number of database server jobs may be active on the server so the first step is to identify the job that serves the particular client connection The easiest method to accomplish this task is to run the following CL command from the i5OS prompt

WRKOBJLCK OBJ(DB2USER) OBJTYPE(USRPRF)

Here DB2USER is the user profile that is used to connect to the iSeries server Note that a QZDASONIT job is assigned to a client after the connection has been established so the developer needs to set a breakpoint in the client application after the database connection has been established

Once the Work with Object Locks appears key in 5 (Work with Job) next to the only QZDASOINIT job that should be listed This shows the Work with Job dialog Select option 10 to

16

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

display the job log for the database server job Now the job log can be searched for any error messages generated by the DB2 runtime

Sometimes it is also useful to include debug messages in the job log The debug messages are informational messages written to the job log about the implementation of a query They describe query implementation methods such as the use of indexes join order ODP implementation (reusable versus non-reusable) and so on The easiest way to instruct an iSeries server to include the debug messages is to set the ServerTraceCategories property on the data source object

tkcpdssetServerTraceCategories(AS400JDBCDataSourceSERVER_TRACE_DEBUG_SERVER_JOB)

A sample of the job log messages with debug messages enabled is shown below

SET TRANSACTION completeSTATEMENT NAME FOUND QZ868F0A458E13AF8C Starting optimizer debug message for query Arrival sequence access was used for file COFFEESODP created ODP not deleted 5000 rows inserted in COFFEES in DB2USER STATEMENT NAME FOUND QZ868F0A4C144BF12EBlocking used for queryCursor CRSR0001 opened606 rows fetched from cursor CRSR0001 ODP not deleted Cursor CRSR0001 closed

So the job log offers fairly detailed information on how the AIX client requests were implemented by the DB2 runtime

JDBC Trace UtilityThe JTOpen driver provides a tracing utility which can be used to collect detailed client-side traces The JDBC tracing is turned off by default It can be enabled by setting the Trace property to true Heres an example of how to switch on tracing using the setTrace method on the data source object

tkcpdssetTrace(true)

The trace can also be enabled when using the DriverManagergetConnection() method for obtaining a connection to DB2 UDB for iSeries In this case the developer could add the trace property to the connection string This approach is illustrated in the following code snippet

ClassforName(comibmas400accessAS400JDBCDriver) [1] hellip con = DriverManagergetConnection(jdbcas400teraplextrace=true

db2userdb2pwd) [2]

At [1] an instance of the JTOpen JDBC Driver is initiated Then at [2] the driver is used to obtain a connection to the iSeries server Note how the trace property has been added to the database URL See the IBM Toolbox for Java JDBC properties documentation on the iSeries Information Center Web site for a complete list of properties supported by the JTOpen driver

Although the level of details provided by the trace utility is sufficient in most troubleshooting scenarios sometimes the developer may need to collect low-level traces scoped to a certain type

17

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

of information In V5R3 the IBM Toolbox for Java (as well as the latest JTOpen) added a comprehensive detailed trace facility The following is the complete list of detailed trace parameters and their purpose

bull None or ldquordquo ndash This setting disables the detailed trace bull datastream - This category is used by Toolbox classes to log dataflow between the local host

and the remote system It is not intended for use by application classes bull diagnostic - This category is used to log object state information bull error - This category is used to log errors that cause an exception bull information - This category is used to track the flow of control through the code bull warning - This category is used to log errors that are recoverable bull conversion - This category is used by Toolbox classes to log character set conversions

between Unicode and native code pages bull proxy - This category is used by Toolbox classes to log data flow between the client and the

proxy server bull pcml - This category is used to determine how PCML interprets the data that is sent to and

from the server bull jdbc - This category is used to track JDBC calls throughout the program bull thread - This category is used to enable tracing of thread information This is useful when

debugging multi-threaded applications bull all - This category will enable all previous categories

The detailed trace can be enabled when using the DriverManagergetConnection() method for obtaining a connection to DB2 UDB for iSeries In this case the developer could add the toolbox trace property to the connection string This is illustrated in the following code sample

String dbUrl = jdbcas400pwd1toolbox trace=diagnostic con = DriverManagergetConnection(dbUrl dbUser dbPassword)

Note that currently the driverrsquos DataSource interfaces do not allow the developer to directly activate the detailed tracing However they could set the server from the command line at the time the java program is launched The example below shows how the detailed trace properties could be enabled at the command line

java -Dcomibmas400accessTracecategory=diagnostic TestJDBC

The -D switch indicates to the java interpreter that the information following it will be a system property

In case of a WebSphere application the trace property can be set through the admin console In the console select Application Servers-gt server1-gt Process Definition -gt Java Virtual Machine Figure 9 shows how to set the Generic JVM Arguments for an application server instance

18

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 9 Setting JVM arguments to enable detailed Toolbox tracing

Database Monitor

The database monitor is the ultimate tool available on DB2 UDB for iSeries to collect low-level SQL traces It is mainly used to pin down the SQL performance problems Refer to the lsquoUsing iSeries Database Monitor to Identify and Tune SQL Queriesrsquo white paper for a detailed discussion on how to collect and analyze the database monitor traces httpibmcomserversenablesiteeducationiborecordhtmldtmon

IBM DB2 JDBC Universal Driver DB2 JDBC Universal Driver is one of the new features delivered with DB2 UDB Version 8 DB2 JDBC Universal Driver has been designed to eliminate the dependency on DB2 CLI runtime modules as well as to enable direct Type 4 connectivity to DB2 UDB for iSeries and DB2 UDB for zOSreg

The pure-Java (Type 4) remote connectivity is based on the DRDA open distributed protocol for cross-platform access to DB2 DRDA defines the rules the protocols and the semantics for accessing distributed data Applications can access data in a distributed relational environment by using SQL statements The iSeries DRDA application server implementation is based on multiple connection-oriented server jobs running in the QSYSWRK subsystem A DRDA listener job (QRWTLSTN) listens for TCP connect requests on port 446 Once an application requester connects to the listener job the listener wakes up one of the QRWTSRVR prestart jobs and assigns it to a given client connection Any further communication occurs directly between the client application and the QRWTSRVR job These concepts are illustrated in Figure 10

19

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 10 Accessing DB2 UDB for iSeries with DB2 Universal Driver

The DB2 Universal Driver can be loaded in an AIX partition by installing one of the DB2 Connect for AIX products (see the Additional Information section for details) It is also a part of a DB2 Enterprise Server Edition for AIX install Specifically the developer needs three JAR files in a AIX partition to successfully connect to an iSeries server db2jccjar db2jcc_license_cisuzjar and db2jcc_license_cujar The iSeries license is contained in db2jcc_license_cisuzjar Note that this file is not a part of DB2 Client In other words a DB2 Connect license is required to use the driver in production environments The location of the JAR files needs to be added to the CLASSPATH environment variable For instance the following entry could be added to the AIX profile script

CLASSPATH=homedb2inst2sqllibjavadb2jccjarCLASSPATH=$CLASSPATHhomedb2inst2sqllibjavadb2jcc_license_cujarCLASSPATH=$CLASSPATHhomedb2inst2sqllibjavadb2jcc_license_cisuzjarexport CLASSPATH

Java Runtime 131 is a prerequisite

Additionally the developer should install the latest database group PTF (SF99503 for i5OS V5R3) on the iSeries server The Informational APAR ii13348 is keeping track of any fixes relevant to DRDA above and beyond the current database group PTF

Obtaining a Connection to DB2 UDB for iSeries When Type 4 connectivity is used the DB2 Universal Driver connects directly to the DB2 on iSeries through TCPIP Note that this is different from the legacy DB2 Type 2 JDBC driver that requires a DB2 node and remote database configurations on the client accessing iSeries The following code snippet illustrates how to use the DB2 JDBC Universal Driver to obtain a connection to DB2 UDB for iSeries

20

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

try ClassforName(comibmdb2jccDB2Driver) [1] catch(javalangClassNotFoundException e) Systemerrprint(ClassNotFoundException )Systemerrprintln(egetMessage())

try DriverManagergetConnection(jdbcdb2teraplex446TERAPLEX[2]

db2userdb2pwd) hellip catch(SQLException ex) Systemerrprintln(

SQLException + exgetMessage())

At [1] an instance of the DB2 JDBC Universal Driver is instantiated Then at [2] the driver is used to obtain a connection to the iSeries server Note the proper form of the database URL required by the driver

Considerations There are several advantages of DB2 JDBC Universal Driver bull Ease of cross-platform development mdash Consistent coding techniques and consistent error

codes and messages bull Ease of deployment mdash Pure Java (no runtime client required) and a single driver for accessing

DB2 on different platforms

The ease of use comes at a price though The iSeries JTOpen driver is optimized for accessing DB2 UDB for iSeries data and it uses native iSeries protocol to communicate with the back-end database server job This usually results in better performance and more-efficient system resources utilization For instance when using the DB2 JDBC Universal Driver to access an iSeries server the executeBatch method results in a single record insert There are also some restrictions when using DB2 Universal JDBC Driver with Type 4 connectivity

bull Support for distributed transactions (JTA) is not enabled bull Driver built-in connection pooling is not supported

Refer to Java application support in DB2 for more details on DB2 JDBC Universal Driver

21

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 Connect data access This section will explore the most important aspects of DB2 Connect ndash iSeries integration - including configuration tips and coding examples

DB2 Connect provides functionality for accessing data stored in DB2 UDB for iSeries as well as DB2 UDB for zOS and DB2 UDB for OS390reg DB2 Connect offers capabilities to access DB2 family members via several SQL interfaces gateway functions such as connection pooling and federated database functionality Many applications supporting the DB2 family of products leverage DB2 Connect as a key middleware component DB2 Connect is offered as separate AIX license products

Enterprise Edition Application Server Edition

In addition to DB2 Connect there are several other DB2 UDB Version 81 products that are supported on AIX

DB2 Universal Database Enterprise Server Edition DB2 Universal Database Workgroup Server Unlimited Edition DB2 Universal Database Workgroup Server Edition DB2 Universal Database Universal Developers Edition All Clients

The DB2 Connect Enterprise Edition functionality is also contained in DB2 Enterprise Server Edition for AIX

22

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 Connect in a nutshell In the scenario described in this paper the DB2 Connect functions contained in DB2 Enterprise Edition for AIX are utilized DB2 Connect Enterprise Edition provides support for both local and remote DB2 clients This is illustrated in Figure 11 Accessing DB2 UDB for iSeries with DB2 Connect

Figure 11 Accessing DB2 UDB for iSeries with DB2 Connect

DB2 Connect implements the Distributed Relational Database Architecturetrade (DRDAreg) to reduce the cost and complexity of accessing data stored in DB2 UDB for iSeries and other DRDA-compliant database servers DRDA defines the rules the protocols and the semantics for accessing distributed data Applications can access data in a distributed relational environment by using SQL statements In a distributed environment the system running the application and sending the SQL requests across the network is called the application requester (AR) A remote database server that executes SQL requests submitted by an application requester is known as the application server (AS) In the example shown in Figure 11 (above) DB2 Connect plays the role of an application requester while DB2 UDB for iSeries is an application server In this case DB2 Connect communicates with the iSeries database through TCPIP The iSeries DRDA application server implementation is based on multiple connection-oriented server jobs running in the QSYSWRK subsystem A DRDA listener job (QRWTLSTN) listens for TCP connect requests on port 446 Once an application requester connects to the listener job the listener wakes up one of the QRWTSRVR prestart jobs and assigns it to a given client connection Any further communication occurs directly between the client application and the QRWTSRVR job

DB2 Connect supports a wide range of programming interfaces that can be used by AIX applications to access the iSeries database Embedded SQL frac34 Both static and dynamic SQL frac34 Various programming languages (Java CC++ Cobol Fortran REXX)

DB2 Call Level Interface (DB2 CLI) ODBC JDBC frac34 DB2 JDBC Type 2 Driver frac34 DB2 JDBC Type 4 Driver (Universal JDBC Driver)

23

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Note that DB2 Connect supports access to DB2 UDB for iSeries through DB2 JDBC Universal driver However for performance and ease of maintenance reasons IBM recommends that Java applications running in AIX use native iSeries Toolbox JDBC driver See the JDBC Data Access section of this paper (above) for more details On the other hand DB2 Connect is a very efficient and robust connectivity option for AIX applications especially in the environments that are not directly supported by the native iSeries JDBC driver Here are several possible scenarios that would require DB2 Connect installed in a AIX partition

Embedded SQL interface is used to access DB2 CLI or ODBC interface is used to access DB2 A single SQL interface is needed to access multiple back end DB2 server Specific DB2 Connect functionality is needed such as distributed join or connection

pooling

Prerequisites One of the DB2 Connect products or DB2 Enterprise Server Edition for AIX V81 is needed Additionally DB2 Application Development Client is required in the AIX partition to compile DB2 applications

For maximum database server stability the developer should install the latest database group PTF (SF99503 for i5OS V5R3) on the iSeries server The Informational APAR ii13348 is keeping track of any fixes relevant to DRDA above and beyond the current database group PTF

DB2 Connect configuration The following example employs i5OS V5R3 and DB2 UDB Enterprise Server Edition for AIX Version 81 FixPak 6

Configuration steps in the iSeries partition The following process lists the necessary steps to be performed on the iSeries server 1) Verify that the TCPIP stack is working correctly It is assumed that the Virtual LAN is used to

communicate with the i5OS partition First obtain the IP address of the iSeries server or its hostname and ping the iSeries server from the AIX partition

2) Create a relational database (RDB) entry for the iSeries database in the i5OS partition If this has already been created it can be displayed by using the DSPRDBDIRE command Make sure that the RDB entry with a location of LOCAL exists on the iSeries server If it does not exist use the ADDRDBDIRE command to add the appropriate RDB entry For example the following command would add an RDB entry named TPLX For simplicity it is recommended that the TCPIP host name and RDB entry remain the same

ADDRDBDIRE RDB(TPLX) RMTLOCNAME(LOCAL)

3) Create a collection called NULLID This is necessary because the utilities shipped with DB2 Connect and DB2 UDB for AIX store their packages in the NULLID collection Since it does not exist by default in the iSeries server you must create it using the following command

CRTLIB LIB(NULLID)

4) Products that support DRDA automatically perform any necessary code page conversions at the receiving system For this to happen both systems need a translation table from their code page to the partner code page The default Coded Character Set Identifier (CCSID) on the iSeries server is 65535 Since DB2 Connect does not have a translation table for this code page the developer needs to change the individual user profiles to contain a CCSID that can be converted properly by DB2 Connect For US English this is 037 For other languages see DB2 Connect Personal Edition Quick Beginning GC09-2967 The following command changes the CCSID for an individual user profile to 037

24

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

CHGUSRPRF userid CCSID(037)

5) Verify that the default port 446 for DRDA service is being used To do this go to the Configure TCPIP menu (CFGTCP) select Configure Related Tables and then select Work with service table entries Verify that the DRDA service is set for port 446

6) The Distributed Data Management (DDM) job must be started for DRDA to work If you want the DDM job to be automatically started whenever TCPIP is started change the attributes of the DDM job using the CHGDDMTCPA command and set the Autostart server parameter to YES

7) If the system administrator chooses not to autostart the server issue the following command to start the DDM server job

STRTCPSVR SERVER(DDM)

8) Make sure that the user profiles that will be used to connect to the iSeries server exist on the server

25

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Configuration steps in the AIX partition The following steps are required for DB2 Connect to be configured in the AIX partition 1) Sign on to the AIX partition as the DB2 administrator 2) Launch Client Configuration Assistant (db2ca from the command prompt) It is assumed that

VNC or an X-Windows server are being used on the workstation so that the db2ca GUI can be properly rendered

3) From the Selected pull-down menu select the Add Database using Wizard option The Select how you want to setup a connection dialog appears Select Manually configure a connection to a database and click Next This is shown in Figure 12

Figure 12 Accessing DB2 UDB for iSeries with DB2 Connect

26

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

4) On the Select a communications protocol choose TCPIP and select The database physical resides on a host or OS400 system Then select the option Connect directly to the server as shown in Figure 13 Click Next

Figure 13 mdash Selecting communications protocol

27

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

5) On the TCPIP tab fill in the host name of the iSeries server The port number should be 446 This is shown in Figure 14 Click Next

Figure 14 mdash Specifying TCPIP communication parameters

28

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

6) On the Database tab fill in the Relational Database name Use the RDB entry name (specified in step 2) in the Configuration steps in the iSeries partition section as shown in Figure 15 Click Next

Figure 15 mdash Specifying the remote database

7) If you plan to use the ODBC applications select Register this database for ODBC as a system data source on the ODBC tab Click Next

29

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

8) On the Specify the node option dialog select OS400 from the Operating System pull-down menu This is shown in Figure 16 Click Finish

Figure 16 mdash Specifying the node options

30

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

9) The Test Connection dialog appears This allows the developer to verify that the connection works Select both CLI and JDBC check boxes You are also prompted for an iSeries user ID and password as shown in Figure 17

Figure 17 mdash Testing the connection

31

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

10) The successful connection to the database server is confirmed by the message box shown in Figure 18

Figure 18 mdash Test Connection results 11) At this time a newly configured database connection should appear in the main DB2

Configuration Assistant window It is recommended that the DB2 utilities are also bound to the iSeries database The bind process creates the necessary SQL packages on the remote database In the main Configuration Assistant window click the TPLX database entry and then select Selected-gtBindhellip

32

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

12) The Bind dialog appears Click Select All and then enter the connection information as shown in Figure 19 Click Bind The Results message box appears This allows the developer to monitor the progress of the binding process Watch for any error and warning messages

Figure 19 mdash Binding the DB2 utilities This concludes the DB2 Connect configuration steps

33

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Accessing DB2 UDB for iSeries from C embedded SQL

As mentioned earlier DB2 Connect allows developers to compile and run embedded SQL applications that access DB2 UDB for iSeries data This section covers implementation details for a C embedded SQL application called cursorsjsqc (see Appendix B for source code)

Prerequisites An embedded SQL application running in an AIX partition will use DB2 Connect services to access DB2 UDB for iSeries therefore the developer needs to make sure that all components listed in section Prerequisites on page 24 are installed The developer also needs to create a remote database connection as described in the DB2 Connect configuration section of this paper on page 24

Static SQL and SQL packages To successfully run against a DB2 UDB for iSeries database an embedded SQL application needs to be first precompiled and bound to the back-end database This process creates an SQL package on the target iSeries server The SQL package contains the access plan information for the SQL statements executed by the application The internal structure of the package as well as the method how its content is used by the SQL runtime to facilitate the access plan reuse is similar to the Extended Dynamic SQL support covered in detail in the Extended Dynamic SQL and Statement Caching section of this paper (on page 9) There are however important differences between the packages created by the extended dynamic SQL support and the packages created for embedded SQL DRDA client applications The extended dynamic SQL packages support dynamic SQL interfaces such as JDBC

that can submit ad hoc SQL statements at the run time The SQL runtime can prepare the dynamic statements and add them to the package On the other hand the DRDA packages are created at the precompile time and contain static SQL In order to add new statements to the package the application needs to be precompiled and rebound again

The extended dynamic SQL package can dynamically grow up to 500MB by allocating new space as required The DRDA packages since they are created at the precompile time have a fix size and do not grow over their life time

Simple embedded SQL application The application is based on a source code provided in the DB2 UDB samples directory typically to be found at homedb2inst1sqllibsamples The cursorsjsqc performs a join between STAFF and ORG tables located in DB2USER schema (library) on the TPLX database server (the source is provided at the end of this paper in Appendix B) The join statement retrieves the DEPTNAME column from ORG NAME column from STAFF and calculates the total compensation for an employee by adding SALARY and COMM columns in STAFF The results are sorted by department name and total compensation Here is the SELECT statement used by the application

SELECT deptname name salary + IFNULL(comm0) as compensationFROM org o staff sWHERE odeptnumb = sdeptORDER BY deptname compensation DESC

The application iterates through the selected records and prints out the data to the standard output device The sample DB2USER schema was created with the following SQL statements

db2 CONNECT TO tplx USER db2user USING mypassworddb2 CALL QSYSCREATE_SQL_SAMPLE(DB2USER)

34

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Make sure that the AIX partition is logged into with the DB2 admin user profile If the defaults were selected at the DB2 installation time this profile name is db2inst1 It is also assumed that DB2USER user exists on the iSeries server and that it has appropriate authority

There are several steps that are required to create an executable for the cursorsjsqc source code First the DB2 PRECOMPILE utility needs to be called The utility creates a bind file that is used to bind the required SQL package to the TPLX database It also converts embedded SQL statements into DB2 run-time API calls and produces a pure C source file that can be processed by an AIX C compiler

db2 CONNECT TO tplx USER db2user USING mypassworddb2 prep cursorsjsqc bindfile

Note that the connect statement is required only if the developer is not already connected to the database on an iSeries server Watch for any error or warning messages returned by the DB2 prep utility The prepare step should produce cursorsjbnd and cursorsjc files in the current directory Now the developer can invoke the bind utility to prepare the statements contained in the bind file and create the package on the target iSeries database server

db2 bind cursorsjbnd

It is assumed that Visual C++ 60 is installed and configured in the AIX partition Refer to the ldquoDeveloping and Porting C and C++ Applications on AIXrdquo redbook for more information on how to use the Visual C++ compiler httpibmcomredbooksabstractssg245674htmlOpen

Use the following commands to compile the C source generated by the precompile utility

xlc -I$INSTHOMEsqllibinclude ndashc cursorsjcxlc ndasho cursorsj cursorsjo -L$INSTHOMEsqlliblib ndashldb2

Run the program from the AIX prompt

cursorsj db2user mypassword

Distributed Join DB2 UDB Version 8 provides core federated server functionality A federated system consists of a DB2 UDB instance that operates as a federated server a database that acts as the federated database one or more data sources and clients (users and applications) that access the database and data sources Federated server permits objects stored in multiple databases to be accessed together in the same query For example a query can refer to a table that resides in DB2 UDB for iSeries and join it to a table stored in DB2 UDB for AIX Such a query would constitute so called distributed join The support for DB2 UDB for iSeries as a federated data source is provided by core federated server functionality directly implemented in DB2 UDB Enterprise Server Edition and DB2 UDB Connect Enterprise Edition All other DB2 UDB family members are also supported directly by core DB2 UDB federated server An additional software product DB2 Information Integratortrade is required to access non-DB2 UDB databases such as Oracle Sybase or Microsoftreg SQL Server Consult the following white papers for a detailed discussion on DB2 federated server support Heterogeneous data access for iSeries applications Version 2 httpibmcomserversenablesiteeducationiborecordhtmlhetdata Fundamentals of IBM DB2 Federated Server and Relational Connect httpwww7bsoftwareibmcomdmddlibrarytecharticle0206purnell0206purnellhtml

35

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Distributed Join Example In this section the steps that are required to configure DB2 UDB for iSeries as a federated data source will be illustrated Then the cursorsjsqc program will be ldquotweakedrdquo so that it executes a distributed join query that accesses data stored on an iSeries server and in the local DB2 UDB for AIX database It is assumed that the developer is familiar with the DB2 federated server concepts

Note Run the following commands from the Command Line Processor prompt Load the utility by executing the db2 command at the AIX prompt 1) First the local DB2 UDB for AIX instance needs to be enabled as a DB2 federated server

This is done by setting the database manager configuration parameter FEDERATED to YES

db2=gt update dbm cfg using FEDERATED YES

The database instance needs to be restarted for the change to take effect

NOTE A federated database is a regular database in a DB2 UDB instance that has the FEDERATED parameter enabled Therefore in this example the SAMPLE database that was created earlier is used as the federated database A new database can also be created using the CREATE DATABASE command

2) Connect to the federated database

db2=gt connect to sample

3) Use the CREATE WRAPPER statement to register a wrapper for the iSeries data source Wrappers are library routines that are used by the federated server to perform operations such as connecting to a data source and retrieving data from it The default wrapper name for DB2 UDB for iSeries is DRDA Here is the command to register the DRDA wrapper

db2=gt create wrapper drda

4) Use the CREATE SERVER statement to register a data source as a server within the federated database The server definition specifies the type and version of the data source and the wrapper used for communications with this data source For the DB2 UDB for iSeries data source the node and the database names are also needed The node and database name parameters have been configured for our TPLX database in the Configuration steps in the AIX partition section (on page 24) Use the following DB2 UDB command to lookup these parameter on the federated server

db2=gt list database directory

In this case the command produced the following output

Database alias = TPLX Database name = DCSE99E1 Node name = NDE9BF76 Database release level = a00 Comment = Directory entry type = Remote Authentication = SERVER Catalog database partition number = -1

36

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Note that the node name is set to NDE9BF76 The name was generated by the Configuration Administrator utility (db2ca)

Here is the command to register the TPLX database as a federated server

db2=gt create server tplx type db2400 version 530 wrapperdrda authorization db2user password mypassword options(nodeNDE9BF76 dbname TPLX)

The command is quite complex so make sure that the syntax is correct

5) Define the user mappings that instructs the federated server what user ID and password should be used when connecting to the iSeries data source

db2=gt create user mapping for user server tplxoptions(remote_authid db2user remote_password mypassword)

Specify the nickname for the iSeries table or view A nickname is an identifier that is used by the federated server to reference an object located at the data source The following command creates a nickname for the STAFF table located in the DB2USER schema on the TPLX database

db2=gt create nickname tplx_staff for tplxdb2userstaff

6) Test the distributed join query

db2=gt SELECT deptname name salary + COALESCE(comm0) ascompensation FROM org o tplx_staff s WHERE odeptnumb =sdept ORDER BY deptname compensation DESC

Note that the native iSeries function IFNULL has been substituted with an equivalent DB2 UDB function COALESCE COALESCE is also supported on iSeries servers For better portability IBM encourages the use of COALESCE rather than IFNULL Note also that the query runs on the federated server rather than on TPLX It accesses the ORG table in the local DB2 UDB for AIX SAMPLE database and the STAFF table that resides in TPLX The federated server performs the necessary distributed join

7) Modify the cursorsjsqc so that it executes a distributed join There are two source code modifications - Change the CONNECT TO statements Now the application needs to connect to the

federated database SAMPLE rather than to TPLX

EXEC SQL CONNECT TO SAMPLEEXEC SQL CONNECT TO SAMPLE USER userid USING passwd

- Modify the select statement so that it performs a distributed join Use the statement (shown in step 6) above Save the new source version as cursordjsqc

- Prepare bind and compile the distributed join version of the program as described in the Simple C embedded SQL application section (on page 34)

db2 prep cursordjsqc bindfiledb2 bind cursordjbndxlc -I$INSTHOMEsqllibinclude ndashc cursordjcxlc ndasho cursordj cursordjo -L$INSTHOMEsqlliblib ndashldb2

37

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

- Run the program from the AIX prompt

cursordj

Connection Pooling and Connection ConcentratorA modern Web-based application typically executes a large number of short-lived transactions Executing a transaction in this environment means establishing a database connection executing a few SQL statements and terminating this connection Creating connections to the database server is a very costly process To reduce the unnecessary workload DB2 Connect implements connection pooling and connection concentrator Connection pooling mechanism allows DB2 Connect to reuse an existing connection infrastructure for subsequent connection requests The connection concentrator is an advanced technology that allows DB2 Connect to serve a potentially very large number of clients with a limited number of database connections This is accomplished by decoupling clients from a particular database connection

Note that currently neither connection pooling nor connection concentrator support DB2 UDB for iSeries Therefore for performance reasons the author strongly recommends that the application server that obtains and drops connections very frequently implements its own database connection pooling mechanism that would assign an existing pooled database connection to a new AIX process or thread

TroubleshootingTroubleshooting a multi-tier application may be a bit tricky because the developer needs to deal with software components that reside in separate partitions The authorrsquos experience shows that two tools are particularly useful for pinning down the potential problem areas The joblog messages for a database server job usually provide enough details to isolate DB2

UDB for iSeries runtime issues The DRDA trace utility provides granular information about the data flow between the AIX

application and the iSeries server job

38

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Job Log MessagesAs mentioned earlier a DB2 client communicates with a corresponding iSeries server job This server job runs the SQL requests on behalf of the client More precisely when a DB2 client submits an SQL statement the statement is passed to a server job that in turn calls the DB2 runtime to execute the statement The results are then reformatted and marshaled to the client The iSeries DRDA server jobs are called QRWTSRVR and they run in the QUSRWRK subsystem At any given time there may be a large number of DRDA server jobs active on the system so the first step is to identify the job that serves the particular client connection The easiest method to accomplish this task is to run the following CL command from the i5OS prompt

WRKOBJLCK OBJ(DB2USER) OBJTYPE(USRPRF)

Here DB2USER is the user profile that is used to connect to the iSeries server Note that a QRWTSRVR job is assigned to a client after the connection has been established so the developer needs to set a breakpoint in the client application below the CONNECT TO statement

Once the Work with Object Locks appears key in 5 (Work with Job) next to the only QRWTSRVR job that should be listed This shows the Work with Job dialog Select option 10 to display the job log for the database server job Now the developer can search the job log for any error messages generated by the DB2 runtime

Sometimes it is also useful to include debug messages in the job log The debug messages are informational messages written to the job log about the implementation of a query They describe query implementation methods such as use of indexes join order ODP implementation (reusable versus non-reusable) and so on The easiest way to instruct the iSeries server to include the debug messages is to call the following stored procedure just after the connection to the iSeries server is established

EXEC SQL call qsysqcmdexc(STRDBGUPDPROD(YES)000000002000000)

A sample of the job log messages with debug messages enabled is shown below in Figure 20

Arrival sequence access was used for file STAFFAccess path suggestion for file STAFFQuery options used to build the OS400 query access plan Ending debug message for query ODP created Blocking used for queryCursor SQLCUR201 opened1 rows fetched from cursor SQLCUR201Row not found for SQLCUR201ODP deleted Cursor SQLCUR201 closedDESCRIBE of prepared statement STMT0201 completed

Figure 20 mdash Joblog with debug messages enabled

So the job log offers fairly detailed information on how the AIX client requests were implemented by the DB2 runtime

39

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 DRDA trace utilityThe DB2 DRDA trace utility (db2drdat) provides detailed information about the data streams exchanged between DB2 Connect and target database server The output file produced by the utility contains send and receive communications buffers TCPIP error messages and SQL Communications Area (SQLCA) information Please refer to lsquoDB2 Connect Userrsquos Guidersquo manual for in-depth discussion of the DRDA trace utility

Accessing DB2 UDB for iSeries from CLI DB2 Call Level Interface (CLI ) is based on the Microsoft Open Database Connectivity (ODBC) specification and the ISO CLI standard The DB2 CLI interface gained popularity among DB2 application providers because the developer can build an ODBC application by simply linking the application with libdb2 library on a UNIX server In other words the developer directly utilizes the DB2 ODBC driver services without a need for an ODBC driver manager Additionally in contrast to embedded SQL the developer does not need to precompile or bind DB2 CLI applications because they use packages provided with DB2 UDB The developer simply compiles and links the application

Prerequisites A DB2 CLI application running in an AIX partition will use DB2 Connect services to access DB2 UDB for iSeries therefore make sure that all components listed in Prerequisites section of this paper on page 24 are installed The developer also needs to create a remote database connection as described in the DB2 Connect configuration section of this paper on page 24

Dynamic SQL and Access Plan Caching A DB2 CLI client application uses the dynamic SQL interface and does not have the capability to utilize the extended dynamic SQL support Therefore it runs lsquopurersquo dynamic SQL statements That does not mean however that the process of parsing validating and optimizing will be repeated for every execution of a given dynamic SQL statement

The DB2 UDB for iSeries database implements an internal object called System-Wide SQL Statement Cache (SWSC) The SWSC can improve the performance of programs using dynamic SQL statements by caching the access plans in a system-wide cache When a dynamic SQL statement is submitted the SQL runtime searches the SWSC to see if this statement has been previously executed If so then DB2 retrieves and reuses the key information associated with the cached statement and thereby the processing time and the resources utilization can be significantly reduced

Simple DB2 CLI C++ ApplicationThis section covers DB2 CLI implementation details for a sample C++ program called testclicpp (the source is provided at the end of this paper in Appendix C) To compile the source with Visual C++ complier use the following command in the AIX partition

xlC ndashI$INSTHOMEsqllibinclude ndashc testclicppxlC ndasho testcli testclio ndashL$INSTHOMEsqlliblib ndashldb2

The application performs a join between STAFF and ORG tables located in DB2USER schema (library) The join statement retrieves the DEPTNAME column from ORG NAME and JOB columns from STAFF and calculates the total compensation for an employee by adding SALARY and COMM columns in STAFF The results are sorted by total compensation The selection criterion is based on the current value of the department name parameter Here is the SELECT statement used by testcli

40

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

select name job salary + coalesce(comm0) as compensationfrom org o staff swhere odeptnumb = sdeptand deptname = order by compensation desc

Figure 21 shows the software components involved in the execution of this sample application

Figure 21 How a DB2 CLI client accesses DB2 UDB on an iSeries server

Although the testcli application is fairly simple it covers some important aspects of efficient CLI programming for DB2 UDB for iSeries

Reusable Open Data Paths (ODPs)An Open Data Path (ODP) definition is an internal i5OS object that is created when certain SQL statements (such as OPEN INSERT UPDATE and DELETE) are executed for the first time in a given job (or connection) The ODP can be thought of as a runtime implementation of an access plan The access plan created at the optimization time provides a recipe or in other words a sequence of steps necessary to execute the statement The ODP on the other hand provides the executable code for all requested IO operations The process of creating new ODP objects is fairly CPU- and IO-intensive so whenever possible the iSeries DB2 runtime tries to reuse existing ODPs For instance a SQLCloseCursor() API call may close the SQL cursor but leave the ODP available to be used the next time the cursor is opened This can significantly reduce the processing and response time in running SQL statements A reusable OPD usually requires 10 to 20 times less CPU resources than a newly created ODP Therefore it is important that the applications employ programming techniques that allow the DB2 runtime to reuse ODPs

With dynamic interfaces such as CLI full opens are avoided by using a prepare once execute many programming paradigm It means that when an SQL statement is going to be executed more than once you should prepare the statement just once and then reuse the prepared

41

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

statements for consecutive executions Although DB2 UDB does try to convert literals to parameter markers so that similar statements can be reused it is a better programming practice to explicitly implement parameter markers That way the chances for reusable ODPs are quite significantly improved The code snippet in Figure 22 illustrates how to implement the prepare once execute many programming technique

Define A SELECT SQL Statementstrcpy((char ) SQLStmt select name job salary + ifnull(comm0) ascompensation )ptr = strcat( (char ) SQLStmt from org o staff s )ptr = strcat( (char ) SQLStmt where odeptnumb = sdept)ptr = strcat( (char ) SQLStmt and deptname = )ptr = strcat( (char ) SQLStmt order by compensation desc) [1]

Prepare The SQL Statementrc = SQLPrepare(ExampleStmtHandle SQLStmt SQL_NTS) [2]

Bind The Columns In The Result Data Set Returned To Application Variablesrc = SQLBindCol(ExampleStmtHandle 1 SQL_C_CHAR (SQLPOINTER)

ExampleName sizeof(ExampleName) NULL)rc = SQLBindCol(ExampleStmtHandle 2 SQL_C_CHAR (SQLPOINTER)

ExampleJob sizeof(ExampleJob) NULL)rc = SQLBindCol(ExampleStmtHandle 3 SQL_C_DOUBLE (SQLPOINTER)

ampExampleComp sizeof(ExampleComp) NULL)

for (int i = 0 i lt LOOPS i++)rc=SQLBindParameter(ExampleStmtHandle

1SQL_PARAM_INPUTSQL_C_CHARSQL_CHAR10(SQLPOINTER) currentDepartment[i8]0NULL) [3]

rc = SQLExecute(ExampleStmtHandle) [4]cout ltlt endl ltlt Current Dept ltlt currentDepartment[i8] ltlt endl Display The Results Of The SQL QueryExampleShowResults()

Figure 22 Use the prepare once execute many programming technique

The error-handling code has been removed for clarity At [1] the statement text is assigned to a variable Note that a parameter marker is used in the WHERE clause The statement is then prepared just once at [2] The current value of the parameter is bound to the prepared statement at [3] The prepared statement is executed at [4] Steps [3] and [4] are repeatedly executed in a for loop

Techniques to Further Improve DB2 CLI Performance Thus far this paper has discussed the techniques used by a sample application to tune the CLI performance However depending on the application architecture other methods of improving CLI performance may be considered

Connection PoolingCurrently the CLI application connecting through DB2 Connect to DB2 UDB for iSeries does not take advantage of the connection pooling mechanism implemented by DB2 Connect Therefore for performance reasons the author strongly recommends that the application server that obtains and drops connections very frequently implements its own database connection pooling mechanism that would assign an existing pooled database connection to a new AIX process or thread

42

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Blocking

For queries which result in returning large data blocks from the iSeries server (usually 32K of data and above) ensure that the database manager configuration parameter RQRIOBLK is set to 32767 This can be done using the Command Line Processor (CLP) as follows

db2 update database manager configuration using RQRIOBLK 32767

TroubleshootingThe experience of the author shows that two tools are particularly useful for pinning down the potential problem areas bull Joblog messages for a database server job usually provides enough details to isolate DB2

runtime issues bull CLI trace utility provides granular information about the data flow between the AIX application

and the database server job

Job Log MessagesThe process of finding and analyzing the job log for a DB2 CLI connection is identical to the process outlined for an embedded SQL application in the Job Log Message section of this paper on page 39

CLI Trace The DB2 CLIODBCJDBC trace utility provides very detailed information about the data streams exchanged between DB2 Connect and target database server Refer to the DB2 Information Center for more information on how to set up and analyze the CLI traces httppublibboulderibmcominfocenterdb2v8luwindexjsptopic=comibmdb2udbdocadc000 7959htm

43

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Trademarks

IBM eServer iSeries AIX AIX 5L i5OS WebSphere DB2 DB2 Universal Database DB2 Connect OS400 zOS OS390 Distributed Relational Database Architecture DRDA and DB2 Information Integration are trademarks or registered trademarks of International Business Machines Corporation in the United States and other countries

Java and all Java-based trademarks are trademarks of Sun Microsystems Inc in the United States other countries or both

Linux is a registered trademark of Linus Torvalds in the United States other countries or both

UNIX is a registered trademark of The Open Group in the United States and other countries

Microsoft and Windows are registered trademarks of Microsoft Corporation in the United States andor other countries

All other registered trademarks and trademarks are properties of their respective owners

IBM makes no commitment to make available any products referred to herein

References in this publication to IBM products or services do not imply that IBM intends to make them available in every country in which IBM operates

Additional Information ITSO offers a Redbook that can be helpful to those who want to learn more about i5OS AIX integration

bull AIX Integration with I5OS on the IBM eServer iSeries Server (SG24-6551)

Jarek Miszczyk is the Senior Software Engineer IBM eServer Solutions Enablement IBM Rochester

[Portions of this white paper reprinted with permission from MC Mag Online published by MC Press LLP httpwwwmcpressonlinecom]

Acknowledgments The author would like to thank the following people for their advice contributions and support on this paper

Bob Bittner IBM Rochester Jon Rush IBM Rochester Prasad Vallurupalli IBM Rochester Neil Willis IBM Rochester

44

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix A Source Listing of TestJDBCjava

package comibmiseriespwdimport javasqlimport javaxnamingimport javautilHashtableimport javautilimport javaxsqlimport comibmas400access

public class TestJDBC public static void main(javalangString[] args)

throws Exception

int numOfLoops = 5000int outerNumOfLoops = 5boolean firstExec = trueConnection conStatement sPreparedStatement psPreparedStatement pstmtdelCallableStatement cstmPreparedStatement pstmtHashtable env = new Hashtable()

envput(ContextINITIAL_CONTEXT_FACTORYcomsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env)Systemoutprintln(Deploying connection pooling data source)deployDataSource() Do the work with connection pooling onlyAS400JDBCConnectionPoolDataSource tkcpds =

(AS400JDBCConnectionPoolDataSource)ctxlookup(jdbcToolkitDataSource) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPool pool = new AS400JDBCConnectionPool(tkcpds) Adds 1 connection to the pool that can be used by theapplication (creates the physical database connections based onthe data source)poolfill(1)Systemoutprintln(nStart timing Toolkit connection pooling)long startTime = SystemcurrentTimeMillis()

for (int i = 0 i lt outerNumOfLoops i++) con = poolgetConnection()consetAutoCommit(false) deleteif ( i == 0)

long startDelete = SystemcurrentTimeMillis()cstm = cstm = conprepareCall(

CALL qsysqcmdexc(CLRPFM FILE(DB2USERCOFFEES) + 000000002800000))

cstmexecuteUpdate()cstmclose()long endDelete = SystemcurrentTimeMillis()Systemoutprintln(Delete all records +

(endDelete - startDelete) + ms elapsed)

45

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

String sqlinstrlong startInsert = SystemcurrentTimeMillis() insert

pstmt =conprepareStatement(INSERT INTO COFFEES VALUES( ))for (int j = 0 j lt numOfLoops j++) pstmtsetString(1 Kona_ + IntegertoString(i))pstmtsetInt(2 150)pstmtsetFloat(3 999f)pstmtsetInt(4 0)pstmtsetInt(5 0)pstmtaddBatch()int [] updateCounts = pstmtexecuteBatch()concommit()pstmtclose()long endInsert = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for + numOfLoops + inserts

+ (endInsert - startInsert)) selectlong startSelect = SystemcurrentTimeMillis()ps = conprepareStatement(SELECT FROM COFFEES)ResultSet rs = psexecuteQuery()rsnext()rsclose()concommit()psclose()long endSelect = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for select +

(endSelect - startSelect))consetAutoCommit(true)conclose()long endTime = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for + outerNumOfLoops +

loops + (endTime - startTime))Systemexit(0)

private static void deployDataSource()throws ExceptionString serverName = teraplex String databaseName = TERAPLEX String userName = db2user String password = db2pwd

Establish a JNDI context and bind the connection pool data sourceHashtable env = new Hashtable()envput(ContextINITIAL_CONTEXT_FACTORY

comsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPoolDataSource tkcpds = new

AS400JDBCConnectionPoolDataSource()tkcpdssetServerName(serverName) tkcpdssetDatabaseName(databaseName) tkcpdssetUser(userName) tkcpdssetPassword(password) tkcpdssetDescription(Toolkit Connection Pooling DataSource)tkcpdssetSavePasswordWhenSerialized(true)tkcpdssetExtendedDynamic(true)

46

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

tkcpdssetPackage(JDBCDS)tkcpdssetPackageCache(true)tkcpdssetPackageCriteria(select)enable the following properties as requiredcpdssetTrace(true)tkcpdssetServerTraceCategories( AS400JDBCDataSourceSERVER_TRACE_DEBUG_SERVER_JOB)

ctxrebind(jdbcToolkitDataSource tkcpds)

47

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix B mdash Source Listing of cursorsjsqc

Source File Name = cursorsjsqc Licensed Materials - Property of IBM (C) COPYRIGHT International Business Machines Corp 1995 2000 2004 All Rights Reserved US Government Users Restricted Rights - Use duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp PURPOSE This sample program demonstrates the use of a CURSOR The CURSOR is processed using static SQL EXTERNAL DEPENDENCIES - Ensure existence of database for precompile purposes - Precompile with the SQL precompiler (PREP in DB2) - Bind to a database (BIND in DB2) - Compile and link with the IBM Cset++ compiler (AIX and OS2) or the Microsoft Visual C++ compiler (Windows) or the compiler supported on your platform For more information about these samples see the README file For more information on programming in C see the - Programming in C and C++ section of the Application Development Guide For more information on building C applications see the - Building C Applications section of the Application Building Guide For more information on the SQL language see the SQL Reference

include ltstdiohgt include ltstdlibhgt include ltstringhgtinclude ltsqlhgtinclude ltsqlenvhgtinclude ltsqldahgtinclude ltsqlcahgt

int SqlInfoPrint( char struct sqlca int char )void TransRollback( void)

define EMB_SQL_CHECK( MSG_STR ) rc = SqlInfoPrint( MSG_STR ampsqlca __LINE__ __FILE__) if ( rc = 0 ) TransRollback( )

return 1

EXEC SQL INCLUDE SQLCA

int main(int argc char argv[])

EXEC SQL BEGIN DECLARE SECTIONchar dname[15]

48

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

char pname[10]double compchar userid[9]char passwd[19]

EXEC SQL END DECLARE SECTION

int rc = 0printf( Sample C program CURSORSJ n )if (argc == 1)

EXEC SQL CONNECT TO TPLXEMB_SQL_CHECK(CONNECT TO TPLX)

else if (argc == 3)

strcpy (userid argv[1])strcpy (passwd argv[2])EXEC SQL CONNECT TO TPLX USER userid USING passwdEMB_SQL_CHECK(CONNECT TO TPLX)

else

printf (nUSAGE cursor [userid passwd]nn)return 1

endif

EXEC SQL DECLARE c1 CURSOR FORselect deptname name salary + ifnull(comm0) as compensationfrom org o staff swhere odeptnumb = sdeptorder by deptname compensation desc

EXEC SQL OPEN c1EMB_SQL_CHECK(OPEN CURSOR)

printf(DEPARTMENT NAME COMPENSn)printf(-----------------------------------n)do

EXEC SQL FETCH c1 INTO dname pname compif (SQLCODE = 0) breakprintf( -1515s -1010s 72fn dname pname comp )

while ( 1 )

EXEC SQL CLOSE c1EMB_SQL_CHECK(CLOSE CURSOR)

EXEC SQL CONNECT RESETEMB_SQL_CHECK(CONNECT RESET)

exit(0)

end of program CURSORSJSQC

int SqlInfoPrint( char appMsgstruct sqlca pSqlcaint linechar file )

int rc = 0char sqlInfo[1024]char sqlInfoToken[1024]char sqlstateMsg[1024]char errorMsg[1024]

if (pSqlca-gtsqlcode = 0 ampamp pSqlca-gtsqlcode = 100)

49

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

strcpy(sqlInfo )if( pSqlca-gtsqlcode lt 0) sprintf( sqlInfoToken n---- error report ----n)

strcat( sqlInfo sqlInfoToken)else sprintf( sqlInfoToken n---- warning report ----n)

strcat( sqlInfo sqlInfoToken) endif

sprintf( sqlInfoToken app message = sn appMsg)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken line = dn line)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken file = sn file)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken SQLCODE = ldn pSqlca-gtsqlcode)strcat( sqlInfo sqlInfoToken)

get error message rc = sqlaintp( errorMsg 1024 80 pSqlca) return code is the length of the errorMsg string if( rc gt 0) sprintf( sqlInfoToken sn errorMsg)

strcat( sqlInfo sqlInfoToken)

get SQLSTATE message rc = sqlogstt( sqlstateMsg 1024 80 pSqlca-gtsqlstate)if (rc == 0) sprintf( sqlInfoToken sn sqlstateMsg)

strcat( sqlInfo sqlInfoToken)

if( pSqlca-gtsqlcode lt 0) sprintf( sqlInfoToken --- end error report ---n)

strcat( sqlInfo sqlInfoToken)printf(s sqlInfo)return 1

else sprintf( sqlInfoToken --- end warning report ---n)

strcat( sqlInfo sqlInfoToken)printf(s sqlInfo)return 0

endif endif

return 0

void TransRollback( ) struct sqlca sqlca

int rc = 0 rollback the transaction printf( nRolling back the transaction n)

EXEC SQL ROLLBACKrc = SqlInfoPrint( ROLLBACK ampsqlca __LINE__ __FILE__)if( rc == 0) printf( The transaction was rolled backn)

50

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

51

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix C mdash Source Listing of testclicpp

Include The Appropriate Header Filesinclude ltsqlclihgtinclude ltsqlcli1hgtinclude ltsqlutilhgtinclude ltsqlenvhgtinclude ltstdiohgt include ltiostreamgt include ltlocalehgt include ltstringhgtdefine SQL_SQLSTATE_SIZE 5define LOOPS 8

using namespace std

Define The CLI_Class Classclass CLI_Class

Attributespublic

SQLHANDLE EnvHandleSQLHANDLE ConHandleSQLHANDLE StmtHandleSQLRETURN rcSQLCHAR Job[6]SQLCHAR Name[10]SQLDOUBLE Comp

Operationspublic

CLI_Class()~CLI_Class()SQLRETURN ShowResults()

Constructor Destructor

SQLRETURN printError( SQLHDBC SQLHSTMT)

Define The Class ConstructorCLI_ClassCLI_Class()

setlocale( LC_ALL )

Initialize The Return Code Variablerc = SQL_SUCCESS

Allocate An Environment Handlerc = SQLAllocHandle(SQL_HANDLE_ENV SQL_NULL_HANDLE ampEnvHandle)

Allocate A Connection Handleif (rc == SQL_SUCCESS)

rc = SQLAllocHandle(SQL_HANDLE_DBC EnvHandle ampConHandle)

Define The Class DestructorCLI_Class~CLI_Class()

Free The Connection Handleif (ConHandle = NULL)

SQLFreeHandle(SQL_HANDLE_DBC ConHandle)

Free The Environment Handle

52

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

if (EnvHandle = NULL)SQLFreeHandle(SQL_HANDLE_ENV EnvHandle)

Define The ShowResults() Member FunctionSQLRETURN CLI_ClassShowResults(void)

While There Are Records In The Result Data Set Generated Retrieve And Display Themcout ltlt Name Job Compensation ltlt endlcout ltlt --------- ------ ------------ ltlt endlcoutsetf(iosleft)coutprecision(2)coutsetf(iosfixed)while (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)

rc = SQLFetch(StmtHandle)if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)

coutwidth(15)cout ltlt Name

coutwidth(10)cout ltlt Job

coutwidth(7)cout ltlt Comp ltltendl

if(rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO ampamp rc = SQL_NO_DATA)printError(ConHandle StmtHandle)

else

rc = 0SQLCloseCursor(StmtHandle)

Return The ODBC API Return Code To The Calling Functionreturn(rc)

SQLRETURN CLI_ClassprintError (SQLHDBC hdbc

SQLHSTMT hstmt)

SQLCHAR buffer[SQL_MAX_MESSAGE_LENGTH + 1]SQLCHAR sqlstate[SQL_SQLSTATE_SIZE + 1]SQLINTEGER sqlcodeSQLSMALLINT lengthSQLRETURN rcwhile ((rc = SQLError(SQL_NULL_HENV hdbc hstmt

sqlstateampsqlcodebufferSQL_MAX_MESSAGE_LENGTH + 1amplength)) == SQL_SUCCESS || rc ==

SQL_SUCCESS_WITH_INFO)

cout ltlt SQLSTATE ltlt sqlstate ltlt endlcout ltlt SQLCODE ltlt sqlcode ltlt endlcout ltlt Error msg ltlt buffer ltlt endl

53

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

cout ltlt----------------------------- ltlt endl ltlt endl

return(SQL_ERROR)

----------------------------------------------------------------- The Main Function -----------------------------------------------------------------int main()

Declare The Local Memory Variables

(SQLCHAR ) db2user SQL_NTS (SQLCHAR ) test26t SQL_NTS)

SQLRETURNSQLCHARSQLCHARSQLCHARchar

SQLCHAR

rc = SQL_SUCCESSDBName[10] = TPLXSQLStmt[255]c[10]ptrcurrentDepartment[8][15] = Head Office

New England Mid Atlantic South Atlantic Great Lakes PlainsPacificMountain

Create An Instance Of The CLI_Class ClassCLI_Class Example

Connect To iSeries Database if (ExampleConHandle = NULL)

rc = SQLConnect(ExampleConHandle DBName SQL_NTS

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)ExampleprintError(ExampleConHandle SQL_NULL_HSTMT)

return(rc)

cout ltlt Successfully connected to ltlt DBName ltlt ltlt endlrc = SQLSetConnectAttr(ExampleConHandle SQL_ATTR_AUTOCOMMIT

(SQLPOINTER) SQL_AUTOCOMMIT_OFF SQL_IS_UINTEGER) Allocate An SQL Statement Handlerc = SQLAllocHandle(SQL_HANDLE_STMT ExampleConHandle

ampExampleStmtHandle)if (rc == SQL_SUCCESS)

Define A SELECT SQL Statement

strcpy((char ) SQLStmt select name job salary + ifnull(comm0) ascompensation )

ptr = strcat( (char ) SQLStmt from org o staff s )ptr = strcat( (char ) SQLStmt where odeptnumb = sdept)ptr = strcat( (char ) SQLStmt and deptname = )ptr = strcat( (char ) SQLStmt order by compensation desc)

Prepare The SQL Statementrc = SQLPrepare(ExampleStmtHandle SQLStmt SQL_NTS)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)ExampleprintError(ExampleConHandle ExampleStmtHandle)

54

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

return(rc)

Bind The Columns In The Result Data Set Returned To Application Variables

rc = SQLBindCol(ExampleStmtHandle 1 SQL_C_CHAR (SQLPOINTER)ExampleName sizeof(ExampleName) NULL)

rc = SQLBindCol(ExampleStmtHandle 2 SQL_C_CHAR (SQLPOINTER)ExampleJob sizeof(ExampleJob) NULL)

rc = SQLBindCol(ExampleStmtHandle 3 SQL_C_DOUBLE (SQLPOINTER)ampExampleComp sizeof(ExampleComp) NULL)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO) ExampleprintError(ExampleConHandle ExampleStmtHandle)

return(rc)

while (true)

for (int i = 0 i lt LOOPS i++)

rc=SQLBindParameter(ExampleStmtHandle1SQL_PARAM_INPUTSQL_C_CHARSQL_CHAR

150(SQLPOINTER) currentDepartment[i8]0NULL)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)

ExampleprintError(ExampleConHandle ExampleStmtHandle)return(rc)

rc = SQLExecute(ExampleStmtHandle)if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)

ExampleprintError(ExampleConHandle ExampleStmtHandle)return(rc)

cout ltlt endl ltlt Current Dept ltlt currentDepartment[i8] ltlt

endl Display The Results Of The SQL QueryExampleShowResults()if(rc = 0)break

if ( i500 == 0 ampamp i gt 0 )cout ltlt Loops ltlt i ltlt ltlt endl

cout ltlt AFTER ltlt LOOPS ltlt loops Press X to exit ltlt endlcin gtgt cif (c[0] == x || c[0] == X)

break

Free The SQL Statement Handleif (ExampleStmtHandle = NULL )

SQLFreeHandle(SQL_HANDLE_STMT ExampleStmtHandle) Disconnect From The Northwind Sample Databaserc = SQLDisconnect(ExampleConHandle)

Return To The Operating Systemreturn(rc)

55

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

WebSphere Considerations In certain situations an application provider may decide to deploy WebSphere Application Server in an AIX partition rather than natively in i5OS At the same time the application uses DB2 UDB for iSeries as an back-end database server Typically the WebSphere Application Server running in the AIX partition uses the virtual LAN to communicate with DB2 UDB for iSeries The WebSphere applications will access the database through a remote JDBC connection For performance and functionality reasons IBM recommends to utilize in such environments the IBM Toolbox for Java JTOpen driver Most of the tips and techniques described so far in this document hold true for WebSphere applications accessing DB2 UDB for iSeries There are however certain JDBC access aspects that are specific to this multi-tier architecture Letrsquos have a closer look at some of these considerations

Connection Pooling and Statement Caching

WebSphere Application Server provides its own connection pooling and statement caching mechanism that is by default enabled so that WebSphere applications automatically enjoy the performance benefits of these two critical programming techniques See the following link to learn more about the optimal connection pool setting in WebSphere

httppublibboulderibmcomwas40051englishinforzaiz51adminhelpudat_conpoolsethtml

Extended Dynamic SQL

For non-JTA connections WebSphere Application Server uses the comibmas400accessAS400JDBCConnectionPoolDataSource class as the iSeries JDBC provider implementation This is the DataSource implementation that has been used in all previous coding examples As mentioned the class supports a range of iSeries specific properties that can be used to fine tune JDBC performance These properties can be set through the WebSphere Application Server admin console For example herersquos the procedure to enable the extended dynamic SQL support In the WebSphere Application Server admin console navigate to the Data Source configuration dialog by selecting JDBC Providers -gt iSeriesToolbox -gt Data Sources then scroll down to the Additional Properties section Select Custom Properties link The Custom Properties dialog opens Scroll down to find the Extended Dynamic property and select it Change the default value false to true save the new configuration by clicking Apply button This is illustrated in Figure 5

12

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 5 Enabling the extended dynamic SQL through WebSphere Application Server console

The WebSphere Application Server needs to be restarted for the change to take effect The similar procedure can be followed to set other iSeries Data Source properties

Changing the WebSphere Application Server default isolation level

WebSphere Application Server V5 uses the REPEATABLE_READ (RR) isolation level for all implicit (WebSphere Application Server managed) transactions With the RR isolation level the rows selected updated deleted and inserted are locked until the end of the transaction Under certain circumstances this fairly extensive locking policy may cause locking contention especially when a WebSphere application competes for database resources with other applications that run on iSeries server For example a legacy order entry application may share data with the e-business customer care application running in WebSphere The locking contention may sometimes be eliminated by lowering the isolation level used by WebSphere Although the iSeries Data Source supports the custom transactionIsolation property resetting this property on the Data Source object will not change the default isolation level used by WebSphere for the connection objects produced by that Data Source In other words WebSphere will override the Data Source isolation level setting at the time the connection is obtained by a WebSphere application object such as servlet or Enterprise Java Bean (EJB) In order to change the default WebSphere behavior one must use the resource referencing Resource referencing allows a programmer to lookup DataSource or EJB objects using alias names rather than JNDI names Additionally by creating a resource reference a programmer can change certain properties of the underlying object Specifically a DataSource reference can be used to set a different isolation level for the connections produced by this database resource Typically resource references are defined by a programmer in a application development tool such as WebSphere Studio Application Developer The method to specify a DataSource reference differs depending on whether a programmer plans to use the reference in a servlet or in an EJB Letrsquos start with outlining the configuration process for a servlet In WebSphere Studio Application Developer open the deployment descriptor editor for the web project that contains the servlet To do so double click on the webxml file under WEB-INF directory in the web project In the deployment editor dialog select the References tab and then select Resource tab located in the top of the dialog that appears Under Resource References section select the Add button Herersquos an example of a DataSource reference created for iSeries DataSource named TestJDBCDS Note that the reference changes the default isolation level to READ_COMMITTED

13

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 6 Defining a resource reference for a servlet

Once the resource reference has been defined and saved the servlet source code needs to be changed to reflect the fact that a resource reference is used to obtain a DataSource from the JNDI service Herersquos the relevant code snippet try

ctx = new InitialContext() ds = (DataSource)ctxlookup(javacompenvTestJDBCJ2C)

catch (Exception e) eprintStackTrace(out)

Now the ds DataSource object will produce connections that by default run with the isolation level of READ_COMMITTED (RC)

As mentioned the process of defining a resource reference for an EJB differs from the process that is used in the case of a servlet In WebSphere Studio Application Developer open the deployment descriptor editor for the EJB project that contains the EJB To do so double click on the ejb-jarxml file under WEB-INF directory in the project In the deployment editor dialog select the References tab In the references section on the left locate and select the EJB for which the developer wants to change the default isolation level Click the Add button The Add Reference dialog opens Click the Resource Reference radio button and then Next Define the reference following the example shown in Figure 7

14

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 7 Adding a resource reference for an EJB

When you click ldquoFinishrdquo the reference definition is added to the EJB descriptor The new definition needs to be further modified To do so click on the (+) sign next to the EJB in the References list Click the new reference TestJDBCJ2C in this example to open the properties for the reference Change WebSphere Bindings and WebSphere Extensions sections as illustrated in Figure 8

15

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 8 Defining a resource reference for an EJB

Save the modified definition and then change the EJB source code to use the reference rather than directly DataSource

TroubleshootingTroubleshooting a multi-tier application may be a bit tricky because the developer needs to deal with software components that reside in separate partitions Three tools are particularly useful for pinning down the potential problem areas bull Joblog messages for a database server job mdash Provides enough details to isolate DB2 UDB for

iSeries runtime issues bull JDBC trace utility mdash Provides granular information about the data flow between the AIX

application and the iSeries server job bull Database Monitor ndash Provides detailed SQL runtime trace

Job Log MessagesAs mentioned a DB2 client communicates with a corresponding iSeries server job This server job runs the SQL requests on behalf of the client The iSeries database server jobs are called QZDASOINIT and they run in the QUSRWRK subsystem At any given time a large number of database server jobs may be active on the server so the first step is to identify the job that serves the particular client connection The easiest method to accomplish this task is to run the following CL command from the i5OS prompt

WRKOBJLCK OBJ(DB2USER) OBJTYPE(USRPRF)

Here DB2USER is the user profile that is used to connect to the iSeries server Note that a QZDASONIT job is assigned to a client after the connection has been established so the developer needs to set a breakpoint in the client application after the database connection has been established

Once the Work with Object Locks appears key in 5 (Work with Job) next to the only QZDASOINIT job that should be listed This shows the Work with Job dialog Select option 10 to

16

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

display the job log for the database server job Now the job log can be searched for any error messages generated by the DB2 runtime

Sometimes it is also useful to include debug messages in the job log The debug messages are informational messages written to the job log about the implementation of a query They describe query implementation methods such as the use of indexes join order ODP implementation (reusable versus non-reusable) and so on The easiest way to instruct an iSeries server to include the debug messages is to set the ServerTraceCategories property on the data source object

tkcpdssetServerTraceCategories(AS400JDBCDataSourceSERVER_TRACE_DEBUG_SERVER_JOB)

A sample of the job log messages with debug messages enabled is shown below

SET TRANSACTION completeSTATEMENT NAME FOUND QZ868F0A458E13AF8C Starting optimizer debug message for query Arrival sequence access was used for file COFFEESODP created ODP not deleted 5000 rows inserted in COFFEES in DB2USER STATEMENT NAME FOUND QZ868F0A4C144BF12EBlocking used for queryCursor CRSR0001 opened606 rows fetched from cursor CRSR0001 ODP not deleted Cursor CRSR0001 closed

So the job log offers fairly detailed information on how the AIX client requests were implemented by the DB2 runtime

JDBC Trace UtilityThe JTOpen driver provides a tracing utility which can be used to collect detailed client-side traces The JDBC tracing is turned off by default It can be enabled by setting the Trace property to true Heres an example of how to switch on tracing using the setTrace method on the data source object

tkcpdssetTrace(true)

The trace can also be enabled when using the DriverManagergetConnection() method for obtaining a connection to DB2 UDB for iSeries In this case the developer could add the trace property to the connection string This approach is illustrated in the following code snippet

ClassforName(comibmas400accessAS400JDBCDriver) [1] hellip con = DriverManagergetConnection(jdbcas400teraplextrace=true

db2userdb2pwd) [2]

At [1] an instance of the JTOpen JDBC Driver is initiated Then at [2] the driver is used to obtain a connection to the iSeries server Note how the trace property has been added to the database URL See the IBM Toolbox for Java JDBC properties documentation on the iSeries Information Center Web site for a complete list of properties supported by the JTOpen driver

Although the level of details provided by the trace utility is sufficient in most troubleshooting scenarios sometimes the developer may need to collect low-level traces scoped to a certain type

17

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

of information In V5R3 the IBM Toolbox for Java (as well as the latest JTOpen) added a comprehensive detailed trace facility The following is the complete list of detailed trace parameters and their purpose

bull None or ldquordquo ndash This setting disables the detailed trace bull datastream - This category is used by Toolbox classes to log dataflow between the local host

and the remote system It is not intended for use by application classes bull diagnostic - This category is used to log object state information bull error - This category is used to log errors that cause an exception bull information - This category is used to track the flow of control through the code bull warning - This category is used to log errors that are recoverable bull conversion - This category is used by Toolbox classes to log character set conversions

between Unicode and native code pages bull proxy - This category is used by Toolbox classes to log data flow between the client and the

proxy server bull pcml - This category is used to determine how PCML interprets the data that is sent to and

from the server bull jdbc - This category is used to track JDBC calls throughout the program bull thread - This category is used to enable tracing of thread information This is useful when

debugging multi-threaded applications bull all - This category will enable all previous categories

The detailed trace can be enabled when using the DriverManagergetConnection() method for obtaining a connection to DB2 UDB for iSeries In this case the developer could add the toolbox trace property to the connection string This is illustrated in the following code sample

String dbUrl = jdbcas400pwd1toolbox trace=diagnostic con = DriverManagergetConnection(dbUrl dbUser dbPassword)

Note that currently the driverrsquos DataSource interfaces do not allow the developer to directly activate the detailed tracing However they could set the server from the command line at the time the java program is launched The example below shows how the detailed trace properties could be enabled at the command line

java -Dcomibmas400accessTracecategory=diagnostic TestJDBC

The -D switch indicates to the java interpreter that the information following it will be a system property

In case of a WebSphere application the trace property can be set through the admin console In the console select Application Servers-gt server1-gt Process Definition -gt Java Virtual Machine Figure 9 shows how to set the Generic JVM Arguments for an application server instance

18

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 9 Setting JVM arguments to enable detailed Toolbox tracing

Database Monitor

The database monitor is the ultimate tool available on DB2 UDB for iSeries to collect low-level SQL traces It is mainly used to pin down the SQL performance problems Refer to the lsquoUsing iSeries Database Monitor to Identify and Tune SQL Queriesrsquo white paper for a detailed discussion on how to collect and analyze the database monitor traces httpibmcomserversenablesiteeducationiborecordhtmldtmon

IBM DB2 JDBC Universal Driver DB2 JDBC Universal Driver is one of the new features delivered with DB2 UDB Version 8 DB2 JDBC Universal Driver has been designed to eliminate the dependency on DB2 CLI runtime modules as well as to enable direct Type 4 connectivity to DB2 UDB for iSeries and DB2 UDB for zOSreg

The pure-Java (Type 4) remote connectivity is based on the DRDA open distributed protocol for cross-platform access to DB2 DRDA defines the rules the protocols and the semantics for accessing distributed data Applications can access data in a distributed relational environment by using SQL statements The iSeries DRDA application server implementation is based on multiple connection-oriented server jobs running in the QSYSWRK subsystem A DRDA listener job (QRWTLSTN) listens for TCP connect requests on port 446 Once an application requester connects to the listener job the listener wakes up one of the QRWTSRVR prestart jobs and assigns it to a given client connection Any further communication occurs directly between the client application and the QRWTSRVR job These concepts are illustrated in Figure 10

19

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 10 Accessing DB2 UDB for iSeries with DB2 Universal Driver

The DB2 Universal Driver can be loaded in an AIX partition by installing one of the DB2 Connect for AIX products (see the Additional Information section for details) It is also a part of a DB2 Enterprise Server Edition for AIX install Specifically the developer needs three JAR files in a AIX partition to successfully connect to an iSeries server db2jccjar db2jcc_license_cisuzjar and db2jcc_license_cujar The iSeries license is contained in db2jcc_license_cisuzjar Note that this file is not a part of DB2 Client In other words a DB2 Connect license is required to use the driver in production environments The location of the JAR files needs to be added to the CLASSPATH environment variable For instance the following entry could be added to the AIX profile script

CLASSPATH=homedb2inst2sqllibjavadb2jccjarCLASSPATH=$CLASSPATHhomedb2inst2sqllibjavadb2jcc_license_cujarCLASSPATH=$CLASSPATHhomedb2inst2sqllibjavadb2jcc_license_cisuzjarexport CLASSPATH

Java Runtime 131 is a prerequisite

Additionally the developer should install the latest database group PTF (SF99503 for i5OS V5R3) on the iSeries server The Informational APAR ii13348 is keeping track of any fixes relevant to DRDA above and beyond the current database group PTF

Obtaining a Connection to DB2 UDB for iSeries When Type 4 connectivity is used the DB2 Universal Driver connects directly to the DB2 on iSeries through TCPIP Note that this is different from the legacy DB2 Type 2 JDBC driver that requires a DB2 node and remote database configurations on the client accessing iSeries The following code snippet illustrates how to use the DB2 JDBC Universal Driver to obtain a connection to DB2 UDB for iSeries

20

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

try ClassforName(comibmdb2jccDB2Driver) [1] catch(javalangClassNotFoundException e) Systemerrprint(ClassNotFoundException )Systemerrprintln(egetMessage())

try DriverManagergetConnection(jdbcdb2teraplex446TERAPLEX[2]

db2userdb2pwd) hellip catch(SQLException ex) Systemerrprintln(

SQLException + exgetMessage())

At [1] an instance of the DB2 JDBC Universal Driver is instantiated Then at [2] the driver is used to obtain a connection to the iSeries server Note the proper form of the database URL required by the driver

Considerations There are several advantages of DB2 JDBC Universal Driver bull Ease of cross-platform development mdash Consistent coding techniques and consistent error

codes and messages bull Ease of deployment mdash Pure Java (no runtime client required) and a single driver for accessing

DB2 on different platforms

The ease of use comes at a price though The iSeries JTOpen driver is optimized for accessing DB2 UDB for iSeries data and it uses native iSeries protocol to communicate with the back-end database server job This usually results in better performance and more-efficient system resources utilization For instance when using the DB2 JDBC Universal Driver to access an iSeries server the executeBatch method results in a single record insert There are also some restrictions when using DB2 Universal JDBC Driver with Type 4 connectivity

bull Support for distributed transactions (JTA) is not enabled bull Driver built-in connection pooling is not supported

Refer to Java application support in DB2 for more details on DB2 JDBC Universal Driver

21

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 Connect data access This section will explore the most important aspects of DB2 Connect ndash iSeries integration - including configuration tips and coding examples

DB2 Connect provides functionality for accessing data stored in DB2 UDB for iSeries as well as DB2 UDB for zOS and DB2 UDB for OS390reg DB2 Connect offers capabilities to access DB2 family members via several SQL interfaces gateway functions such as connection pooling and federated database functionality Many applications supporting the DB2 family of products leverage DB2 Connect as a key middleware component DB2 Connect is offered as separate AIX license products

Enterprise Edition Application Server Edition

In addition to DB2 Connect there are several other DB2 UDB Version 81 products that are supported on AIX

DB2 Universal Database Enterprise Server Edition DB2 Universal Database Workgroup Server Unlimited Edition DB2 Universal Database Workgroup Server Edition DB2 Universal Database Universal Developers Edition All Clients

The DB2 Connect Enterprise Edition functionality is also contained in DB2 Enterprise Server Edition for AIX

22

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 Connect in a nutshell In the scenario described in this paper the DB2 Connect functions contained in DB2 Enterprise Edition for AIX are utilized DB2 Connect Enterprise Edition provides support for both local and remote DB2 clients This is illustrated in Figure 11 Accessing DB2 UDB for iSeries with DB2 Connect

Figure 11 Accessing DB2 UDB for iSeries with DB2 Connect

DB2 Connect implements the Distributed Relational Database Architecturetrade (DRDAreg) to reduce the cost and complexity of accessing data stored in DB2 UDB for iSeries and other DRDA-compliant database servers DRDA defines the rules the protocols and the semantics for accessing distributed data Applications can access data in a distributed relational environment by using SQL statements In a distributed environment the system running the application and sending the SQL requests across the network is called the application requester (AR) A remote database server that executes SQL requests submitted by an application requester is known as the application server (AS) In the example shown in Figure 11 (above) DB2 Connect plays the role of an application requester while DB2 UDB for iSeries is an application server In this case DB2 Connect communicates with the iSeries database through TCPIP The iSeries DRDA application server implementation is based on multiple connection-oriented server jobs running in the QSYSWRK subsystem A DRDA listener job (QRWTLSTN) listens for TCP connect requests on port 446 Once an application requester connects to the listener job the listener wakes up one of the QRWTSRVR prestart jobs and assigns it to a given client connection Any further communication occurs directly between the client application and the QRWTSRVR job

DB2 Connect supports a wide range of programming interfaces that can be used by AIX applications to access the iSeries database Embedded SQL frac34 Both static and dynamic SQL frac34 Various programming languages (Java CC++ Cobol Fortran REXX)

DB2 Call Level Interface (DB2 CLI) ODBC JDBC frac34 DB2 JDBC Type 2 Driver frac34 DB2 JDBC Type 4 Driver (Universal JDBC Driver)

23

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Note that DB2 Connect supports access to DB2 UDB for iSeries through DB2 JDBC Universal driver However for performance and ease of maintenance reasons IBM recommends that Java applications running in AIX use native iSeries Toolbox JDBC driver See the JDBC Data Access section of this paper (above) for more details On the other hand DB2 Connect is a very efficient and robust connectivity option for AIX applications especially in the environments that are not directly supported by the native iSeries JDBC driver Here are several possible scenarios that would require DB2 Connect installed in a AIX partition

Embedded SQL interface is used to access DB2 CLI or ODBC interface is used to access DB2 A single SQL interface is needed to access multiple back end DB2 server Specific DB2 Connect functionality is needed such as distributed join or connection

pooling

Prerequisites One of the DB2 Connect products or DB2 Enterprise Server Edition for AIX V81 is needed Additionally DB2 Application Development Client is required in the AIX partition to compile DB2 applications

For maximum database server stability the developer should install the latest database group PTF (SF99503 for i5OS V5R3) on the iSeries server The Informational APAR ii13348 is keeping track of any fixes relevant to DRDA above and beyond the current database group PTF

DB2 Connect configuration The following example employs i5OS V5R3 and DB2 UDB Enterprise Server Edition for AIX Version 81 FixPak 6

Configuration steps in the iSeries partition The following process lists the necessary steps to be performed on the iSeries server 1) Verify that the TCPIP stack is working correctly It is assumed that the Virtual LAN is used to

communicate with the i5OS partition First obtain the IP address of the iSeries server or its hostname and ping the iSeries server from the AIX partition

2) Create a relational database (RDB) entry for the iSeries database in the i5OS partition If this has already been created it can be displayed by using the DSPRDBDIRE command Make sure that the RDB entry with a location of LOCAL exists on the iSeries server If it does not exist use the ADDRDBDIRE command to add the appropriate RDB entry For example the following command would add an RDB entry named TPLX For simplicity it is recommended that the TCPIP host name and RDB entry remain the same

ADDRDBDIRE RDB(TPLX) RMTLOCNAME(LOCAL)

3) Create a collection called NULLID This is necessary because the utilities shipped with DB2 Connect and DB2 UDB for AIX store their packages in the NULLID collection Since it does not exist by default in the iSeries server you must create it using the following command

CRTLIB LIB(NULLID)

4) Products that support DRDA automatically perform any necessary code page conversions at the receiving system For this to happen both systems need a translation table from their code page to the partner code page The default Coded Character Set Identifier (CCSID) on the iSeries server is 65535 Since DB2 Connect does not have a translation table for this code page the developer needs to change the individual user profiles to contain a CCSID that can be converted properly by DB2 Connect For US English this is 037 For other languages see DB2 Connect Personal Edition Quick Beginning GC09-2967 The following command changes the CCSID for an individual user profile to 037

24

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

CHGUSRPRF userid CCSID(037)

5) Verify that the default port 446 for DRDA service is being used To do this go to the Configure TCPIP menu (CFGTCP) select Configure Related Tables and then select Work with service table entries Verify that the DRDA service is set for port 446

6) The Distributed Data Management (DDM) job must be started for DRDA to work If you want the DDM job to be automatically started whenever TCPIP is started change the attributes of the DDM job using the CHGDDMTCPA command and set the Autostart server parameter to YES

7) If the system administrator chooses not to autostart the server issue the following command to start the DDM server job

STRTCPSVR SERVER(DDM)

8) Make sure that the user profiles that will be used to connect to the iSeries server exist on the server

25

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Configuration steps in the AIX partition The following steps are required for DB2 Connect to be configured in the AIX partition 1) Sign on to the AIX partition as the DB2 administrator 2) Launch Client Configuration Assistant (db2ca from the command prompt) It is assumed that

VNC or an X-Windows server are being used on the workstation so that the db2ca GUI can be properly rendered

3) From the Selected pull-down menu select the Add Database using Wizard option The Select how you want to setup a connection dialog appears Select Manually configure a connection to a database and click Next This is shown in Figure 12

Figure 12 Accessing DB2 UDB for iSeries with DB2 Connect

26

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

4) On the Select a communications protocol choose TCPIP and select The database physical resides on a host or OS400 system Then select the option Connect directly to the server as shown in Figure 13 Click Next

Figure 13 mdash Selecting communications protocol

27

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

5) On the TCPIP tab fill in the host name of the iSeries server The port number should be 446 This is shown in Figure 14 Click Next

Figure 14 mdash Specifying TCPIP communication parameters

28

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

6) On the Database tab fill in the Relational Database name Use the RDB entry name (specified in step 2) in the Configuration steps in the iSeries partition section as shown in Figure 15 Click Next

Figure 15 mdash Specifying the remote database

7) If you plan to use the ODBC applications select Register this database for ODBC as a system data source on the ODBC tab Click Next

29

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

8) On the Specify the node option dialog select OS400 from the Operating System pull-down menu This is shown in Figure 16 Click Finish

Figure 16 mdash Specifying the node options

30

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

9) The Test Connection dialog appears This allows the developer to verify that the connection works Select both CLI and JDBC check boxes You are also prompted for an iSeries user ID and password as shown in Figure 17

Figure 17 mdash Testing the connection

31

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

10) The successful connection to the database server is confirmed by the message box shown in Figure 18

Figure 18 mdash Test Connection results 11) At this time a newly configured database connection should appear in the main DB2

Configuration Assistant window It is recommended that the DB2 utilities are also bound to the iSeries database The bind process creates the necessary SQL packages on the remote database In the main Configuration Assistant window click the TPLX database entry and then select Selected-gtBindhellip

32

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

12) The Bind dialog appears Click Select All and then enter the connection information as shown in Figure 19 Click Bind The Results message box appears This allows the developer to monitor the progress of the binding process Watch for any error and warning messages

Figure 19 mdash Binding the DB2 utilities This concludes the DB2 Connect configuration steps

33

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Accessing DB2 UDB for iSeries from C embedded SQL

As mentioned earlier DB2 Connect allows developers to compile and run embedded SQL applications that access DB2 UDB for iSeries data This section covers implementation details for a C embedded SQL application called cursorsjsqc (see Appendix B for source code)

Prerequisites An embedded SQL application running in an AIX partition will use DB2 Connect services to access DB2 UDB for iSeries therefore the developer needs to make sure that all components listed in section Prerequisites on page 24 are installed The developer also needs to create a remote database connection as described in the DB2 Connect configuration section of this paper on page 24

Static SQL and SQL packages To successfully run against a DB2 UDB for iSeries database an embedded SQL application needs to be first precompiled and bound to the back-end database This process creates an SQL package on the target iSeries server The SQL package contains the access plan information for the SQL statements executed by the application The internal structure of the package as well as the method how its content is used by the SQL runtime to facilitate the access plan reuse is similar to the Extended Dynamic SQL support covered in detail in the Extended Dynamic SQL and Statement Caching section of this paper (on page 9) There are however important differences between the packages created by the extended dynamic SQL support and the packages created for embedded SQL DRDA client applications The extended dynamic SQL packages support dynamic SQL interfaces such as JDBC

that can submit ad hoc SQL statements at the run time The SQL runtime can prepare the dynamic statements and add them to the package On the other hand the DRDA packages are created at the precompile time and contain static SQL In order to add new statements to the package the application needs to be precompiled and rebound again

The extended dynamic SQL package can dynamically grow up to 500MB by allocating new space as required The DRDA packages since they are created at the precompile time have a fix size and do not grow over their life time

Simple embedded SQL application The application is based on a source code provided in the DB2 UDB samples directory typically to be found at homedb2inst1sqllibsamples The cursorsjsqc performs a join between STAFF and ORG tables located in DB2USER schema (library) on the TPLX database server (the source is provided at the end of this paper in Appendix B) The join statement retrieves the DEPTNAME column from ORG NAME column from STAFF and calculates the total compensation for an employee by adding SALARY and COMM columns in STAFF The results are sorted by department name and total compensation Here is the SELECT statement used by the application

SELECT deptname name salary + IFNULL(comm0) as compensationFROM org o staff sWHERE odeptnumb = sdeptORDER BY deptname compensation DESC

The application iterates through the selected records and prints out the data to the standard output device The sample DB2USER schema was created with the following SQL statements

db2 CONNECT TO tplx USER db2user USING mypassworddb2 CALL QSYSCREATE_SQL_SAMPLE(DB2USER)

34

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Make sure that the AIX partition is logged into with the DB2 admin user profile If the defaults were selected at the DB2 installation time this profile name is db2inst1 It is also assumed that DB2USER user exists on the iSeries server and that it has appropriate authority

There are several steps that are required to create an executable for the cursorsjsqc source code First the DB2 PRECOMPILE utility needs to be called The utility creates a bind file that is used to bind the required SQL package to the TPLX database It also converts embedded SQL statements into DB2 run-time API calls and produces a pure C source file that can be processed by an AIX C compiler

db2 CONNECT TO tplx USER db2user USING mypassworddb2 prep cursorsjsqc bindfile

Note that the connect statement is required only if the developer is not already connected to the database on an iSeries server Watch for any error or warning messages returned by the DB2 prep utility The prepare step should produce cursorsjbnd and cursorsjc files in the current directory Now the developer can invoke the bind utility to prepare the statements contained in the bind file and create the package on the target iSeries database server

db2 bind cursorsjbnd

It is assumed that Visual C++ 60 is installed and configured in the AIX partition Refer to the ldquoDeveloping and Porting C and C++ Applications on AIXrdquo redbook for more information on how to use the Visual C++ compiler httpibmcomredbooksabstractssg245674htmlOpen

Use the following commands to compile the C source generated by the precompile utility

xlc -I$INSTHOMEsqllibinclude ndashc cursorsjcxlc ndasho cursorsj cursorsjo -L$INSTHOMEsqlliblib ndashldb2

Run the program from the AIX prompt

cursorsj db2user mypassword

Distributed Join DB2 UDB Version 8 provides core federated server functionality A federated system consists of a DB2 UDB instance that operates as a federated server a database that acts as the federated database one or more data sources and clients (users and applications) that access the database and data sources Federated server permits objects stored in multiple databases to be accessed together in the same query For example a query can refer to a table that resides in DB2 UDB for iSeries and join it to a table stored in DB2 UDB for AIX Such a query would constitute so called distributed join The support for DB2 UDB for iSeries as a federated data source is provided by core federated server functionality directly implemented in DB2 UDB Enterprise Server Edition and DB2 UDB Connect Enterprise Edition All other DB2 UDB family members are also supported directly by core DB2 UDB federated server An additional software product DB2 Information Integratortrade is required to access non-DB2 UDB databases such as Oracle Sybase or Microsoftreg SQL Server Consult the following white papers for a detailed discussion on DB2 federated server support Heterogeneous data access for iSeries applications Version 2 httpibmcomserversenablesiteeducationiborecordhtmlhetdata Fundamentals of IBM DB2 Federated Server and Relational Connect httpwww7bsoftwareibmcomdmddlibrarytecharticle0206purnell0206purnellhtml

35

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Distributed Join Example In this section the steps that are required to configure DB2 UDB for iSeries as a federated data source will be illustrated Then the cursorsjsqc program will be ldquotweakedrdquo so that it executes a distributed join query that accesses data stored on an iSeries server and in the local DB2 UDB for AIX database It is assumed that the developer is familiar with the DB2 federated server concepts

Note Run the following commands from the Command Line Processor prompt Load the utility by executing the db2 command at the AIX prompt 1) First the local DB2 UDB for AIX instance needs to be enabled as a DB2 federated server

This is done by setting the database manager configuration parameter FEDERATED to YES

db2=gt update dbm cfg using FEDERATED YES

The database instance needs to be restarted for the change to take effect

NOTE A federated database is a regular database in a DB2 UDB instance that has the FEDERATED parameter enabled Therefore in this example the SAMPLE database that was created earlier is used as the federated database A new database can also be created using the CREATE DATABASE command

2) Connect to the federated database

db2=gt connect to sample

3) Use the CREATE WRAPPER statement to register a wrapper for the iSeries data source Wrappers are library routines that are used by the federated server to perform operations such as connecting to a data source and retrieving data from it The default wrapper name for DB2 UDB for iSeries is DRDA Here is the command to register the DRDA wrapper

db2=gt create wrapper drda

4) Use the CREATE SERVER statement to register a data source as a server within the federated database The server definition specifies the type and version of the data source and the wrapper used for communications with this data source For the DB2 UDB for iSeries data source the node and the database names are also needed The node and database name parameters have been configured for our TPLX database in the Configuration steps in the AIX partition section (on page 24) Use the following DB2 UDB command to lookup these parameter on the federated server

db2=gt list database directory

In this case the command produced the following output

Database alias = TPLX Database name = DCSE99E1 Node name = NDE9BF76 Database release level = a00 Comment = Directory entry type = Remote Authentication = SERVER Catalog database partition number = -1

36

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Note that the node name is set to NDE9BF76 The name was generated by the Configuration Administrator utility (db2ca)

Here is the command to register the TPLX database as a federated server

db2=gt create server tplx type db2400 version 530 wrapperdrda authorization db2user password mypassword options(nodeNDE9BF76 dbname TPLX)

The command is quite complex so make sure that the syntax is correct

5) Define the user mappings that instructs the federated server what user ID and password should be used when connecting to the iSeries data source

db2=gt create user mapping for user server tplxoptions(remote_authid db2user remote_password mypassword)

Specify the nickname for the iSeries table or view A nickname is an identifier that is used by the federated server to reference an object located at the data source The following command creates a nickname for the STAFF table located in the DB2USER schema on the TPLX database

db2=gt create nickname tplx_staff for tplxdb2userstaff

6) Test the distributed join query

db2=gt SELECT deptname name salary + COALESCE(comm0) ascompensation FROM org o tplx_staff s WHERE odeptnumb =sdept ORDER BY deptname compensation DESC

Note that the native iSeries function IFNULL has been substituted with an equivalent DB2 UDB function COALESCE COALESCE is also supported on iSeries servers For better portability IBM encourages the use of COALESCE rather than IFNULL Note also that the query runs on the federated server rather than on TPLX It accesses the ORG table in the local DB2 UDB for AIX SAMPLE database and the STAFF table that resides in TPLX The federated server performs the necessary distributed join

7) Modify the cursorsjsqc so that it executes a distributed join There are two source code modifications - Change the CONNECT TO statements Now the application needs to connect to the

federated database SAMPLE rather than to TPLX

EXEC SQL CONNECT TO SAMPLEEXEC SQL CONNECT TO SAMPLE USER userid USING passwd

- Modify the select statement so that it performs a distributed join Use the statement (shown in step 6) above Save the new source version as cursordjsqc

- Prepare bind and compile the distributed join version of the program as described in the Simple C embedded SQL application section (on page 34)

db2 prep cursordjsqc bindfiledb2 bind cursordjbndxlc -I$INSTHOMEsqllibinclude ndashc cursordjcxlc ndasho cursordj cursordjo -L$INSTHOMEsqlliblib ndashldb2

37

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

- Run the program from the AIX prompt

cursordj

Connection Pooling and Connection ConcentratorA modern Web-based application typically executes a large number of short-lived transactions Executing a transaction in this environment means establishing a database connection executing a few SQL statements and terminating this connection Creating connections to the database server is a very costly process To reduce the unnecessary workload DB2 Connect implements connection pooling and connection concentrator Connection pooling mechanism allows DB2 Connect to reuse an existing connection infrastructure for subsequent connection requests The connection concentrator is an advanced technology that allows DB2 Connect to serve a potentially very large number of clients with a limited number of database connections This is accomplished by decoupling clients from a particular database connection

Note that currently neither connection pooling nor connection concentrator support DB2 UDB for iSeries Therefore for performance reasons the author strongly recommends that the application server that obtains and drops connections very frequently implements its own database connection pooling mechanism that would assign an existing pooled database connection to a new AIX process or thread

TroubleshootingTroubleshooting a multi-tier application may be a bit tricky because the developer needs to deal with software components that reside in separate partitions The authorrsquos experience shows that two tools are particularly useful for pinning down the potential problem areas The joblog messages for a database server job usually provide enough details to isolate DB2

UDB for iSeries runtime issues The DRDA trace utility provides granular information about the data flow between the AIX

application and the iSeries server job

38

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Job Log MessagesAs mentioned earlier a DB2 client communicates with a corresponding iSeries server job This server job runs the SQL requests on behalf of the client More precisely when a DB2 client submits an SQL statement the statement is passed to a server job that in turn calls the DB2 runtime to execute the statement The results are then reformatted and marshaled to the client The iSeries DRDA server jobs are called QRWTSRVR and they run in the QUSRWRK subsystem At any given time there may be a large number of DRDA server jobs active on the system so the first step is to identify the job that serves the particular client connection The easiest method to accomplish this task is to run the following CL command from the i5OS prompt

WRKOBJLCK OBJ(DB2USER) OBJTYPE(USRPRF)

Here DB2USER is the user profile that is used to connect to the iSeries server Note that a QRWTSRVR job is assigned to a client after the connection has been established so the developer needs to set a breakpoint in the client application below the CONNECT TO statement

Once the Work with Object Locks appears key in 5 (Work with Job) next to the only QRWTSRVR job that should be listed This shows the Work with Job dialog Select option 10 to display the job log for the database server job Now the developer can search the job log for any error messages generated by the DB2 runtime

Sometimes it is also useful to include debug messages in the job log The debug messages are informational messages written to the job log about the implementation of a query They describe query implementation methods such as use of indexes join order ODP implementation (reusable versus non-reusable) and so on The easiest way to instruct the iSeries server to include the debug messages is to call the following stored procedure just after the connection to the iSeries server is established

EXEC SQL call qsysqcmdexc(STRDBGUPDPROD(YES)000000002000000)

A sample of the job log messages with debug messages enabled is shown below in Figure 20

Arrival sequence access was used for file STAFFAccess path suggestion for file STAFFQuery options used to build the OS400 query access plan Ending debug message for query ODP created Blocking used for queryCursor SQLCUR201 opened1 rows fetched from cursor SQLCUR201Row not found for SQLCUR201ODP deleted Cursor SQLCUR201 closedDESCRIBE of prepared statement STMT0201 completed

Figure 20 mdash Joblog with debug messages enabled

So the job log offers fairly detailed information on how the AIX client requests were implemented by the DB2 runtime

39

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 DRDA trace utilityThe DB2 DRDA trace utility (db2drdat) provides detailed information about the data streams exchanged between DB2 Connect and target database server The output file produced by the utility contains send and receive communications buffers TCPIP error messages and SQL Communications Area (SQLCA) information Please refer to lsquoDB2 Connect Userrsquos Guidersquo manual for in-depth discussion of the DRDA trace utility

Accessing DB2 UDB for iSeries from CLI DB2 Call Level Interface (CLI ) is based on the Microsoft Open Database Connectivity (ODBC) specification and the ISO CLI standard The DB2 CLI interface gained popularity among DB2 application providers because the developer can build an ODBC application by simply linking the application with libdb2 library on a UNIX server In other words the developer directly utilizes the DB2 ODBC driver services without a need for an ODBC driver manager Additionally in contrast to embedded SQL the developer does not need to precompile or bind DB2 CLI applications because they use packages provided with DB2 UDB The developer simply compiles and links the application

Prerequisites A DB2 CLI application running in an AIX partition will use DB2 Connect services to access DB2 UDB for iSeries therefore make sure that all components listed in Prerequisites section of this paper on page 24 are installed The developer also needs to create a remote database connection as described in the DB2 Connect configuration section of this paper on page 24

Dynamic SQL and Access Plan Caching A DB2 CLI client application uses the dynamic SQL interface and does not have the capability to utilize the extended dynamic SQL support Therefore it runs lsquopurersquo dynamic SQL statements That does not mean however that the process of parsing validating and optimizing will be repeated for every execution of a given dynamic SQL statement

The DB2 UDB for iSeries database implements an internal object called System-Wide SQL Statement Cache (SWSC) The SWSC can improve the performance of programs using dynamic SQL statements by caching the access plans in a system-wide cache When a dynamic SQL statement is submitted the SQL runtime searches the SWSC to see if this statement has been previously executed If so then DB2 retrieves and reuses the key information associated with the cached statement and thereby the processing time and the resources utilization can be significantly reduced

Simple DB2 CLI C++ ApplicationThis section covers DB2 CLI implementation details for a sample C++ program called testclicpp (the source is provided at the end of this paper in Appendix C) To compile the source with Visual C++ complier use the following command in the AIX partition

xlC ndashI$INSTHOMEsqllibinclude ndashc testclicppxlC ndasho testcli testclio ndashL$INSTHOMEsqlliblib ndashldb2

The application performs a join between STAFF and ORG tables located in DB2USER schema (library) The join statement retrieves the DEPTNAME column from ORG NAME and JOB columns from STAFF and calculates the total compensation for an employee by adding SALARY and COMM columns in STAFF The results are sorted by total compensation The selection criterion is based on the current value of the department name parameter Here is the SELECT statement used by testcli

40

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

select name job salary + coalesce(comm0) as compensationfrom org o staff swhere odeptnumb = sdeptand deptname = order by compensation desc

Figure 21 shows the software components involved in the execution of this sample application

Figure 21 How a DB2 CLI client accesses DB2 UDB on an iSeries server

Although the testcli application is fairly simple it covers some important aspects of efficient CLI programming for DB2 UDB for iSeries

Reusable Open Data Paths (ODPs)An Open Data Path (ODP) definition is an internal i5OS object that is created when certain SQL statements (such as OPEN INSERT UPDATE and DELETE) are executed for the first time in a given job (or connection) The ODP can be thought of as a runtime implementation of an access plan The access plan created at the optimization time provides a recipe or in other words a sequence of steps necessary to execute the statement The ODP on the other hand provides the executable code for all requested IO operations The process of creating new ODP objects is fairly CPU- and IO-intensive so whenever possible the iSeries DB2 runtime tries to reuse existing ODPs For instance a SQLCloseCursor() API call may close the SQL cursor but leave the ODP available to be used the next time the cursor is opened This can significantly reduce the processing and response time in running SQL statements A reusable OPD usually requires 10 to 20 times less CPU resources than a newly created ODP Therefore it is important that the applications employ programming techniques that allow the DB2 runtime to reuse ODPs

With dynamic interfaces such as CLI full opens are avoided by using a prepare once execute many programming paradigm It means that when an SQL statement is going to be executed more than once you should prepare the statement just once and then reuse the prepared

41

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

statements for consecutive executions Although DB2 UDB does try to convert literals to parameter markers so that similar statements can be reused it is a better programming practice to explicitly implement parameter markers That way the chances for reusable ODPs are quite significantly improved The code snippet in Figure 22 illustrates how to implement the prepare once execute many programming technique

Define A SELECT SQL Statementstrcpy((char ) SQLStmt select name job salary + ifnull(comm0) ascompensation )ptr = strcat( (char ) SQLStmt from org o staff s )ptr = strcat( (char ) SQLStmt where odeptnumb = sdept)ptr = strcat( (char ) SQLStmt and deptname = )ptr = strcat( (char ) SQLStmt order by compensation desc) [1]

Prepare The SQL Statementrc = SQLPrepare(ExampleStmtHandle SQLStmt SQL_NTS) [2]

Bind The Columns In The Result Data Set Returned To Application Variablesrc = SQLBindCol(ExampleStmtHandle 1 SQL_C_CHAR (SQLPOINTER)

ExampleName sizeof(ExampleName) NULL)rc = SQLBindCol(ExampleStmtHandle 2 SQL_C_CHAR (SQLPOINTER)

ExampleJob sizeof(ExampleJob) NULL)rc = SQLBindCol(ExampleStmtHandle 3 SQL_C_DOUBLE (SQLPOINTER)

ampExampleComp sizeof(ExampleComp) NULL)

for (int i = 0 i lt LOOPS i++)rc=SQLBindParameter(ExampleStmtHandle

1SQL_PARAM_INPUTSQL_C_CHARSQL_CHAR10(SQLPOINTER) currentDepartment[i8]0NULL) [3]

rc = SQLExecute(ExampleStmtHandle) [4]cout ltlt endl ltlt Current Dept ltlt currentDepartment[i8] ltlt endl Display The Results Of The SQL QueryExampleShowResults()

Figure 22 Use the prepare once execute many programming technique

The error-handling code has been removed for clarity At [1] the statement text is assigned to a variable Note that a parameter marker is used in the WHERE clause The statement is then prepared just once at [2] The current value of the parameter is bound to the prepared statement at [3] The prepared statement is executed at [4] Steps [3] and [4] are repeatedly executed in a for loop

Techniques to Further Improve DB2 CLI Performance Thus far this paper has discussed the techniques used by a sample application to tune the CLI performance However depending on the application architecture other methods of improving CLI performance may be considered

Connection PoolingCurrently the CLI application connecting through DB2 Connect to DB2 UDB for iSeries does not take advantage of the connection pooling mechanism implemented by DB2 Connect Therefore for performance reasons the author strongly recommends that the application server that obtains and drops connections very frequently implements its own database connection pooling mechanism that would assign an existing pooled database connection to a new AIX process or thread

42

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Blocking

For queries which result in returning large data blocks from the iSeries server (usually 32K of data and above) ensure that the database manager configuration parameter RQRIOBLK is set to 32767 This can be done using the Command Line Processor (CLP) as follows

db2 update database manager configuration using RQRIOBLK 32767

TroubleshootingThe experience of the author shows that two tools are particularly useful for pinning down the potential problem areas bull Joblog messages for a database server job usually provides enough details to isolate DB2

runtime issues bull CLI trace utility provides granular information about the data flow between the AIX application

and the database server job

Job Log MessagesThe process of finding and analyzing the job log for a DB2 CLI connection is identical to the process outlined for an embedded SQL application in the Job Log Message section of this paper on page 39

CLI Trace The DB2 CLIODBCJDBC trace utility provides very detailed information about the data streams exchanged between DB2 Connect and target database server Refer to the DB2 Information Center for more information on how to set up and analyze the CLI traces httppublibboulderibmcominfocenterdb2v8luwindexjsptopic=comibmdb2udbdocadc000 7959htm

43

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Trademarks

IBM eServer iSeries AIX AIX 5L i5OS WebSphere DB2 DB2 Universal Database DB2 Connect OS400 zOS OS390 Distributed Relational Database Architecture DRDA and DB2 Information Integration are trademarks or registered trademarks of International Business Machines Corporation in the United States and other countries

Java and all Java-based trademarks are trademarks of Sun Microsystems Inc in the United States other countries or both

Linux is a registered trademark of Linus Torvalds in the United States other countries or both

UNIX is a registered trademark of The Open Group in the United States and other countries

Microsoft and Windows are registered trademarks of Microsoft Corporation in the United States andor other countries

All other registered trademarks and trademarks are properties of their respective owners

IBM makes no commitment to make available any products referred to herein

References in this publication to IBM products or services do not imply that IBM intends to make them available in every country in which IBM operates

Additional Information ITSO offers a Redbook that can be helpful to those who want to learn more about i5OS AIX integration

bull AIX Integration with I5OS on the IBM eServer iSeries Server (SG24-6551)

Jarek Miszczyk is the Senior Software Engineer IBM eServer Solutions Enablement IBM Rochester

[Portions of this white paper reprinted with permission from MC Mag Online published by MC Press LLP httpwwwmcpressonlinecom]

Acknowledgments The author would like to thank the following people for their advice contributions and support on this paper

Bob Bittner IBM Rochester Jon Rush IBM Rochester Prasad Vallurupalli IBM Rochester Neil Willis IBM Rochester

44

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix A Source Listing of TestJDBCjava

package comibmiseriespwdimport javasqlimport javaxnamingimport javautilHashtableimport javautilimport javaxsqlimport comibmas400access

public class TestJDBC public static void main(javalangString[] args)

throws Exception

int numOfLoops = 5000int outerNumOfLoops = 5boolean firstExec = trueConnection conStatement sPreparedStatement psPreparedStatement pstmtdelCallableStatement cstmPreparedStatement pstmtHashtable env = new Hashtable()

envput(ContextINITIAL_CONTEXT_FACTORYcomsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env)Systemoutprintln(Deploying connection pooling data source)deployDataSource() Do the work with connection pooling onlyAS400JDBCConnectionPoolDataSource tkcpds =

(AS400JDBCConnectionPoolDataSource)ctxlookup(jdbcToolkitDataSource) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPool pool = new AS400JDBCConnectionPool(tkcpds) Adds 1 connection to the pool that can be used by theapplication (creates the physical database connections based onthe data source)poolfill(1)Systemoutprintln(nStart timing Toolkit connection pooling)long startTime = SystemcurrentTimeMillis()

for (int i = 0 i lt outerNumOfLoops i++) con = poolgetConnection()consetAutoCommit(false) deleteif ( i == 0)

long startDelete = SystemcurrentTimeMillis()cstm = cstm = conprepareCall(

CALL qsysqcmdexc(CLRPFM FILE(DB2USERCOFFEES) + 000000002800000))

cstmexecuteUpdate()cstmclose()long endDelete = SystemcurrentTimeMillis()Systemoutprintln(Delete all records +

(endDelete - startDelete) + ms elapsed)

45

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

String sqlinstrlong startInsert = SystemcurrentTimeMillis() insert

pstmt =conprepareStatement(INSERT INTO COFFEES VALUES( ))for (int j = 0 j lt numOfLoops j++) pstmtsetString(1 Kona_ + IntegertoString(i))pstmtsetInt(2 150)pstmtsetFloat(3 999f)pstmtsetInt(4 0)pstmtsetInt(5 0)pstmtaddBatch()int [] updateCounts = pstmtexecuteBatch()concommit()pstmtclose()long endInsert = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for + numOfLoops + inserts

+ (endInsert - startInsert)) selectlong startSelect = SystemcurrentTimeMillis()ps = conprepareStatement(SELECT FROM COFFEES)ResultSet rs = psexecuteQuery()rsnext()rsclose()concommit()psclose()long endSelect = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for select +

(endSelect - startSelect))consetAutoCommit(true)conclose()long endTime = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for + outerNumOfLoops +

loops + (endTime - startTime))Systemexit(0)

private static void deployDataSource()throws ExceptionString serverName = teraplex String databaseName = TERAPLEX String userName = db2user String password = db2pwd

Establish a JNDI context and bind the connection pool data sourceHashtable env = new Hashtable()envput(ContextINITIAL_CONTEXT_FACTORY

comsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPoolDataSource tkcpds = new

AS400JDBCConnectionPoolDataSource()tkcpdssetServerName(serverName) tkcpdssetDatabaseName(databaseName) tkcpdssetUser(userName) tkcpdssetPassword(password) tkcpdssetDescription(Toolkit Connection Pooling DataSource)tkcpdssetSavePasswordWhenSerialized(true)tkcpdssetExtendedDynamic(true)

46

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

tkcpdssetPackage(JDBCDS)tkcpdssetPackageCache(true)tkcpdssetPackageCriteria(select)enable the following properties as requiredcpdssetTrace(true)tkcpdssetServerTraceCategories( AS400JDBCDataSourceSERVER_TRACE_DEBUG_SERVER_JOB)

ctxrebind(jdbcToolkitDataSource tkcpds)

47

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix B mdash Source Listing of cursorsjsqc

Source File Name = cursorsjsqc Licensed Materials - Property of IBM (C) COPYRIGHT International Business Machines Corp 1995 2000 2004 All Rights Reserved US Government Users Restricted Rights - Use duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp PURPOSE This sample program demonstrates the use of a CURSOR The CURSOR is processed using static SQL EXTERNAL DEPENDENCIES - Ensure existence of database for precompile purposes - Precompile with the SQL precompiler (PREP in DB2) - Bind to a database (BIND in DB2) - Compile and link with the IBM Cset++ compiler (AIX and OS2) or the Microsoft Visual C++ compiler (Windows) or the compiler supported on your platform For more information about these samples see the README file For more information on programming in C see the - Programming in C and C++ section of the Application Development Guide For more information on building C applications see the - Building C Applications section of the Application Building Guide For more information on the SQL language see the SQL Reference

include ltstdiohgt include ltstdlibhgt include ltstringhgtinclude ltsqlhgtinclude ltsqlenvhgtinclude ltsqldahgtinclude ltsqlcahgt

int SqlInfoPrint( char struct sqlca int char )void TransRollback( void)

define EMB_SQL_CHECK( MSG_STR ) rc = SqlInfoPrint( MSG_STR ampsqlca __LINE__ __FILE__) if ( rc = 0 ) TransRollback( )

return 1

EXEC SQL INCLUDE SQLCA

int main(int argc char argv[])

EXEC SQL BEGIN DECLARE SECTIONchar dname[15]

48

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

char pname[10]double compchar userid[9]char passwd[19]

EXEC SQL END DECLARE SECTION

int rc = 0printf( Sample C program CURSORSJ n )if (argc == 1)

EXEC SQL CONNECT TO TPLXEMB_SQL_CHECK(CONNECT TO TPLX)

else if (argc == 3)

strcpy (userid argv[1])strcpy (passwd argv[2])EXEC SQL CONNECT TO TPLX USER userid USING passwdEMB_SQL_CHECK(CONNECT TO TPLX)

else

printf (nUSAGE cursor [userid passwd]nn)return 1

endif

EXEC SQL DECLARE c1 CURSOR FORselect deptname name salary + ifnull(comm0) as compensationfrom org o staff swhere odeptnumb = sdeptorder by deptname compensation desc

EXEC SQL OPEN c1EMB_SQL_CHECK(OPEN CURSOR)

printf(DEPARTMENT NAME COMPENSn)printf(-----------------------------------n)do

EXEC SQL FETCH c1 INTO dname pname compif (SQLCODE = 0) breakprintf( -1515s -1010s 72fn dname pname comp )

while ( 1 )

EXEC SQL CLOSE c1EMB_SQL_CHECK(CLOSE CURSOR)

EXEC SQL CONNECT RESETEMB_SQL_CHECK(CONNECT RESET)

exit(0)

end of program CURSORSJSQC

int SqlInfoPrint( char appMsgstruct sqlca pSqlcaint linechar file )

int rc = 0char sqlInfo[1024]char sqlInfoToken[1024]char sqlstateMsg[1024]char errorMsg[1024]

if (pSqlca-gtsqlcode = 0 ampamp pSqlca-gtsqlcode = 100)

49

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

strcpy(sqlInfo )if( pSqlca-gtsqlcode lt 0) sprintf( sqlInfoToken n---- error report ----n)

strcat( sqlInfo sqlInfoToken)else sprintf( sqlInfoToken n---- warning report ----n)

strcat( sqlInfo sqlInfoToken) endif

sprintf( sqlInfoToken app message = sn appMsg)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken line = dn line)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken file = sn file)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken SQLCODE = ldn pSqlca-gtsqlcode)strcat( sqlInfo sqlInfoToken)

get error message rc = sqlaintp( errorMsg 1024 80 pSqlca) return code is the length of the errorMsg string if( rc gt 0) sprintf( sqlInfoToken sn errorMsg)

strcat( sqlInfo sqlInfoToken)

get SQLSTATE message rc = sqlogstt( sqlstateMsg 1024 80 pSqlca-gtsqlstate)if (rc == 0) sprintf( sqlInfoToken sn sqlstateMsg)

strcat( sqlInfo sqlInfoToken)

if( pSqlca-gtsqlcode lt 0) sprintf( sqlInfoToken --- end error report ---n)

strcat( sqlInfo sqlInfoToken)printf(s sqlInfo)return 1

else sprintf( sqlInfoToken --- end warning report ---n)

strcat( sqlInfo sqlInfoToken)printf(s sqlInfo)return 0

endif endif

return 0

void TransRollback( ) struct sqlca sqlca

int rc = 0 rollback the transaction printf( nRolling back the transaction n)

EXEC SQL ROLLBACKrc = SqlInfoPrint( ROLLBACK ampsqlca __LINE__ __FILE__)if( rc == 0) printf( The transaction was rolled backn)

50

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

51

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix C mdash Source Listing of testclicpp

Include The Appropriate Header Filesinclude ltsqlclihgtinclude ltsqlcli1hgtinclude ltsqlutilhgtinclude ltsqlenvhgtinclude ltstdiohgt include ltiostreamgt include ltlocalehgt include ltstringhgtdefine SQL_SQLSTATE_SIZE 5define LOOPS 8

using namespace std

Define The CLI_Class Classclass CLI_Class

Attributespublic

SQLHANDLE EnvHandleSQLHANDLE ConHandleSQLHANDLE StmtHandleSQLRETURN rcSQLCHAR Job[6]SQLCHAR Name[10]SQLDOUBLE Comp

Operationspublic

CLI_Class()~CLI_Class()SQLRETURN ShowResults()

Constructor Destructor

SQLRETURN printError( SQLHDBC SQLHSTMT)

Define The Class ConstructorCLI_ClassCLI_Class()

setlocale( LC_ALL )

Initialize The Return Code Variablerc = SQL_SUCCESS

Allocate An Environment Handlerc = SQLAllocHandle(SQL_HANDLE_ENV SQL_NULL_HANDLE ampEnvHandle)

Allocate A Connection Handleif (rc == SQL_SUCCESS)

rc = SQLAllocHandle(SQL_HANDLE_DBC EnvHandle ampConHandle)

Define The Class DestructorCLI_Class~CLI_Class()

Free The Connection Handleif (ConHandle = NULL)

SQLFreeHandle(SQL_HANDLE_DBC ConHandle)

Free The Environment Handle

52

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

if (EnvHandle = NULL)SQLFreeHandle(SQL_HANDLE_ENV EnvHandle)

Define The ShowResults() Member FunctionSQLRETURN CLI_ClassShowResults(void)

While There Are Records In The Result Data Set Generated Retrieve And Display Themcout ltlt Name Job Compensation ltlt endlcout ltlt --------- ------ ------------ ltlt endlcoutsetf(iosleft)coutprecision(2)coutsetf(iosfixed)while (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)

rc = SQLFetch(StmtHandle)if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)

coutwidth(15)cout ltlt Name

coutwidth(10)cout ltlt Job

coutwidth(7)cout ltlt Comp ltltendl

if(rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO ampamp rc = SQL_NO_DATA)printError(ConHandle StmtHandle)

else

rc = 0SQLCloseCursor(StmtHandle)

Return The ODBC API Return Code To The Calling Functionreturn(rc)

SQLRETURN CLI_ClassprintError (SQLHDBC hdbc

SQLHSTMT hstmt)

SQLCHAR buffer[SQL_MAX_MESSAGE_LENGTH + 1]SQLCHAR sqlstate[SQL_SQLSTATE_SIZE + 1]SQLINTEGER sqlcodeSQLSMALLINT lengthSQLRETURN rcwhile ((rc = SQLError(SQL_NULL_HENV hdbc hstmt

sqlstateampsqlcodebufferSQL_MAX_MESSAGE_LENGTH + 1amplength)) == SQL_SUCCESS || rc ==

SQL_SUCCESS_WITH_INFO)

cout ltlt SQLSTATE ltlt sqlstate ltlt endlcout ltlt SQLCODE ltlt sqlcode ltlt endlcout ltlt Error msg ltlt buffer ltlt endl

53

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

cout ltlt----------------------------- ltlt endl ltlt endl

return(SQL_ERROR)

----------------------------------------------------------------- The Main Function -----------------------------------------------------------------int main()

Declare The Local Memory Variables

(SQLCHAR ) db2user SQL_NTS (SQLCHAR ) test26t SQL_NTS)

SQLRETURNSQLCHARSQLCHARSQLCHARchar

SQLCHAR

rc = SQL_SUCCESSDBName[10] = TPLXSQLStmt[255]c[10]ptrcurrentDepartment[8][15] = Head Office

New England Mid Atlantic South Atlantic Great Lakes PlainsPacificMountain

Create An Instance Of The CLI_Class ClassCLI_Class Example

Connect To iSeries Database if (ExampleConHandle = NULL)

rc = SQLConnect(ExampleConHandle DBName SQL_NTS

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)ExampleprintError(ExampleConHandle SQL_NULL_HSTMT)

return(rc)

cout ltlt Successfully connected to ltlt DBName ltlt ltlt endlrc = SQLSetConnectAttr(ExampleConHandle SQL_ATTR_AUTOCOMMIT

(SQLPOINTER) SQL_AUTOCOMMIT_OFF SQL_IS_UINTEGER) Allocate An SQL Statement Handlerc = SQLAllocHandle(SQL_HANDLE_STMT ExampleConHandle

ampExampleStmtHandle)if (rc == SQL_SUCCESS)

Define A SELECT SQL Statement

strcpy((char ) SQLStmt select name job salary + ifnull(comm0) ascompensation )

ptr = strcat( (char ) SQLStmt from org o staff s )ptr = strcat( (char ) SQLStmt where odeptnumb = sdept)ptr = strcat( (char ) SQLStmt and deptname = )ptr = strcat( (char ) SQLStmt order by compensation desc)

Prepare The SQL Statementrc = SQLPrepare(ExampleStmtHandle SQLStmt SQL_NTS)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)ExampleprintError(ExampleConHandle ExampleStmtHandle)

54

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

return(rc)

Bind The Columns In The Result Data Set Returned To Application Variables

rc = SQLBindCol(ExampleStmtHandle 1 SQL_C_CHAR (SQLPOINTER)ExampleName sizeof(ExampleName) NULL)

rc = SQLBindCol(ExampleStmtHandle 2 SQL_C_CHAR (SQLPOINTER)ExampleJob sizeof(ExampleJob) NULL)

rc = SQLBindCol(ExampleStmtHandle 3 SQL_C_DOUBLE (SQLPOINTER)ampExampleComp sizeof(ExampleComp) NULL)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO) ExampleprintError(ExampleConHandle ExampleStmtHandle)

return(rc)

while (true)

for (int i = 0 i lt LOOPS i++)

rc=SQLBindParameter(ExampleStmtHandle1SQL_PARAM_INPUTSQL_C_CHARSQL_CHAR

150(SQLPOINTER) currentDepartment[i8]0NULL)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)

ExampleprintError(ExampleConHandle ExampleStmtHandle)return(rc)

rc = SQLExecute(ExampleStmtHandle)if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)

ExampleprintError(ExampleConHandle ExampleStmtHandle)return(rc)

cout ltlt endl ltlt Current Dept ltlt currentDepartment[i8] ltlt

endl Display The Results Of The SQL QueryExampleShowResults()if(rc = 0)break

if ( i500 == 0 ampamp i gt 0 )cout ltlt Loops ltlt i ltlt ltlt endl

cout ltlt AFTER ltlt LOOPS ltlt loops Press X to exit ltlt endlcin gtgt cif (c[0] == x || c[0] == X)

break

Free The SQL Statement Handleif (ExampleStmtHandle = NULL )

SQLFreeHandle(SQL_HANDLE_STMT ExampleStmtHandle) Disconnect From The Northwind Sample Databaserc = SQLDisconnect(ExampleConHandle)

Return To The Operating Systemreturn(rc)

55

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 5 Enabling the extended dynamic SQL through WebSphere Application Server console

The WebSphere Application Server needs to be restarted for the change to take effect The similar procedure can be followed to set other iSeries Data Source properties

Changing the WebSphere Application Server default isolation level

WebSphere Application Server V5 uses the REPEATABLE_READ (RR) isolation level for all implicit (WebSphere Application Server managed) transactions With the RR isolation level the rows selected updated deleted and inserted are locked until the end of the transaction Under certain circumstances this fairly extensive locking policy may cause locking contention especially when a WebSphere application competes for database resources with other applications that run on iSeries server For example a legacy order entry application may share data with the e-business customer care application running in WebSphere The locking contention may sometimes be eliminated by lowering the isolation level used by WebSphere Although the iSeries Data Source supports the custom transactionIsolation property resetting this property on the Data Source object will not change the default isolation level used by WebSphere for the connection objects produced by that Data Source In other words WebSphere will override the Data Source isolation level setting at the time the connection is obtained by a WebSphere application object such as servlet or Enterprise Java Bean (EJB) In order to change the default WebSphere behavior one must use the resource referencing Resource referencing allows a programmer to lookup DataSource or EJB objects using alias names rather than JNDI names Additionally by creating a resource reference a programmer can change certain properties of the underlying object Specifically a DataSource reference can be used to set a different isolation level for the connections produced by this database resource Typically resource references are defined by a programmer in a application development tool such as WebSphere Studio Application Developer The method to specify a DataSource reference differs depending on whether a programmer plans to use the reference in a servlet or in an EJB Letrsquos start with outlining the configuration process for a servlet In WebSphere Studio Application Developer open the deployment descriptor editor for the web project that contains the servlet To do so double click on the webxml file under WEB-INF directory in the web project In the deployment editor dialog select the References tab and then select Resource tab located in the top of the dialog that appears Under Resource References section select the Add button Herersquos an example of a DataSource reference created for iSeries DataSource named TestJDBCDS Note that the reference changes the default isolation level to READ_COMMITTED

13

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 6 Defining a resource reference for a servlet

Once the resource reference has been defined and saved the servlet source code needs to be changed to reflect the fact that a resource reference is used to obtain a DataSource from the JNDI service Herersquos the relevant code snippet try

ctx = new InitialContext() ds = (DataSource)ctxlookup(javacompenvTestJDBCJ2C)

catch (Exception e) eprintStackTrace(out)

Now the ds DataSource object will produce connections that by default run with the isolation level of READ_COMMITTED (RC)

As mentioned the process of defining a resource reference for an EJB differs from the process that is used in the case of a servlet In WebSphere Studio Application Developer open the deployment descriptor editor for the EJB project that contains the EJB To do so double click on the ejb-jarxml file under WEB-INF directory in the project In the deployment editor dialog select the References tab In the references section on the left locate and select the EJB for which the developer wants to change the default isolation level Click the Add button The Add Reference dialog opens Click the Resource Reference radio button and then Next Define the reference following the example shown in Figure 7

14

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 7 Adding a resource reference for an EJB

When you click ldquoFinishrdquo the reference definition is added to the EJB descriptor The new definition needs to be further modified To do so click on the (+) sign next to the EJB in the References list Click the new reference TestJDBCJ2C in this example to open the properties for the reference Change WebSphere Bindings and WebSphere Extensions sections as illustrated in Figure 8

15

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 8 Defining a resource reference for an EJB

Save the modified definition and then change the EJB source code to use the reference rather than directly DataSource

TroubleshootingTroubleshooting a multi-tier application may be a bit tricky because the developer needs to deal with software components that reside in separate partitions Three tools are particularly useful for pinning down the potential problem areas bull Joblog messages for a database server job mdash Provides enough details to isolate DB2 UDB for

iSeries runtime issues bull JDBC trace utility mdash Provides granular information about the data flow between the AIX

application and the iSeries server job bull Database Monitor ndash Provides detailed SQL runtime trace

Job Log MessagesAs mentioned a DB2 client communicates with a corresponding iSeries server job This server job runs the SQL requests on behalf of the client The iSeries database server jobs are called QZDASOINIT and they run in the QUSRWRK subsystem At any given time a large number of database server jobs may be active on the server so the first step is to identify the job that serves the particular client connection The easiest method to accomplish this task is to run the following CL command from the i5OS prompt

WRKOBJLCK OBJ(DB2USER) OBJTYPE(USRPRF)

Here DB2USER is the user profile that is used to connect to the iSeries server Note that a QZDASONIT job is assigned to a client after the connection has been established so the developer needs to set a breakpoint in the client application after the database connection has been established

Once the Work with Object Locks appears key in 5 (Work with Job) next to the only QZDASOINIT job that should be listed This shows the Work with Job dialog Select option 10 to

16

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

display the job log for the database server job Now the job log can be searched for any error messages generated by the DB2 runtime

Sometimes it is also useful to include debug messages in the job log The debug messages are informational messages written to the job log about the implementation of a query They describe query implementation methods such as the use of indexes join order ODP implementation (reusable versus non-reusable) and so on The easiest way to instruct an iSeries server to include the debug messages is to set the ServerTraceCategories property on the data source object

tkcpdssetServerTraceCategories(AS400JDBCDataSourceSERVER_TRACE_DEBUG_SERVER_JOB)

A sample of the job log messages with debug messages enabled is shown below

SET TRANSACTION completeSTATEMENT NAME FOUND QZ868F0A458E13AF8C Starting optimizer debug message for query Arrival sequence access was used for file COFFEESODP created ODP not deleted 5000 rows inserted in COFFEES in DB2USER STATEMENT NAME FOUND QZ868F0A4C144BF12EBlocking used for queryCursor CRSR0001 opened606 rows fetched from cursor CRSR0001 ODP not deleted Cursor CRSR0001 closed

So the job log offers fairly detailed information on how the AIX client requests were implemented by the DB2 runtime

JDBC Trace UtilityThe JTOpen driver provides a tracing utility which can be used to collect detailed client-side traces The JDBC tracing is turned off by default It can be enabled by setting the Trace property to true Heres an example of how to switch on tracing using the setTrace method on the data source object

tkcpdssetTrace(true)

The trace can also be enabled when using the DriverManagergetConnection() method for obtaining a connection to DB2 UDB for iSeries In this case the developer could add the trace property to the connection string This approach is illustrated in the following code snippet

ClassforName(comibmas400accessAS400JDBCDriver) [1] hellip con = DriverManagergetConnection(jdbcas400teraplextrace=true

db2userdb2pwd) [2]

At [1] an instance of the JTOpen JDBC Driver is initiated Then at [2] the driver is used to obtain a connection to the iSeries server Note how the trace property has been added to the database URL See the IBM Toolbox for Java JDBC properties documentation on the iSeries Information Center Web site for a complete list of properties supported by the JTOpen driver

Although the level of details provided by the trace utility is sufficient in most troubleshooting scenarios sometimes the developer may need to collect low-level traces scoped to a certain type

17

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

of information In V5R3 the IBM Toolbox for Java (as well as the latest JTOpen) added a comprehensive detailed trace facility The following is the complete list of detailed trace parameters and their purpose

bull None or ldquordquo ndash This setting disables the detailed trace bull datastream - This category is used by Toolbox classes to log dataflow between the local host

and the remote system It is not intended for use by application classes bull diagnostic - This category is used to log object state information bull error - This category is used to log errors that cause an exception bull information - This category is used to track the flow of control through the code bull warning - This category is used to log errors that are recoverable bull conversion - This category is used by Toolbox classes to log character set conversions

between Unicode and native code pages bull proxy - This category is used by Toolbox classes to log data flow between the client and the

proxy server bull pcml - This category is used to determine how PCML interprets the data that is sent to and

from the server bull jdbc - This category is used to track JDBC calls throughout the program bull thread - This category is used to enable tracing of thread information This is useful when

debugging multi-threaded applications bull all - This category will enable all previous categories

The detailed trace can be enabled when using the DriverManagergetConnection() method for obtaining a connection to DB2 UDB for iSeries In this case the developer could add the toolbox trace property to the connection string This is illustrated in the following code sample

String dbUrl = jdbcas400pwd1toolbox trace=diagnostic con = DriverManagergetConnection(dbUrl dbUser dbPassword)

Note that currently the driverrsquos DataSource interfaces do not allow the developer to directly activate the detailed tracing However they could set the server from the command line at the time the java program is launched The example below shows how the detailed trace properties could be enabled at the command line

java -Dcomibmas400accessTracecategory=diagnostic TestJDBC

The -D switch indicates to the java interpreter that the information following it will be a system property

In case of a WebSphere application the trace property can be set through the admin console In the console select Application Servers-gt server1-gt Process Definition -gt Java Virtual Machine Figure 9 shows how to set the Generic JVM Arguments for an application server instance

18

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 9 Setting JVM arguments to enable detailed Toolbox tracing

Database Monitor

The database monitor is the ultimate tool available on DB2 UDB for iSeries to collect low-level SQL traces It is mainly used to pin down the SQL performance problems Refer to the lsquoUsing iSeries Database Monitor to Identify and Tune SQL Queriesrsquo white paper for a detailed discussion on how to collect and analyze the database monitor traces httpibmcomserversenablesiteeducationiborecordhtmldtmon

IBM DB2 JDBC Universal Driver DB2 JDBC Universal Driver is one of the new features delivered with DB2 UDB Version 8 DB2 JDBC Universal Driver has been designed to eliminate the dependency on DB2 CLI runtime modules as well as to enable direct Type 4 connectivity to DB2 UDB for iSeries and DB2 UDB for zOSreg

The pure-Java (Type 4) remote connectivity is based on the DRDA open distributed protocol for cross-platform access to DB2 DRDA defines the rules the protocols and the semantics for accessing distributed data Applications can access data in a distributed relational environment by using SQL statements The iSeries DRDA application server implementation is based on multiple connection-oriented server jobs running in the QSYSWRK subsystem A DRDA listener job (QRWTLSTN) listens for TCP connect requests on port 446 Once an application requester connects to the listener job the listener wakes up one of the QRWTSRVR prestart jobs and assigns it to a given client connection Any further communication occurs directly between the client application and the QRWTSRVR job These concepts are illustrated in Figure 10

19

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 10 Accessing DB2 UDB for iSeries with DB2 Universal Driver

The DB2 Universal Driver can be loaded in an AIX partition by installing one of the DB2 Connect for AIX products (see the Additional Information section for details) It is also a part of a DB2 Enterprise Server Edition for AIX install Specifically the developer needs three JAR files in a AIX partition to successfully connect to an iSeries server db2jccjar db2jcc_license_cisuzjar and db2jcc_license_cujar The iSeries license is contained in db2jcc_license_cisuzjar Note that this file is not a part of DB2 Client In other words a DB2 Connect license is required to use the driver in production environments The location of the JAR files needs to be added to the CLASSPATH environment variable For instance the following entry could be added to the AIX profile script

CLASSPATH=homedb2inst2sqllibjavadb2jccjarCLASSPATH=$CLASSPATHhomedb2inst2sqllibjavadb2jcc_license_cujarCLASSPATH=$CLASSPATHhomedb2inst2sqllibjavadb2jcc_license_cisuzjarexport CLASSPATH

Java Runtime 131 is a prerequisite

Additionally the developer should install the latest database group PTF (SF99503 for i5OS V5R3) on the iSeries server The Informational APAR ii13348 is keeping track of any fixes relevant to DRDA above and beyond the current database group PTF

Obtaining a Connection to DB2 UDB for iSeries When Type 4 connectivity is used the DB2 Universal Driver connects directly to the DB2 on iSeries through TCPIP Note that this is different from the legacy DB2 Type 2 JDBC driver that requires a DB2 node and remote database configurations on the client accessing iSeries The following code snippet illustrates how to use the DB2 JDBC Universal Driver to obtain a connection to DB2 UDB for iSeries

20

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

try ClassforName(comibmdb2jccDB2Driver) [1] catch(javalangClassNotFoundException e) Systemerrprint(ClassNotFoundException )Systemerrprintln(egetMessage())

try DriverManagergetConnection(jdbcdb2teraplex446TERAPLEX[2]

db2userdb2pwd) hellip catch(SQLException ex) Systemerrprintln(

SQLException + exgetMessage())

At [1] an instance of the DB2 JDBC Universal Driver is instantiated Then at [2] the driver is used to obtain a connection to the iSeries server Note the proper form of the database URL required by the driver

Considerations There are several advantages of DB2 JDBC Universal Driver bull Ease of cross-platform development mdash Consistent coding techniques and consistent error

codes and messages bull Ease of deployment mdash Pure Java (no runtime client required) and a single driver for accessing

DB2 on different platforms

The ease of use comes at a price though The iSeries JTOpen driver is optimized for accessing DB2 UDB for iSeries data and it uses native iSeries protocol to communicate with the back-end database server job This usually results in better performance and more-efficient system resources utilization For instance when using the DB2 JDBC Universal Driver to access an iSeries server the executeBatch method results in a single record insert There are also some restrictions when using DB2 Universal JDBC Driver with Type 4 connectivity

bull Support for distributed transactions (JTA) is not enabled bull Driver built-in connection pooling is not supported

Refer to Java application support in DB2 for more details on DB2 JDBC Universal Driver

21

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 Connect data access This section will explore the most important aspects of DB2 Connect ndash iSeries integration - including configuration tips and coding examples

DB2 Connect provides functionality for accessing data stored in DB2 UDB for iSeries as well as DB2 UDB for zOS and DB2 UDB for OS390reg DB2 Connect offers capabilities to access DB2 family members via several SQL interfaces gateway functions such as connection pooling and federated database functionality Many applications supporting the DB2 family of products leverage DB2 Connect as a key middleware component DB2 Connect is offered as separate AIX license products

Enterprise Edition Application Server Edition

In addition to DB2 Connect there are several other DB2 UDB Version 81 products that are supported on AIX

DB2 Universal Database Enterprise Server Edition DB2 Universal Database Workgroup Server Unlimited Edition DB2 Universal Database Workgroup Server Edition DB2 Universal Database Universal Developers Edition All Clients

The DB2 Connect Enterprise Edition functionality is also contained in DB2 Enterprise Server Edition for AIX

22

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 Connect in a nutshell In the scenario described in this paper the DB2 Connect functions contained in DB2 Enterprise Edition for AIX are utilized DB2 Connect Enterprise Edition provides support for both local and remote DB2 clients This is illustrated in Figure 11 Accessing DB2 UDB for iSeries with DB2 Connect

Figure 11 Accessing DB2 UDB for iSeries with DB2 Connect

DB2 Connect implements the Distributed Relational Database Architecturetrade (DRDAreg) to reduce the cost and complexity of accessing data stored in DB2 UDB for iSeries and other DRDA-compliant database servers DRDA defines the rules the protocols and the semantics for accessing distributed data Applications can access data in a distributed relational environment by using SQL statements In a distributed environment the system running the application and sending the SQL requests across the network is called the application requester (AR) A remote database server that executes SQL requests submitted by an application requester is known as the application server (AS) In the example shown in Figure 11 (above) DB2 Connect plays the role of an application requester while DB2 UDB for iSeries is an application server In this case DB2 Connect communicates with the iSeries database through TCPIP The iSeries DRDA application server implementation is based on multiple connection-oriented server jobs running in the QSYSWRK subsystem A DRDA listener job (QRWTLSTN) listens for TCP connect requests on port 446 Once an application requester connects to the listener job the listener wakes up one of the QRWTSRVR prestart jobs and assigns it to a given client connection Any further communication occurs directly between the client application and the QRWTSRVR job

DB2 Connect supports a wide range of programming interfaces that can be used by AIX applications to access the iSeries database Embedded SQL frac34 Both static and dynamic SQL frac34 Various programming languages (Java CC++ Cobol Fortran REXX)

DB2 Call Level Interface (DB2 CLI) ODBC JDBC frac34 DB2 JDBC Type 2 Driver frac34 DB2 JDBC Type 4 Driver (Universal JDBC Driver)

23

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Note that DB2 Connect supports access to DB2 UDB for iSeries through DB2 JDBC Universal driver However for performance and ease of maintenance reasons IBM recommends that Java applications running in AIX use native iSeries Toolbox JDBC driver See the JDBC Data Access section of this paper (above) for more details On the other hand DB2 Connect is a very efficient and robust connectivity option for AIX applications especially in the environments that are not directly supported by the native iSeries JDBC driver Here are several possible scenarios that would require DB2 Connect installed in a AIX partition

Embedded SQL interface is used to access DB2 CLI or ODBC interface is used to access DB2 A single SQL interface is needed to access multiple back end DB2 server Specific DB2 Connect functionality is needed such as distributed join or connection

pooling

Prerequisites One of the DB2 Connect products or DB2 Enterprise Server Edition for AIX V81 is needed Additionally DB2 Application Development Client is required in the AIX partition to compile DB2 applications

For maximum database server stability the developer should install the latest database group PTF (SF99503 for i5OS V5R3) on the iSeries server The Informational APAR ii13348 is keeping track of any fixes relevant to DRDA above and beyond the current database group PTF

DB2 Connect configuration The following example employs i5OS V5R3 and DB2 UDB Enterprise Server Edition for AIX Version 81 FixPak 6

Configuration steps in the iSeries partition The following process lists the necessary steps to be performed on the iSeries server 1) Verify that the TCPIP stack is working correctly It is assumed that the Virtual LAN is used to

communicate with the i5OS partition First obtain the IP address of the iSeries server or its hostname and ping the iSeries server from the AIX partition

2) Create a relational database (RDB) entry for the iSeries database in the i5OS partition If this has already been created it can be displayed by using the DSPRDBDIRE command Make sure that the RDB entry with a location of LOCAL exists on the iSeries server If it does not exist use the ADDRDBDIRE command to add the appropriate RDB entry For example the following command would add an RDB entry named TPLX For simplicity it is recommended that the TCPIP host name and RDB entry remain the same

ADDRDBDIRE RDB(TPLX) RMTLOCNAME(LOCAL)

3) Create a collection called NULLID This is necessary because the utilities shipped with DB2 Connect and DB2 UDB for AIX store their packages in the NULLID collection Since it does not exist by default in the iSeries server you must create it using the following command

CRTLIB LIB(NULLID)

4) Products that support DRDA automatically perform any necessary code page conversions at the receiving system For this to happen both systems need a translation table from their code page to the partner code page The default Coded Character Set Identifier (CCSID) on the iSeries server is 65535 Since DB2 Connect does not have a translation table for this code page the developer needs to change the individual user profiles to contain a CCSID that can be converted properly by DB2 Connect For US English this is 037 For other languages see DB2 Connect Personal Edition Quick Beginning GC09-2967 The following command changes the CCSID for an individual user profile to 037

24

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

CHGUSRPRF userid CCSID(037)

5) Verify that the default port 446 for DRDA service is being used To do this go to the Configure TCPIP menu (CFGTCP) select Configure Related Tables and then select Work with service table entries Verify that the DRDA service is set for port 446

6) The Distributed Data Management (DDM) job must be started for DRDA to work If you want the DDM job to be automatically started whenever TCPIP is started change the attributes of the DDM job using the CHGDDMTCPA command and set the Autostart server parameter to YES

7) If the system administrator chooses not to autostart the server issue the following command to start the DDM server job

STRTCPSVR SERVER(DDM)

8) Make sure that the user profiles that will be used to connect to the iSeries server exist on the server

25

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Configuration steps in the AIX partition The following steps are required for DB2 Connect to be configured in the AIX partition 1) Sign on to the AIX partition as the DB2 administrator 2) Launch Client Configuration Assistant (db2ca from the command prompt) It is assumed that

VNC or an X-Windows server are being used on the workstation so that the db2ca GUI can be properly rendered

3) From the Selected pull-down menu select the Add Database using Wizard option The Select how you want to setup a connection dialog appears Select Manually configure a connection to a database and click Next This is shown in Figure 12

Figure 12 Accessing DB2 UDB for iSeries with DB2 Connect

26

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

4) On the Select a communications protocol choose TCPIP and select The database physical resides on a host or OS400 system Then select the option Connect directly to the server as shown in Figure 13 Click Next

Figure 13 mdash Selecting communications protocol

27

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

5) On the TCPIP tab fill in the host name of the iSeries server The port number should be 446 This is shown in Figure 14 Click Next

Figure 14 mdash Specifying TCPIP communication parameters

28

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

6) On the Database tab fill in the Relational Database name Use the RDB entry name (specified in step 2) in the Configuration steps in the iSeries partition section as shown in Figure 15 Click Next

Figure 15 mdash Specifying the remote database

7) If you plan to use the ODBC applications select Register this database for ODBC as a system data source on the ODBC tab Click Next

29

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

8) On the Specify the node option dialog select OS400 from the Operating System pull-down menu This is shown in Figure 16 Click Finish

Figure 16 mdash Specifying the node options

30

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

9) The Test Connection dialog appears This allows the developer to verify that the connection works Select both CLI and JDBC check boxes You are also prompted for an iSeries user ID and password as shown in Figure 17

Figure 17 mdash Testing the connection

31

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

10) The successful connection to the database server is confirmed by the message box shown in Figure 18

Figure 18 mdash Test Connection results 11) At this time a newly configured database connection should appear in the main DB2

Configuration Assistant window It is recommended that the DB2 utilities are also bound to the iSeries database The bind process creates the necessary SQL packages on the remote database In the main Configuration Assistant window click the TPLX database entry and then select Selected-gtBindhellip

32

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

12) The Bind dialog appears Click Select All and then enter the connection information as shown in Figure 19 Click Bind The Results message box appears This allows the developer to monitor the progress of the binding process Watch for any error and warning messages

Figure 19 mdash Binding the DB2 utilities This concludes the DB2 Connect configuration steps

33

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Accessing DB2 UDB for iSeries from C embedded SQL

As mentioned earlier DB2 Connect allows developers to compile and run embedded SQL applications that access DB2 UDB for iSeries data This section covers implementation details for a C embedded SQL application called cursorsjsqc (see Appendix B for source code)

Prerequisites An embedded SQL application running in an AIX partition will use DB2 Connect services to access DB2 UDB for iSeries therefore the developer needs to make sure that all components listed in section Prerequisites on page 24 are installed The developer also needs to create a remote database connection as described in the DB2 Connect configuration section of this paper on page 24

Static SQL and SQL packages To successfully run against a DB2 UDB for iSeries database an embedded SQL application needs to be first precompiled and bound to the back-end database This process creates an SQL package on the target iSeries server The SQL package contains the access plan information for the SQL statements executed by the application The internal structure of the package as well as the method how its content is used by the SQL runtime to facilitate the access plan reuse is similar to the Extended Dynamic SQL support covered in detail in the Extended Dynamic SQL and Statement Caching section of this paper (on page 9) There are however important differences between the packages created by the extended dynamic SQL support and the packages created for embedded SQL DRDA client applications The extended dynamic SQL packages support dynamic SQL interfaces such as JDBC

that can submit ad hoc SQL statements at the run time The SQL runtime can prepare the dynamic statements and add them to the package On the other hand the DRDA packages are created at the precompile time and contain static SQL In order to add new statements to the package the application needs to be precompiled and rebound again

The extended dynamic SQL package can dynamically grow up to 500MB by allocating new space as required The DRDA packages since they are created at the precompile time have a fix size and do not grow over their life time

Simple embedded SQL application The application is based on a source code provided in the DB2 UDB samples directory typically to be found at homedb2inst1sqllibsamples The cursorsjsqc performs a join between STAFF and ORG tables located in DB2USER schema (library) on the TPLX database server (the source is provided at the end of this paper in Appendix B) The join statement retrieves the DEPTNAME column from ORG NAME column from STAFF and calculates the total compensation for an employee by adding SALARY and COMM columns in STAFF The results are sorted by department name and total compensation Here is the SELECT statement used by the application

SELECT deptname name salary + IFNULL(comm0) as compensationFROM org o staff sWHERE odeptnumb = sdeptORDER BY deptname compensation DESC

The application iterates through the selected records and prints out the data to the standard output device The sample DB2USER schema was created with the following SQL statements

db2 CONNECT TO tplx USER db2user USING mypassworddb2 CALL QSYSCREATE_SQL_SAMPLE(DB2USER)

34

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Make sure that the AIX partition is logged into with the DB2 admin user profile If the defaults were selected at the DB2 installation time this profile name is db2inst1 It is also assumed that DB2USER user exists on the iSeries server and that it has appropriate authority

There are several steps that are required to create an executable for the cursorsjsqc source code First the DB2 PRECOMPILE utility needs to be called The utility creates a bind file that is used to bind the required SQL package to the TPLX database It also converts embedded SQL statements into DB2 run-time API calls and produces a pure C source file that can be processed by an AIX C compiler

db2 CONNECT TO tplx USER db2user USING mypassworddb2 prep cursorsjsqc bindfile

Note that the connect statement is required only if the developer is not already connected to the database on an iSeries server Watch for any error or warning messages returned by the DB2 prep utility The prepare step should produce cursorsjbnd and cursorsjc files in the current directory Now the developer can invoke the bind utility to prepare the statements contained in the bind file and create the package on the target iSeries database server

db2 bind cursorsjbnd

It is assumed that Visual C++ 60 is installed and configured in the AIX partition Refer to the ldquoDeveloping and Porting C and C++ Applications on AIXrdquo redbook for more information on how to use the Visual C++ compiler httpibmcomredbooksabstractssg245674htmlOpen

Use the following commands to compile the C source generated by the precompile utility

xlc -I$INSTHOMEsqllibinclude ndashc cursorsjcxlc ndasho cursorsj cursorsjo -L$INSTHOMEsqlliblib ndashldb2

Run the program from the AIX prompt

cursorsj db2user mypassword

Distributed Join DB2 UDB Version 8 provides core federated server functionality A federated system consists of a DB2 UDB instance that operates as a federated server a database that acts as the federated database one or more data sources and clients (users and applications) that access the database and data sources Federated server permits objects stored in multiple databases to be accessed together in the same query For example a query can refer to a table that resides in DB2 UDB for iSeries and join it to a table stored in DB2 UDB for AIX Such a query would constitute so called distributed join The support for DB2 UDB for iSeries as a federated data source is provided by core federated server functionality directly implemented in DB2 UDB Enterprise Server Edition and DB2 UDB Connect Enterprise Edition All other DB2 UDB family members are also supported directly by core DB2 UDB federated server An additional software product DB2 Information Integratortrade is required to access non-DB2 UDB databases such as Oracle Sybase or Microsoftreg SQL Server Consult the following white papers for a detailed discussion on DB2 federated server support Heterogeneous data access for iSeries applications Version 2 httpibmcomserversenablesiteeducationiborecordhtmlhetdata Fundamentals of IBM DB2 Federated Server and Relational Connect httpwww7bsoftwareibmcomdmddlibrarytecharticle0206purnell0206purnellhtml

35

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Distributed Join Example In this section the steps that are required to configure DB2 UDB for iSeries as a federated data source will be illustrated Then the cursorsjsqc program will be ldquotweakedrdquo so that it executes a distributed join query that accesses data stored on an iSeries server and in the local DB2 UDB for AIX database It is assumed that the developer is familiar with the DB2 federated server concepts

Note Run the following commands from the Command Line Processor prompt Load the utility by executing the db2 command at the AIX prompt 1) First the local DB2 UDB for AIX instance needs to be enabled as a DB2 federated server

This is done by setting the database manager configuration parameter FEDERATED to YES

db2=gt update dbm cfg using FEDERATED YES

The database instance needs to be restarted for the change to take effect

NOTE A federated database is a regular database in a DB2 UDB instance that has the FEDERATED parameter enabled Therefore in this example the SAMPLE database that was created earlier is used as the federated database A new database can also be created using the CREATE DATABASE command

2) Connect to the federated database

db2=gt connect to sample

3) Use the CREATE WRAPPER statement to register a wrapper for the iSeries data source Wrappers are library routines that are used by the federated server to perform operations such as connecting to a data source and retrieving data from it The default wrapper name for DB2 UDB for iSeries is DRDA Here is the command to register the DRDA wrapper

db2=gt create wrapper drda

4) Use the CREATE SERVER statement to register a data source as a server within the federated database The server definition specifies the type and version of the data source and the wrapper used for communications with this data source For the DB2 UDB for iSeries data source the node and the database names are also needed The node and database name parameters have been configured for our TPLX database in the Configuration steps in the AIX partition section (on page 24) Use the following DB2 UDB command to lookup these parameter on the federated server

db2=gt list database directory

In this case the command produced the following output

Database alias = TPLX Database name = DCSE99E1 Node name = NDE9BF76 Database release level = a00 Comment = Directory entry type = Remote Authentication = SERVER Catalog database partition number = -1

36

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Note that the node name is set to NDE9BF76 The name was generated by the Configuration Administrator utility (db2ca)

Here is the command to register the TPLX database as a federated server

db2=gt create server tplx type db2400 version 530 wrapperdrda authorization db2user password mypassword options(nodeNDE9BF76 dbname TPLX)

The command is quite complex so make sure that the syntax is correct

5) Define the user mappings that instructs the federated server what user ID and password should be used when connecting to the iSeries data source

db2=gt create user mapping for user server tplxoptions(remote_authid db2user remote_password mypassword)

Specify the nickname for the iSeries table or view A nickname is an identifier that is used by the federated server to reference an object located at the data source The following command creates a nickname for the STAFF table located in the DB2USER schema on the TPLX database

db2=gt create nickname tplx_staff for tplxdb2userstaff

6) Test the distributed join query

db2=gt SELECT deptname name salary + COALESCE(comm0) ascompensation FROM org o tplx_staff s WHERE odeptnumb =sdept ORDER BY deptname compensation DESC

Note that the native iSeries function IFNULL has been substituted with an equivalent DB2 UDB function COALESCE COALESCE is also supported on iSeries servers For better portability IBM encourages the use of COALESCE rather than IFNULL Note also that the query runs on the federated server rather than on TPLX It accesses the ORG table in the local DB2 UDB for AIX SAMPLE database and the STAFF table that resides in TPLX The federated server performs the necessary distributed join

7) Modify the cursorsjsqc so that it executes a distributed join There are two source code modifications - Change the CONNECT TO statements Now the application needs to connect to the

federated database SAMPLE rather than to TPLX

EXEC SQL CONNECT TO SAMPLEEXEC SQL CONNECT TO SAMPLE USER userid USING passwd

- Modify the select statement so that it performs a distributed join Use the statement (shown in step 6) above Save the new source version as cursordjsqc

- Prepare bind and compile the distributed join version of the program as described in the Simple C embedded SQL application section (on page 34)

db2 prep cursordjsqc bindfiledb2 bind cursordjbndxlc -I$INSTHOMEsqllibinclude ndashc cursordjcxlc ndasho cursordj cursordjo -L$INSTHOMEsqlliblib ndashldb2

37

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

- Run the program from the AIX prompt

cursordj

Connection Pooling and Connection ConcentratorA modern Web-based application typically executes a large number of short-lived transactions Executing a transaction in this environment means establishing a database connection executing a few SQL statements and terminating this connection Creating connections to the database server is a very costly process To reduce the unnecessary workload DB2 Connect implements connection pooling and connection concentrator Connection pooling mechanism allows DB2 Connect to reuse an existing connection infrastructure for subsequent connection requests The connection concentrator is an advanced technology that allows DB2 Connect to serve a potentially very large number of clients with a limited number of database connections This is accomplished by decoupling clients from a particular database connection

Note that currently neither connection pooling nor connection concentrator support DB2 UDB for iSeries Therefore for performance reasons the author strongly recommends that the application server that obtains and drops connections very frequently implements its own database connection pooling mechanism that would assign an existing pooled database connection to a new AIX process or thread

TroubleshootingTroubleshooting a multi-tier application may be a bit tricky because the developer needs to deal with software components that reside in separate partitions The authorrsquos experience shows that two tools are particularly useful for pinning down the potential problem areas The joblog messages for a database server job usually provide enough details to isolate DB2

UDB for iSeries runtime issues The DRDA trace utility provides granular information about the data flow between the AIX

application and the iSeries server job

38

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Job Log MessagesAs mentioned earlier a DB2 client communicates with a corresponding iSeries server job This server job runs the SQL requests on behalf of the client More precisely when a DB2 client submits an SQL statement the statement is passed to a server job that in turn calls the DB2 runtime to execute the statement The results are then reformatted and marshaled to the client The iSeries DRDA server jobs are called QRWTSRVR and they run in the QUSRWRK subsystem At any given time there may be a large number of DRDA server jobs active on the system so the first step is to identify the job that serves the particular client connection The easiest method to accomplish this task is to run the following CL command from the i5OS prompt

WRKOBJLCK OBJ(DB2USER) OBJTYPE(USRPRF)

Here DB2USER is the user profile that is used to connect to the iSeries server Note that a QRWTSRVR job is assigned to a client after the connection has been established so the developer needs to set a breakpoint in the client application below the CONNECT TO statement

Once the Work with Object Locks appears key in 5 (Work with Job) next to the only QRWTSRVR job that should be listed This shows the Work with Job dialog Select option 10 to display the job log for the database server job Now the developer can search the job log for any error messages generated by the DB2 runtime

Sometimes it is also useful to include debug messages in the job log The debug messages are informational messages written to the job log about the implementation of a query They describe query implementation methods such as use of indexes join order ODP implementation (reusable versus non-reusable) and so on The easiest way to instruct the iSeries server to include the debug messages is to call the following stored procedure just after the connection to the iSeries server is established

EXEC SQL call qsysqcmdexc(STRDBGUPDPROD(YES)000000002000000)

A sample of the job log messages with debug messages enabled is shown below in Figure 20

Arrival sequence access was used for file STAFFAccess path suggestion for file STAFFQuery options used to build the OS400 query access plan Ending debug message for query ODP created Blocking used for queryCursor SQLCUR201 opened1 rows fetched from cursor SQLCUR201Row not found for SQLCUR201ODP deleted Cursor SQLCUR201 closedDESCRIBE of prepared statement STMT0201 completed

Figure 20 mdash Joblog with debug messages enabled

So the job log offers fairly detailed information on how the AIX client requests were implemented by the DB2 runtime

39

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 DRDA trace utilityThe DB2 DRDA trace utility (db2drdat) provides detailed information about the data streams exchanged between DB2 Connect and target database server The output file produced by the utility contains send and receive communications buffers TCPIP error messages and SQL Communications Area (SQLCA) information Please refer to lsquoDB2 Connect Userrsquos Guidersquo manual for in-depth discussion of the DRDA trace utility

Accessing DB2 UDB for iSeries from CLI DB2 Call Level Interface (CLI ) is based on the Microsoft Open Database Connectivity (ODBC) specification and the ISO CLI standard The DB2 CLI interface gained popularity among DB2 application providers because the developer can build an ODBC application by simply linking the application with libdb2 library on a UNIX server In other words the developer directly utilizes the DB2 ODBC driver services without a need for an ODBC driver manager Additionally in contrast to embedded SQL the developer does not need to precompile or bind DB2 CLI applications because they use packages provided with DB2 UDB The developer simply compiles and links the application

Prerequisites A DB2 CLI application running in an AIX partition will use DB2 Connect services to access DB2 UDB for iSeries therefore make sure that all components listed in Prerequisites section of this paper on page 24 are installed The developer also needs to create a remote database connection as described in the DB2 Connect configuration section of this paper on page 24

Dynamic SQL and Access Plan Caching A DB2 CLI client application uses the dynamic SQL interface and does not have the capability to utilize the extended dynamic SQL support Therefore it runs lsquopurersquo dynamic SQL statements That does not mean however that the process of parsing validating and optimizing will be repeated for every execution of a given dynamic SQL statement

The DB2 UDB for iSeries database implements an internal object called System-Wide SQL Statement Cache (SWSC) The SWSC can improve the performance of programs using dynamic SQL statements by caching the access plans in a system-wide cache When a dynamic SQL statement is submitted the SQL runtime searches the SWSC to see if this statement has been previously executed If so then DB2 retrieves and reuses the key information associated with the cached statement and thereby the processing time and the resources utilization can be significantly reduced

Simple DB2 CLI C++ ApplicationThis section covers DB2 CLI implementation details for a sample C++ program called testclicpp (the source is provided at the end of this paper in Appendix C) To compile the source with Visual C++ complier use the following command in the AIX partition

xlC ndashI$INSTHOMEsqllibinclude ndashc testclicppxlC ndasho testcli testclio ndashL$INSTHOMEsqlliblib ndashldb2

The application performs a join between STAFF and ORG tables located in DB2USER schema (library) The join statement retrieves the DEPTNAME column from ORG NAME and JOB columns from STAFF and calculates the total compensation for an employee by adding SALARY and COMM columns in STAFF The results are sorted by total compensation The selection criterion is based on the current value of the department name parameter Here is the SELECT statement used by testcli

40

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

select name job salary + coalesce(comm0) as compensationfrom org o staff swhere odeptnumb = sdeptand deptname = order by compensation desc

Figure 21 shows the software components involved in the execution of this sample application

Figure 21 How a DB2 CLI client accesses DB2 UDB on an iSeries server

Although the testcli application is fairly simple it covers some important aspects of efficient CLI programming for DB2 UDB for iSeries

Reusable Open Data Paths (ODPs)An Open Data Path (ODP) definition is an internal i5OS object that is created when certain SQL statements (such as OPEN INSERT UPDATE and DELETE) are executed for the first time in a given job (or connection) The ODP can be thought of as a runtime implementation of an access plan The access plan created at the optimization time provides a recipe or in other words a sequence of steps necessary to execute the statement The ODP on the other hand provides the executable code for all requested IO operations The process of creating new ODP objects is fairly CPU- and IO-intensive so whenever possible the iSeries DB2 runtime tries to reuse existing ODPs For instance a SQLCloseCursor() API call may close the SQL cursor but leave the ODP available to be used the next time the cursor is opened This can significantly reduce the processing and response time in running SQL statements A reusable OPD usually requires 10 to 20 times less CPU resources than a newly created ODP Therefore it is important that the applications employ programming techniques that allow the DB2 runtime to reuse ODPs

With dynamic interfaces such as CLI full opens are avoided by using a prepare once execute many programming paradigm It means that when an SQL statement is going to be executed more than once you should prepare the statement just once and then reuse the prepared

41

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

statements for consecutive executions Although DB2 UDB does try to convert literals to parameter markers so that similar statements can be reused it is a better programming practice to explicitly implement parameter markers That way the chances for reusable ODPs are quite significantly improved The code snippet in Figure 22 illustrates how to implement the prepare once execute many programming technique

Define A SELECT SQL Statementstrcpy((char ) SQLStmt select name job salary + ifnull(comm0) ascompensation )ptr = strcat( (char ) SQLStmt from org o staff s )ptr = strcat( (char ) SQLStmt where odeptnumb = sdept)ptr = strcat( (char ) SQLStmt and deptname = )ptr = strcat( (char ) SQLStmt order by compensation desc) [1]

Prepare The SQL Statementrc = SQLPrepare(ExampleStmtHandle SQLStmt SQL_NTS) [2]

Bind The Columns In The Result Data Set Returned To Application Variablesrc = SQLBindCol(ExampleStmtHandle 1 SQL_C_CHAR (SQLPOINTER)

ExampleName sizeof(ExampleName) NULL)rc = SQLBindCol(ExampleStmtHandle 2 SQL_C_CHAR (SQLPOINTER)

ExampleJob sizeof(ExampleJob) NULL)rc = SQLBindCol(ExampleStmtHandle 3 SQL_C_DOUBLE (SQLPOINTER)

ampExampleComp sizeof(ExampleComp) NULL)

for (int i = 0 i lt LOOPS i++)rc=SQLBindParameter(ExampleStmtHandle

1SQL_PARAM_INPUTSQL_C_CHARSQL_CHAR10(SQLPOINTER) currentDepartment[i8]0NULL) [3]

rc = SQLExecute(ExampleStmtHandle) [4]cout ltlt endl ltlt Current Dept ltlt currentDepartment[i8] ltlt endl Display The Results Of The SQL QueryExampleShowResults()

Figure 22 Use the prepare once execute many programming technique

The error-handling code has been removed for clarity At [1] the statement text is assigned to a variable Note that a parameter marker is used in the WHERE clause The statement is then prepared just once at [2] The current value of the parameter is bound to the prepared statement at [3] The prepared statement is executed at [4] Steps [3] and [4] are repeatedly executed in a for loop

Techniques to Further Improve DB2 CLI Performance Thus far this paper has discussed the techniques used by a sample application to tune the CLI performance However depending on the application architecture other methods of improving CLI performance may be considered

Connection PoolingCurrently the CLI application connecting through DB2 Connect to DB2 UDB for iSeries does not take advantage of the connection pooling mechanism implemented by DB2 Connect Therefore for performance reasons the author strongly recommends that the application server that obtains and drops connections very frequently implements its own database connection pooling mechanism that would assign an existing pooled database connection to a new AIX process or thread

42

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Blocking

For queries which result in returning large data blocks from the iSeries server (usually 32K of data and above) ensure that the database manager configuration parameter RQRIOBLK is set to 32767 This can be done using the Command Line Processor (CLP) as follows

db2 update database manager configuration using RQRIOBLK 32767

TroubleshootingThe experience of the author shows that two tools are particularly useful for pinning down the potential problem areas bull Joblog messages for a database server job usually provides enough details to isolate DB2

runtime issues bull CLI trace utility provides granular information about the data flow between the AIX application

and the database server job

Job Log MessagesThe process of finding and analyzing the job log for a DB2 CLI connection is identical to the process outlined for an embedded SQL application in the Job Log Message section of this paper on page 39

CLI Trace The DB2 CLIODBCJDBC trace utility provides very detailed information about the data streams exchanged between DB2 Connect and target database server Refer to the DB2 Information Center for more information on how to set up and analyze the CLI traces httppublibboulderibmcominfocenterdb2v8luwindexjsptopic=comibmdb2udbdocadc000 7959htm

43

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Trademarks

IBM eServer iSeries AIX AIX 5L i5OS WebSphere DB2 DB2 Universal Database DB2 Connect OS400 zOS OS390 Distributed Relational Database Architecture DRDA and DB2 Information Integration are trademarks or registered trademarks of International Business Machines Corporation in the United States and other countries

Java and all Java-based trademarks are trademarks of Sun Microsystems Inc in the United States other countries or both

Linux is a registered trademark of Linus Torvalds in the United States other countries or both

UNIX is a registered trademark of The Open Group in the United States and other countries

Microsoft and Windows are registered trademarks of Microsoft Corporation in the United States andor other countries

All other registered trademarks and trademarks are properties of their respective owners

IBM makes no commitment to make available any products referred to herein

References in this publication to IBM products or services do not imply that IBM intends to make them available in every country in which IBM operates

Additional Information ITSO offers a Redbook that can be helpful to those who want to learn more about i5OS AIX integration

bull AIX Integration with I5OS on the IBM eServer iSeries Server (SG24-6551)

Jarek Miszczyk is the Senior Software Engineer IBM eServer Solutions Enablement IBM Rochester

[Portions of this white paper reprinted with permission from MC Mag Online published by MC Press LLP httpwwwmcpressonlinecom]

Acknowledgments The author would like to thank the following people for their advice contributions and support on this paper

Bob Bittner IBM Rochester Jon Rush IBM Rochester Prasad Vallurupalli IBM Rochester Neil Willis IBM Rochester

44

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix A Source Listing of TestJDBCjava

package comibmiseriespwdimport javasqlimport javaxnamingimport javautilHashtableimport javautilimport javaxsqlimport comibmas400access

public class TestJDBC public static void main(javalangString[] args)

throws Exception

int numOfLoops = 5000int outerNumOfLoops = 5boolean firstExec = trueConnection conStatement sPreparedStatement psPreparedStatement pstmtdelCallableStatement cstmPreparedStatement pstmtHashtable env = new Hashtable()

envput(ContextINITIAL_CONTEXT_FACTORYcomsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env)Systemoutprintln(Deploying connection pooling data source)deployDataSource() Do the work with connection pooling onlyAS400JDBCConnectionPoolDataSource tkcpds =

(AS400JDBCConnectionPoolDataSource)ctxlookup(jdbcToolkitDataSource) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPool pool = new AS400JDBCConnectionPool(tkcpds) Adds 1 connection to the pool that can be used by theapplication (creates the physical database connections based onthe data source)poolfill(1)Systemoutprintln(nStart timing Toolkit connection pooling)long startTime = SystemcurrentTimeMillis()

for (int i = 0 i lt outerNumOfLoops i++) con = poolgetConnection()consetAutoCommit(false) deleteif ( i == 0)

long startDelete = SystemcurrentTimeMillis()cstm = cstm = conprepareCall(

CALL qsysqcmdexc(CLRPFM FILE(DB2USERCOFFEES) + 000000002800000))

cstmexecuteUpdate()cstmclose()long endDelete = SystemcurrentTimeMillis()Systemoutprintln(Delete all records +

(endDelete - startDelete) + ms elapsed)

45

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

String sqlinstrlong startInsert = SystemcurrentTimeMillis() insert

pstmt =conprepareStatement(INSERT INTO COFFEES VALUES( ))for (int j = 0 j lt numOfLoops j++) pstmtsetString(1 Kona_ + IntegertoString(i))pstmtsetInt(2 150)pstmtsetFloat(3 999f)pstmtsetInt(4 0)pstmtsetInt(5 0)pstmtaddBatch()int [] updateCounts = pstmtexecuteBatch()concommit()pstmtclose()long endInsert = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for + numOfLoops + inserts

+ (endInsert - startInsert)) selectlong startSelect = SystemcurrentTimeMillis()ps = conprepareStatement(SELECT FROM COFFEES)ResultSet rs = psexecuteQuery()rsnext()rsclose()concommit()psclose()long endSelect = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for select +

(endSelect - startSelect))consetAutoCommit(true)conclose()long endTime = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for + outerNumOfLoops +

loops + (endTime - startTime))Systemexit(0)

private static void deployDataSource()throws ExceptionString serverName = teraplex String databaseName = TERAPLEX String userName = db2user String password = db2pwd

Establish a JNDI context and bind the connection pool data sourceHashtable env = new Hashtable()envput(ContextINITIAL_CONTEXT_FACTORY

comsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPoolDataSource tkcpds = new

AS400JDBCConnectionPoolDataSource()tkcpdssetServerName(serverName) tkcpdssetDatabaseName(databaseName) tkcpdssetUser(userName) tkcpdssetPassword(password) tkcpdssetDescription(Toolkit Connection Pooling DataSource)tkcpdssetSavePasswordWhenSerialized(true)tkcpdssetExtendedDynamic(true)

46

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

tkcpdssetPackage(JDBCDS)tkcpdssetPackageCache(true)tkcpdssetPackageCriteria(select)enable the following properties as requiredcpdssetTrace(true)tkcpdssetServerTraceCategories( AS400JDBCDataSourceSERVER_TRACE_DEBUG_SERVER_JOB)

ctxrebind(jdbcToolkitDataSource tkcpds)

47

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix B mdash Source Listing of cursorsjsqc

Source File Name = cursorsjsqc Licensed Materials - Property of IBM (C) COPYRIGHT International Business Machines Corp 1995 2000 2004 All Rights Reserved US Government Users Restricted Rights - Use duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp PURPOSE This sample program demonstrates the use of a CURSOR The CURSOR is processed using static SQL EXTERNAL DEPENDENCIES - Ensure existence of database for precompile purposes - Precompile with the SQL precompiler (PREP in DB2) - Bind to a database (BIND in DB2) - Compile and link with the IBM Cset++ compiler (AIX and OS2) or the Microsoft Visual C++ compiler (Windows) or the compiler supported on your platform For more information about these samples see the README file For more information on programming in C see the - Programming in C and C++ section of the Application Development Guide For more information on building C applications see the - Building C Applications section of the Application Building Guide For more information on the SQL language see the SQL Reference

include ltstdiohgt include ltstdlibhgt include ltstringhgtinclude ltsqlhgtinclude ltsqlenvhgtinclude ltsqldahgtinclude ltsqlcahgt

int SqlInfoPrint( char struct sqlca int char )void TransRollback( void)

define EMB_SQL_CHECK( MSG_STR ) rc = SqlInfoPrint( MSG_STR ampsqlca __LINE__ __FILE__) if ( rc = 0 ) TransRollback( )

return 1

EXEC SQL INCLUDE SQLCA

int main(int argc char argv[])

EXEC SQL BEGIN DECLARE SECTIONchar dname[15]

48

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

char pname[10]double compchar userid[9]char passwd[19]

EXEC SQL END DECLARE SECTION

int rc = 0printf( Sample C program CURSORSJ n )if (argc == 1)

EXEC SQL CONNECT TO TPLXEMB_SQL_CHECK(CONNECT TO TPLX)

else if (argc == 3)

strcpy (userid argv[1])strcpy (passwd argv[2])EXEC SQL CONNECT TO TPLX USER userid USING passwdEMB_SQL_CHECK(CONNECT TO TPLX)

else

printf (nUSAGE cursor [userid passwd]nn)return 1

endif

EXEC SQL DECLARE c1 CURSOR FORselect deptname name salary + ifnull(comm0) as compensationfrom org o staff swhere odeptnumb = sdeptorder by deptname compensation desc

EXEC SQL OPEN c1EMB_SQL_CHECK(OPEN CURSOR)

printf(DEPARTMENT NAME COMPENSn)printf(-----------------------------------n)do

EXEC SQL FETCH c1 INTO dname pname compif (SQLCODE = 0) breakprintf( -1515s -1010s 72fn dname pname comp )

while ( 1 )

EXEC SQL CLOSE c1EMB_SQL_CHECK(CLOSE CURSOR)

EXEC SQL CONNECT RESETEMB_SQL_CHECK(CONNECT RESET)

exit(0)

end of program CURSORSJSQC

int SqlInfoPrint( char appMsgstruct sqlca pSqlcaint linechar file )

int rc = 0char sqlInfo[1024]char sqlInfoToken[1024]char sqlstateMsg[1024]char errorMsg[1024]

if (pSqlca-gtsqlcode = 0 ampamp pSqlca-gtsqlcode = 100)

49

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

strcpy(sqlInfo )if( pSqlca-gtsqlcode lt 0) sprintf( sqlInfoToken n---- error report ----n)

strcat( sqlInfo sqlInfoToken)else sprintf( sqlInfoToken n---- warning report ----n)

strcat( sqlInfo sqlInfoToken) endif

sprintf( sqlInfoToken app message = sn appMsg)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken line = dn line)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken file = sn file)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken SQLCODE = ldn pSqlca-gtsqlcode)strcat( sqlInfo sqlInfoToken)

get error message rc = sqlaintp( errorMsg 1024 80 pSqlca) return code is the length of the errorMsg string if( rc gt 0) sprintf( sqlInfoToken sn errorMsg)

strcat( sqlInfo sqlInfoToken)

get SQLSTATE message rc = sqlogstt( sqlstateMsg 1024 80 pSqlca-gtsqlstate)if (rc == 0) sprintf( sqlInfoToken sn sqlstateMsg)

strcat( sqlInfo sqlInfoToken)

if( pSqlca-gtsqlcode lt 0) sprintf( sqlInfoToken --- end error report ---n)

strcat( sqlInfo sqlInfoToken)printf(s sqlInfo)return 1

else sprintf( sqlInfoToken --- end warning report ---n)

strcat( sqlInfo sqlInfoToken)printf(s sqlInfo)return 0

endif endif

return 0

void TransRollback( ) struct sqlca sqlca

int rc = 0 rollback the transaction printf( nRolling back the transaction n)

EXEC SQL ROLLBACKrc = SqlInfoPrint( ROLLBACK ampsqlca __LINE__ __FILE__)if( rc == 0) printf( The transaction was rolled backn)

50

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

51

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix C mdash Source Listing of testclicpp

Include The Appropriate Header Filesinclude ltsqlclihgtinclude ltsqlcli1hgtinclude ltsqlutilhgtinclude ltsqlenvhgtinclude ltstdiohgt include ltiostreamgt include ltlocalehgt include ltstringhgtdefine SQL_SQLSTATE_SIZE 5define LOOPS 8

using namespace std

Define The CLI_Class Classclass CLI_Class

Attributespublic

SQLHANDLE EnvHandleSQLHANDLE ConHandleSQLHANDLE StmtHandleSQLRETURN rcSQLCHAR Job[6]SQLCHAR Name[10]SQLDOUBLE Comp

Operationspublic

CLI_Class()~CLI_Class()SQLRETURN ShowResults()

Constructor Destructor

SQLRETURN printError( SQLHDBC SQLHSTMT)

Define The Class ConstructorCLI_ClassCLI_Class()

setlocale( LC_ALL )

Initialize The Return Code Variablerc = SQL_SUCCESS

Allocate An Environment Handlerc = SQLAllocHandle(SQL_HANDLE_ENV SQL_NULL_HANDLE ampEnvHandle)

Allocate A Connection Handleif (rc == SQL_SUCCESS)

rc = SQLAllocHandle(SQL_HANDLE_DBC EnvHandle ampConHandle)

Define The Class DestructorCLI_Class~CLI_Class()

Free The Connection Handleif (ConHandle = NULL)

SQLFreeHandle(SQL_HANDLE_DBC ConHandle)

Free The Environment Handle

52

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

if (EnvHandle = NULL)SQLFreeHandle(SQL_HANDLE_ENV EnvHandle)

Define The ShowResults() Member FunctionSQLRETURN CLI_ClassShowResults(void)

While There Are Records In The Result Data Set Generated Retrieve And Display Themcout ltlt Name Job Compensation ltlt endlcout ltlt --------- ------ ------------ ltlt endlcoutsetf(iosleft)coutprecision(2)coutsetf(iosfixed)while (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)

rc = SQLFetch(StmtHandle)if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)

coutwidth(15)cout ltlt Name

coutwidth(10)cout ltlt Job

coutwidth(7)cout ltlt Comp ltltendl

if(rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO ampamp rc = SQL_NO_DATA)printError(ConHandle StmtHandle)

else

rc = 0SQLCloseCursor(StmtHandle)

Return The ODBC API Return Code To The Calling Functionreturn(rc)

SQLRETURN CLI_ClassprintError (SQLHDBC hdbc

SQLHSTMT hstmt)

SQLCHAR buffer[SQL_MAX_MESSAGE_LENGTH + 1]SQLCHAR sqlstate[SQL_SQLSTATE_SIZE + 1]SQLINTEGER sqlcodeSQLSMALLINT lengthSQLRETURN rcwhile ((rc = SQLError(SQL_NULL_HENV hdbc hstmt

sqlstateampsqlcodebufferSQL_MAX_MESSAGE_LENGTH + 1amplength)) == SQL_SUCCESS || rc ==

SQL_SUCCESS_WITH_INFO)

cout ltlt SQLSTATE ltlt sqlstate ltlt endlcout ltlt SQLCODE ltlt sqlcode ltlt endlcout ltlt Error msg ltlt buffer ltlt endl

53

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

cout ltlt----------------------------- ltlt endl ltlt endl

return(SQL_ERROR)

----------------------------------------------------------------- The Main Function -----------------------------------------------------------------int main()

Declare The Local Memory Variables

(SQLCHAR ) db2user SQL_NTS (SQLCHAR ) test26t SQL_NTS)

SQLRETURNSQLCHARSQLCHARSQLCHARchar

SQLCHAR

rc = SQL_SUCCESSDBName[10] = TPLXSQLStmt[255]c[10]ptrcurrentDepartment[8][15] = Head Office

New England Mid Atlantic South Atlantic Great Lakes PlainsPacificMountain

Create An Instance Of The CLI_Class ClassCLI_Class Example

Connect To iSeries Database if (ExampleConHandle = NULL)

rc = SQLConnect(ExampleConHandle DBName SQL_NTS

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)ExampleprintError(ExampleConHandle SQL_NULL_HSTMT)

return(rc)

cout ltlt Successfully connected to ltlt DBName ltlt ltlt endlrc = SQLSetConnectAttr(ExampleConHandle SQL_ATTR_AUTOCOMMIT

(SQLPOINTER) SQL_AUTOCOMMIT_OFF SQL_IS_UINTEGER) Allocate An SQL Statement Handlerc = SQLAllocHandle(SQL_HANDLE_STMT ExampleConHandle

ampExampleStmtHandle)if (rc == SQL_SUCCESS)

Define A SELECT SQL Statement

strcpy((char ) SQLStmt select name job salary + ifnull(comm0) ascompensation )

ptr = strcat( (char ) SQLStmt from org o staff s )ptr = strcat( (char ) SQLStmt where odeptnumb = sdept)ptr = strcat( (char ) SQLStmt and deptname = )ptr = strcat( (char ) SQLStmt order by compensation desc)

Prepare The SQL Statementrc = SQLPrepare(ExampleStmtHandle SQLStmt SQL_NTS)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)ExampleprintError(ExampleConHandle ExampleStmtHandle)

54

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

return(rc)

Bind The Columns In The Result Data Set Returned To Application Variables

rc = SQLBindCol(ExampleStmtHandle 1 SQL_C_CHAR (SQLPOINTER)ExampleName sizeof(ExampleName) NULL)

rc = SQLBindCol(ExampleStmtHandle 2 SQL_C_CHAR (SQLPOINTER)ExampleJob sizeof(ExampleJob) NULL)

rc = SQLBindCol(ExampleStmtHandle 3 SQL_C_DOUBLE (SQLPOINTER)ampExampleComp sizeof(ExampleComp) NULL)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO) ExampleprintError(ExampleConHandle ExampleStmtHandle)

return(rc)

while (true)

for (int i = 0 i lt LOOPS i++)

rc=SQLBindParameter(ExampleStmtHandle1SQL_PARAM_INPUTSQL_C_CHARSQL_CHAR

150(SQLPOINTER) currentDepartment[i8]0NULL)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)

ExampleprintError(ExampleConHandle ExampleStmtHandle)return(rc)

rc = SQLExecute(ExampleStmtHandle)if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)

ExampleprintError(ExampleConHandle ExampleStmtHandle)return(rc)

cout ltlt endl ltlt Current Dept ltlt currentDepartment[i8] ltlt

endl Display The Results Of The SQL QueryExampleShowResults()if(rc = 0)break

if ( i500 == 0 ampamp i gt 0 )cout ltlt Loops ltlt i ltlt ltlt endl

cout ltlt AFTER ltlt LOOPS ltlt loops Press X to exit ltlt endlcin gtgt cif (c[0] == x || c[0] == X)

break

Free The SQL Statement Handleif (ExampleStmtHandle = NULL )

SQLFreeHandle(SQL_HANDLE_STMT ExampleStmtHandle) Disconnect From The Northwind Sample Databaserc = SQLDisconnect(ExampleConHandle)

Return To The Operating Systemreturn(rc)

55

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 6 Defining a resource reference for a servlet

Once the resource reference has been defined and saved the servlet source code needs to be changed to reflect the fact that a resource reference is used to obtain a DataSource from the JNDI service Herersquos the relevant code snippet try

ctx = new InitialContext() ds = (DataSource)ctxlookup(javacompenvTestJDBCJ2C)

catch (Exception e) eprintStackTrace(out)

Now the ds DataSource object will produce connections that by default run with the isolation level of READ_COMMITTED (RC)

As mentioned the process of defining a resource reference for an EJB differs from the process that is used in the case of a servlet In WebSphere Studio Application Developer open the deployment descriptor editor for the EJB project that contains the EJB To do so double click on the ejb-jarxml file under WEB-INF directory in the project In the deployment editor dialog select the References tab In the references section on the left locate and select the EJB for which the developer wants to change the default isolation level Click the Add button The Add Reference dialog opens Click the Resource Reference radio button and then Next Define the reference following the example shown in Figure 7

14

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 7 Adding a resource reference for an EJB

When you click ldquoFinishrdquo the reference definition is added to the EJB descriptor The new definition needs to be further modified To do so click on the (+) sign next to the EJB in the References list Click the new reference TestJDBCJ2C in this example to open the properties for the reference Change WebSphere Bindings and WebSphere Extensions sections as illustrated in Figure 8

15

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 8 Defining a resource reference for an EJB

Save the modified definition and then change the EJB source code to use the reference rather than directly DataSource

TroubleshootingTroubleshooting a multi-tier application may be a bit tricky because the developer needs to deal with software components that reside in separate partitions Three tools are particularly useful for pinning down the potential problem areas bull Joblog messages for a database server job mdash Provides enough details to isolate DB2 UDB for

iSeries runtime issues bull JDBC trace utility mdash Provides granular information about the data flow between the AIX

application and the iSeries server job bull Database Monitor ndash Provides detailed SQL runtime trace

Job Log MessagesAs mentioned a DB2 client communicates with a corresponding iSeries server job This server job runs the SQL requests on behalf of the client The iSeries database server jobs are called QZDASOINIT and they run in the QUSRWRK subsystem At any given time a large number of database server jobs may be active on the server so the first step is to identify the job that serves the particular client connection The easiest method to accomplish this task is to run the following CL command from the i5OS prompt

WRKOBJLCK OBJ(DB2USER) OBJTYPE(USRPRF)

Here DB2USER is the user profile that is used to connect to the iSeries server Note that a QZDASONIT job is assigned to a client after the connection has been established so the developer needs to set a breakpoint in the client application after the database connection has been established

Once the Work with Object Locks appears key in 5 (Work with Job) next to the only QZDASOINIT job that should be listed This shows the Work with Job dialog Select option 10 to

16

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

display the job log for the database server job Now the job log can be searched for any error messages generated by the DB2 runtime

Sometimes it is also useful to include debug messages in the job log The debug messages are informational messages written to the job log about the implementation of a query They describe query implementation methods such as the use of indexes join order ODP implementation (reusable versus non-reusable) and so on The easiest way to instruct an iSeries server to include the debug messages is to set the ServerTraceCategories property on the data source object

tkcpdssetServerTraceCategories(AS400JDBCDataSourceSERVER_TRACE_DEBUG_SERVER_JOB)

A sample of the job log messages with debug messages enabled is shown below

SET TRANSACTION completeSTATEMENT NAME FOUND QZ868F0A458E13AF8C Starting optimizer debug message for query Arrival sequence access was used for file COFFEESODP created ODP not deleted 5000 rows inserted in COFFEES in DB2USER STATEMENT NAME FOUND QZ868F0A4C144BF12EBlocking used for queryCursor CRSR0001 opened606 rows fetched from cursor CRSR0001 ODP not deleted Cursor CRSR0001 closed

So the job log offers fairly detailed information on how the AIX client requests were implemented by the DB2 runtime

JDBC Trace UtilityThe JTOpen driver provides a tracing utility which can be used to collect detailed client-side traces The JDBC tracing is turned off by default It can be enabled by setting the Trace property to true Heres an example of how to switch on tracing using the setTrace method on the data source object

tkcpdssetTrace(true)

The trace can also be enabled when using the DriverManagergetConnection() method for obtaining a connection to DB2 UDB for iSeries In this case the developer could add the trace property to the connection string This approach is illustrated in the following code snippet

ClassforName(comibmas400accessAS400JDBCDriver) [1] hellip con = DriverManagergetConnection(jdbcas400teraplextrace=true

db2userdb2pwd) [2]

At [1] an instance of the JTOpen JDBC Driver is initiated Then at [2] the driver is used to obtain a connection to the iSeries server Note how the trace property has been added to the database URL See the IBM Toolbox for Java JDBC properties documentation on the iSeries Information Center Web site for a complete list of properties supported by the JTOpen driver

Although the level of details provided by the trace utility is sufficient in most troubleshooting scenarios sometimes the developer may need to collect low-level traces scoped to a certain type

17

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

of information In V5R3 the IBM Toolbox for Java (as well as the latest JTOpen) added a comprehensive detailed trace facility The following is the complete list of detailed trace parameters and their purpose

bull None or ldquordquo ndash This setting disables the detailed trace bull datastream - This category is used by Toolbox classes to log dataflow between the local host

and the remote system It is not intended for use by application classes bull diagnostic - This category is used to log object state information bull error - This category is used to log errors that cause an exception bull information - This category is used to track the flow of control through the code bull warning - This category is used to log errors that are recoverable bull conversion - This category is used by Toolbox classes to log character set conversions

between Unicode and native code pages bull proxy - This category is used by Toolbox classes to log data flow between the client and the

proxy server bull pcml - This category is used to determine how PCML interprets the data that is sent to and

from the server bull jdbc - This category is used to track JDBC calls throughout the program bull thread - This category is used to enable tracing of thread information This is useful when

debugging multi-threaded applications bull all - This category will enable all previous categories

The detailed trace can be enabled when using the DriverManagergetConnection() method for obtaining a connection to DB2 UDB for iSeries In this case the developer could add the toolbox trace property to the connection string This is illustrated in the following code sample

String dbUrl = jdbcas400pwd1toolbox trace=diagnostic con = DriverManagergetConnection(dbUrl dbUser dbPassword)

Note that currently the driverrsquos DataSource interfaces do not allow the developer to directly activate the detailed tracing However they could set the server from the command line at the time the java program is launched The example below shows how the detailed trace properties could be enabled at the command line

java -Dcomibmas400accessTracecategory=diagnostic TestJDBC

The -D switch indicates to the java interpreter that the information following it will be a system property

In case of a WebSphere application the trace property can be set through the admin console In the console select Application Servers-gt server1-gt Process Definition -gt Java Virtual Machine Figure 9 shows how to set the Generic JVM Arguments for an application server instance

18

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 9 Setting JVM arguments to enable detailed Toolbox tracing

Database Monitor

The database monitor is the ultimate tool available on DB2 UDB for iSeries to collect low-level SQL traces It is mainly used to pin down the SQL performance problems Refer to the lsquoUsing iSeries Database Monitor to Identify and Tune SQL Queriesrsquo white paper for a detailed discussion on how to collect and analyze the database monitor traces httpibmcomserversenablesiteeducationiborecordhtmldtmon

IBM DB2 JDBC Universal Driver DB2 JDBC Universal Driver is one of the new features delivered with DB2 UDB Version 8 DB2 JDBC Universal Driver has been designed to eliminate the dependency on DB2 CLI runtime modules as well as to enable direct Type 4 connectivity to DB2 UDB for iSeries and DB2 UDB for zOSreg

The pure-Java (Type 4) remote connectivity is based on the DRDA open distributed protocol for cross-platform access to DB2 DRDA defines the rules the protocols and the semantics for accessing distributed data Applications can access data in a distributed relational environment by using SQL statements The iSeries DRDA application server implementation is based on multiple connection-oriented server jobs running in the QSYSWRK subsystem A DRDA listener job (QRWTLSTN) listens for TCP connect requests on port 446 Once an application requester connects to the listener job the listener wakes up one of the QRWTSRVR prestart jobs and assigns it to a given client connection Any further communication occurs directly between the client application and the QRWTSRVR job These concepts are illustrated in Figure 10

19

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 10 Accessing DB2 UDB for iSeries with DB2 Universal Driver

The DB2 Universal Driver can be loaded in an AIX partition by installing one of the DB2 Connect for AIX products (see the Additional Information section for details) It is also a part of a DB2 Enterprise Server Edition for AIX install Specifically the developer needs three JAR files in a AIX partition to successfully connect to an iSeries server db2jccjar db2jcc_license_cisuzjar and db2jcc_license_cujar The iSeries license is contained in db2jcc_license_cisuzjar Note that this file is not a part of DB2 Client In other words a DB2 Connect license is required to use the driver in production environments The location of the JAR files needs to be added to the CLASSPATH environment variable For instance the following entry could be added to the AIX profile script

CLASSPATH=homedb2inst2sqllibjavadb2jccjarCLASSPATH=$CLASSPATHhomedb2inst2sqllibjavadb2jcc_license_cujarCLASSPATH=$CLASSPATHhomedb2inst2sqllibjavadb2jcc_license_cisuzjarexport CLASSPATH

Java Runtime 131 is a prerequisite

Additionally the developer should install the latest database group PTF (SF99503 for i5OS V5R3) on the iSeries server The Informational APAR ii13348 is keeping track of any fixes relevant to DRDA above and beyond the current database group PTF

Obtaining a Connection to DB2 UDB for iSeries When Type 4 connectivity is used the DB2 Universal Driver connects directly to the DB2 on iSeries through TCPIP Note that this is different from the legacy DB2 Type 2 JDBC driver that requires a DB2 node and remote database configurations on the client accessing iSeries The following code snippet illustrates how to use the DB2 JDBC Universal Driver to obtain a connection to DB2 UDB for iSeries

20

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

try ClassforName(comibmdb2jccDB2Driver) [1] catch(javalangClassNotFoundException e) Systemerrprint(ClassNotFoundException )Systemerrprintln(egetMessage())

try DriverManagergetConnection(jdbcdb2teraplex446TERAPLEX[2]

db2userdb2pwd) hellip catch(SQLException ex) Systemerrprintln(

SQLException + exgetMessage())

At [1] an instance of the DB2 JDBC Universal Driver is instantiated Then at [2] the driver is used to obtain a connection to the iSeries server Note the proper form of the database URL required by the driver

Considerations There are several advantages of DB2 JDBC Universal Driver bull Ease of cross-platform development mdash Consistent coding techniques and consistent error

codes and messages bull Ease of deployment mdash Pure Java (no runtime client required) and a single driver for accessing

DB2 on different platforms

The ease of use comes at a price though The iSeries JTOpen driver is optimized for accessing DB2 UDB for iSeries data and it uses native iSeries protocol to communicate with the back-end database server job This usually results in better performance and more-efficient system resources utilization For instance when using the DB2 JDBC Universal Driver to access an iSeries server the executeBatch method results in a single record insert There are also some restrictions when using DB2 Universal JDBC Driver with Type 4 connectivity

bull Support for distributed transactions (JTA) is not enabled bull Driver built-in connection pooling is not supported

Refer to Java application support in DB2 for more details on DB2 JDBC Universal Driver

21

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 Connect data access This section will explore the most important aspects of DB2 Connect ndash iSeries integration - including configuration tips and coding examples

DB2 Connect provides functionality for accessing data stored in DB2 UDB for iSeries as well as DB2 UDB for zOS and DB2 UDB for OS390reg DB2 Connect offers capabilities to access DB2 family members via several SQL interfaces gateway functions such as connection pooling and federated database functionality Many applications supporting the DB2 family of products leverage DB2 Connect as a key middleware component DB2 Connect is offered as separate AIX license products

Enterprise Edition Application Server Edition

In addition to DB2 Connect there are several other DB2 UDB Version 81 products that are supported on AIX

DB2 Universal Database Enterprise Server Edition DB2 Universal Database Workgroup Server Unlimited Edition DB2 Universal Database Workgroup Server Edition DB2 Universal Database Universal Developers Edition All Clients

The DB2 Connect Enterprise Edition functionality is also contained in DB2 Enterprise Server Edition for AIX

22

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 Connect in a nutshell In the scenario described in this paper the DB2 Connect functions contained in DB2 Enterprise Edition for AIX are utilized DB2 Connect Enterprise Edition provides support for both local and remote DB2 clients This is illustrated in Figure 11 Accessing DB2 UDB for iSeries with DB2 Connect

Figure 11 Accessing DB2 UDB for iSeries with DB2 Connect

DB2 Connect implements the Distributed Relational Database Architecturetrade (DRDAreg) to reduce the cost and complexity of accessing data stored in DB2 UDB for iSeries and other DRDA-compliant database servers DRDA defines the rules the protocols and the semantics for accessing distributed data Applications can access data in a distributed relational environment by using SQL statements In a distributed environment the system running the application and sending the SQL requests across the network is called the application requester (AR) A remote database server that executes SQL requests submitted by an application requester is known as the application server (AS) In the example shown in Figure 11 (above) DB2 Connect plays the role of an application requester while DB2 UDB for iSeries is an application server In this case DB2 Connect communicates with the iSeries database through TCPIP The iSeries DRDA application server implementation is based on multiple connection-oriented server jobs running in the QSYSWRK subsystem A DRDA listener job (QRWTLSTN) listens for TCP connect requests on port 446 Once an application requester connects to the listener job the listener wakes up one of the QRWTSRVR prestart jobs and assigns it to a given client connection Any further communication occurs directly between the client application and the QRWTSRVR job

DB2 Connect supports a wide range of programming interfaces that can be used by AIX applications to access the iSeries database Embedded SQL frac34 Both static and dynamic SQL frac34 Various programming languages (Java CC++ Cobol Fortran REXX)

DB2 Call Level Interface (DB2 CLI) ODBC JDBC frac34 DB2 JDBC Type 2 Driver frac34 DB2 JDBC Type 4 Driver (Universal JDBC Driver)

23

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Note that DB2 Connect supports access to DB2 UDB for iSeries through DB2 JDBC Universal driver However for performance and ease of maintenance reasons IBM recommends that Java applications running in AIX use native iSeries Toolbox JDBC driver See the JDBC Data Access section of this paper (above) for more details On the other hand DB2 Connect is a very efficient and robust connectivity option for AIX applications especially in the environments that are not directly supported by the native iSeries JDBC driver Here are several possible scenarios that would require DB2 Connect installed in a AIX partition

Embedded SQL interface is used to access DB2 CLI or ODBC interface is used to access DB2 A single SQL interface is needed to access multiple back end DB2 server Specific DB2 Connect functionality is needed such as distributed join or connection

pooling

Prerequisites One of the DB2 Connect products or DB2 Enterprise Server Edition for AIX V81 is needed Additionally DB2 Application Development Client is required in the AIX partition to compile DB2 applications

For maximum database server stability the developer should install the latest database group PTF (SF99503 for i5OS V5R3) on the iSeries server The Informational APAR ii13348 is keeping track of any fixes relevant to DRDA above and beyond the current database group PTF

DB2 Connect configuration The following example employs i5OS V5R3 and DB2 UDB Enterprise Server Edition for AIX Version 81 FixPak 6

Configuration steps in the iSeries partition The following process lists the necessary steps to be performed on the iSeries server 1) Verify that the TCPIP stack is working correctly It is assumed that the Virtual LAN is used to

communicate with the i5OS partition First obtain the IP address of the iSeries server or its hostname and ping the iSeries server from the AIX partition

2) Create a relational database (RDB) entry for the iSeries database in the i5OS partition If this has already been created it can be displayed by using the DSPRDBDIRE command Make sure that the RDB entry with a location of LOCAL exists on the iSeries server If it does not exist use the ADDRDBDIRE command to add the appropriate RDB entry For example the following command would add an RDB entry named TPLX For simplicity it is recommended that the TCPIP host name and RDB entry remain the same

ADDRDBDIRE RDB(TPLX) RMTLOCNAME(LOCAL)

3) Create a collection called NULLID This is necessary because the utilities shipped with DB2 Connect and DB2 UDB for AIX store their packages in the NULLID collection Since it does not exist by default in the iSeries server you must create it using the following command

CRTLIB LIB(NULLID)

4) Products that support DRDA automatically perform any necessary code page conversions at the receiving system For this to happen both systems need a translation table from their code page to the partner code page The default Coded Character Set Identifier (CCSID) on the iSeries server is 65535 Since DB2 Connect does not have a translation table for this code page the developer needs to change the individual user profiles to contain a CCSID that can be converted properly by DB2 Connect For US English this is 037 For other languages see DB2 Connect Personal Edition Quick Beginning GC09-2967 The following command changes the CCSID for an individual user profile to 037

24

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

CHGUSRPRF userid CCSID(037)

5) Verify that the default port 446 for DRDA service is being used To do this go to the Configure TCPIP menu (CFGTCP) select Configure Related Tables and then select Work with service table entries Verify that the DRDA service is set for port 446

6) The Distributed Data Management (DDM) job must be started for DRDA to work If you want the DDM job to be automatically started whenever TCPIP is started change the attributes of the DDM job using the CHGDDMTCPA command and set the Autostart server parameter to YES

7) If the system administrator chooses not to autostart the server issue the following command to start the DDM server job

STRTCPSVR SERVER(DDM)

8) Make sure that the user profiles that will be used to connect to the iSeries server exist on the server

25

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Configuration steps in the AIX partition The following steps are required for DB2 Connect to be configured in the AIX partition 1) Sign on to the AIX partition as the DB2 administrator 2) Launch Client Configuration Assistant (db2ca from the command prompt) It is assumed that

VNC or an X-Windows server are being used on the workstation so that the db2ca GUI can be properly rendered

3) From the Selected pull-down menu select the Add Database using Wizard option The Select how you want to setup a connection dialog appears Select Manually configure a connection to a database and click Next This is shown in Figure 12

Figure 12 Accessing DB2 UDB for iSeries with DB2 Connect

26

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

4) On the Select a communications protocol choose TCPIP and select The database physical resides on a host or OS400 system Then select the option Connect directly to the server as shown in Figure 13 Click Next

Figure 13 mdash Selecting communications protocol

27

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

5) On the TCPIP tab fill in the host name of the iSeries server The port number should be 446 This is shown in Figure 14 Click Next

Figure 14 mdash Specifying TCPIP communication parameters

28

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

6) On the Database tab fill in the Relational Database name Use the RDB entry name (specified in step 2) in the Configuration steps in the iSeries partition section as shown in Figure 15 Click Next

Figure 15 mdash Specifying the remote database

7) If you plan to use the ODBC applications select Register this database for ODBC as a system data source on the ODBC tab Click Next

29

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

8) On the Specify the node option dialog select OS400 from the Operating System pull-down menu This is shown in Figure 16 Click Finish

Figure 16 mdash Specifying the node options

30

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

9) The Test Connection dialog appears This allows the developer to verify that the connection works Select both CLI and JDBC check boxes You are also prompted for an iSeries user ID and password as shown in Figure 17

Figure 17 mdash Testing the connection

31

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

10) The successful connection to the database server is confirmed by the message box shown in Figure 18

Figure 18 mdash Test Connection results 11) At this time a newly configured database connection should appear in the main DB2

Configuration Assistant window It is recommended that the DB2 utilities are also bound to the iSeries database The bind process creates the necessary SQL packages on the remote database In the main Configuration Assistant window click the TPLX database entry and then select Selected-gtBindhellip

32

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

12) The Bind dialog appears Click Select All and then enter the connection information as shown in Figure 19 Click Bind The Results message box appears This allows the developer to monitor the progress of the binding process Watch for any error and warning messages

Figure 19 mdash Binding the DB2 utilities This concludes the DB2 Connect configuration steps

33

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Accessing DB2 UDB for iSeries from C embedded SQL

As mentioned earlier DB2 Connect allows developers to compile and run embedded SQL applications that access DB2 UDB for iSeries data This section covers implementation details for a C embedded SQL application called cursorsjsqc (see Appendix B for source code)

Prerequisites An embedded SQL application running in an AIX partition will use DB2 Connect services to access DB2 UDB for iSeries therefore the developer needs to make sure that all components listed in section Prerequisites on page 24 are installed The developer also needs to create a remote database connection as described in the DB2 Connect configuration section of this paper on page 24

Static SQL and SQL packages To successfully run against a DB2 UDB for iSeries database an embedded SQL application needs to be first precompiled and bound to the back-end database This process creates an SQL package on the target iSeries server The SQL package contains the access plan information for the SQL statements executed by the application The internal structure of the package as well as the method how its content is used by the SQL runtime to facilitate the access plan reuse is similar to the Extended Dynamic SQL support covered in detail in the Extended Dynamic SQL and Statement Caching section of this paper (on page 9) There are however important differences between the packages created by the extended dynamic SQL support and the packages created for embedded SQL DRDA client applications The extended dynamic SQL packages support dynamic SQL interfaces such as JDBC

that can submit ad hoc SQL statements at the run time The SQL runtime can prepare the dynamic statements and add them to the package On the other hand the DRDA packages are created at the precompile time and contain static SQL In order to add new statements to the package the application needs to be precompiled and rebound again

The extended dynamic SQL package can dynamically grow up to 500MB by allocating new space as required The DRDA packages since they are created at the precompile time have a fix size and do not grow over their life time

Simple embedded SQL application The application is based on a source code provided in the DB2 UDB samples directory typically to be found at homedb2inst1sqllibsamples The cursorsjsqc performs a join between STAFF and ORG tables located in DB2USER schema (library) on the TPLX database server (the source is provided at the end of this paper in Appendix B) The join statement retrieves the DEPTNAME column from ORG NAME column from STAFF and calculates the total compensation for an employee by adding SALARY and COMM columns in STAFF The results are sorted by department name and total compensation Here is the SELECT statement used by the application

SELECT deptname name salary + IFNULL(comm0) as compensationFROM org o staff sWHERE odeptnumb = sdeptORDER BY deptname compensation DESC

The application iterates through the selected records and prints out the data to the standard output device The sample DB2USER schema was created with the following SQL statements

db2 CONNECT TO tplx USER db2user USING mypassworddb2 CALL QSYSCREATE_SQL_SAMPLE(DB2USER)

34

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Make sure that the AIX partition is logged into with the DB2 admin user profile If the defaults were selected at the DB2 installation time this profile name is db2inst1 It is also assumed that DB2USER user exists on the iSeries server and that it has appropriate authority

There are several steps that are required to create an executable for the cursorsjsqc source code First the DB2 PRECOMPILE utility needs to be called The utility creates a bind file that is used to bind the required SQL package to the TPLX database It also converts embedded SQL statements into DB2 run-time API calls and produces a pure C source file that can be processed by an AIX C compiler

db2 CONNECT TO tplx USER db2user USING mypassworddb2 prep cursorsjsqc bindfile

Note that the connect statement is required only if the developer is not already connected to the database on an iSeries server Watch for any error or warning messages returned by the DB2 prep utility The prepare step should produce cursorsjbnd and cursorsjc files in the current directory Now the developer can invoke the bind utility to prepare the statements contained in the bind file and create the package on the target iSeries database server

db2 bind cursorsjbnd

It is assumed that Visual C++ 60 is installed and configured in the AIX partition Refer to the ldquoDeveloping and Porting C and C++ Applications on AIXrdquo redbook for more information on how to use the Visual C++ compiler httpibmcomredbooksabstractssg245674htmlOpen

Use the following commands to compile the C source generated by the precompile utility

xlc -I$INSTHOMEsqllibinclude ndashc cursorsjcxlc ndasho cursorsj cursorsjo -L$INSTHOMEsqlliblib ndashldb2

Run the program from the AIX prompt

cursorsj db2user mypassword

Distributed Join DB2 UDB Version 8 provides core federated server functionality A federated system consists of a DB2 UDB instance that operates as a federated server a database that acts as the federated database one or more data sources and clients (users and applications) that access the database and data sources Federated server permits objects stored in multiple databases to be accessed together in the same query For example a query can refer to a table that resides in DB2 UDB for iSeries and join it to a table stored in DB2 UDB for AIX Such a query would constitute so called distributed join The support for DB2 UDB for iSeries as a federated data source is provided by core federated server functionality directly implemented in DB2 UDB Enterprise Server Edition and DB2 UDB Connect Enterprise Edition All other DB2 UDB family members are also supported directly by core DB2 UDB federated server An additional software product DB2 Information Integratortrade is required to access non-DB2 UDB databases such as Oracle Sybase or Microsoftreg SQL Server Consult the following white papers for a detailed discussion on DB2 federated server support Heterogeneous data access for iSeries applications Version 2 httpibmcomserversenablesiteeducationiborecordhtmlhetdata Fundamentals of IBM DB2 Federated Server and Relational Connect httpwww7bsoftwareibmcomdmddlibrarytecharticle0206purnell0206purnellhtml

35

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Distributed Join Example In this section the steps that are required to configure DB2 UDB for iSeries as a federated data source will be illustrated Then the cursorsjsqc program will be ldquotweakedrdquo so that it executes a distributed join query that accesses data stored on an iSeries server and in the local DB2 UDB for AIX database It is assumed that the developer is familiar with the DB2 federated server concepts

Note Run the following commands from the Command Line Processor prompt Load the utility by executing the db2 command at the AIX prompt 1) First the local DB2 UDB for AIX instance needs to be enabled as a DB2 federated server

This is done by setting the database manager configuration parameter FEDERATED to YES

db2=gt update dbm cfg using FEDERATED YES

The database instance needs to be restarted for the change to take effect

NOTE A federated database is a regular database in a DB2 UDB instance that has the FEDERATED parameter enabled Therefore in this example the SAMPLE database that was created earlier is used as the federated database A new database can also be created using the CREATE DATABASE command

2) Connect to the federated database

db2=gt connect to sample

3) Use the CREATE WRAPPER statement to register a wrapper for the iSeries data source Wrappers are library routines that are used by the federated server to perform operations such as connecting to a data source and retrieving data from it The default wrapper name for DB2 UDB for iSeries is DRDA Here is the command to register the DRDA wrapper

db2=gt create wrapper drda

4) Use the CREATE SERVER statement to register a data source as a server within the federated database The server definition specifies the type and version of the data source and the wrapper used for communications with this data source For the DB2 UDB for iSeries data source the node and the database names are also needed The node and database name parameters have been configured for our TPLX database in the Configuration steps in the AIX partition section (on page 24) Use the following DB2 UDB command to lookup these parameter on the federated server

db2=gt list database directory

In this case the command produced the following output

Database alias = TPLX Database name = DCSE99E1 Node name = NDE9BF76 Database release level = a00 Comment = Directory entry type = Remote Authentication = SERVER Catalog database partition number = -1

36

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Note that the node name is set to NDE9BF76 The name was generated by the Configuration Administrator utility (db2ca)

Here is the command to register the TPLX database as a federated server

db2=gt create server tplx type db2400 version 530 wrapperdrda authorization db2user password mypassword options(nodeNDE9BF76 dbname TPLX)

The command is quite complex so make sure that the syntax is correct

5) Define the user mappings that instructs the federated server what user ID and password should be used when connecting to the iSeries data source

db2=gt create user mapping for user server tplxoptions(remote_authid db2user remote_password mypassword)

Specify the nickname for the iSeries table or view A nickname is an identifier that is used by the federated server to reference an object located at the data source The following command creates a nickname for the STAFF table located in the DB2USER schema on the TPLX database

db2=gt create nickname tplx_staff for tplxdb2userstaff

6) Test the distributed join query

db2=gt SELECT deptname name salary + COALESCE(comm0) ascompensation FROM org o tplx_staff s WHERE odeptnumb =sdept ORDER BY deptname compensation DESC

Note that the native iSeries function IFNULL has been substituted with an equivalent DB2 UDB function COALESCE COALESCE is also supported on iSeries servers For better portability IBM encourages the use of COALESCE rather than IFNULL Note also that the query runs on the federated server rather than on TPLX It accesses the ORG table in the local DB2 UDB for AIX SAMPLE database and the STAFF table that resides in TPLX The federated server performs the necessary distributed join

7) Modify the cursorsjsqc so that it executes a distributed join There are two source code modifications - Change the CONNECT TO statements Now the application needs to connect to the

federated database SAMPLE rather than to TPLX

EXEC SQL CONNECT TO SAMPLEEXEC SQL CONNECT TO SAMPLE USER userid USING passwd

- Modify the select statement so that it performs a distributed join Use the statement (shown in step 6) above Save the new source version as cursordjsqc

- Prepare bind and compile the distributed join version of the program as described in the Simple C embedded SQL application section (on page 34)

db2 prep cursordjsqc bindfiledb2 bind cursordjbndxlc -I$INSTHOMEsqllibinclude ndashc cursordjcxlc ndasho cursordj cursordjo -L$INSTHOMEsqlliblib ndashldb2

37

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

- Run the program from the AIX prompt

cursordj

Connection Pooling and Connection ConcentratorA modern Web-based application typically executes a large number of short-lived transactions Executing a transaction in this environment means establishing a database connection executing a few SQL statements and terminating this connection Creating connections to the database server is a very costly process To reduce the unnecessary workload DB2 Connect implements connection pooling and connection concentrator Connection pooling mechanism allows DB2 Connect to reuse an existing connection infrastructure for subsequent connection requests The connection concentrator is an advanced technology that allows DB2 Connect to serve a potentially very large number of clients with a limited number of database connections This is accomplished by decoupling clients from a particular database connection

Note that currently neither connection pooling nor connection concentrator support DB2 UDB for iSeries Therefore for performance reasons the author strongly recommends that the application server that obtains and drops connections very frequently implements its own database connection pooling mechanism that would assign an existing pooled database connection to a new AIX process or thread

TroubleshootingTroubleshooting a multi-tier application may be a bit tricky because the developer needs to deal with software components that reside in separate partitions The authorrsquos experience shows that two tools are particularly useful for pinning down the potential problem areas The joblog messages for a database server job usually provide enough details to isolate DB2

UDB for iSeries runtime issues The DRDA trace utility provides granular information about the data flow between the AIX

application and the iSeries server job

38

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Job Log MessagesAs mentioned earlier a DB2 client communicates with a corresponding iSeries server job This server job runs the SQL requests on behalf of the client More precisely when a DB2 client submits an SQL statement the statement is passed to a server job that in turn calls the DB2 runtime to execute the statement The results are then reformatted and marshaled to the client The iSeries DRDA server jobs are called QRWTSRVR and they run in the QUSRWRK subsystem At any given time there may be a large number of DRDA server jobs active on the system so the first step is to identify the job that serves the particular client connection The easiest method to accomplish this task is to run the following CL command from the i5OS prompt

WRKOBJLCK OBJ(DB2USER) OBJTYPE(USRPRF)

Here DB2USER is the user profile that is used to connect to the iSeries server Note that a QRWTSRVR job is assigned to a client after the connection has been established so the developer needs to set a breakpoint in the client application below the CONNECT TO statement

Once the Work with Object Locks appears key in 5 (Work with Job) next to the only QRWTSRVR job that should be listed This shows the Work with Job dialog Select option 10 to display the job log for the database server job Now the developer can search the job log for any error messages generated by the DB2 runtime

Sometimes it is also useful to include debug messages in the job log The debug messages are informational messages written to the job log about the implementation of a query They describe query implementation methods such as use of indexes join order ODP implementation (reusable versus non-reusable) and so on The easiest way to instruct the iSeries server to include the debug messages is to call the following stored procedure just after the connection to the iSeries server is established

EXEC SQL call qsysqcmdexc(STRDBGUPDPROD(YES)000000002000000)

A sample of the job log messages with debug messages enabled is shown below in Figure 20

Arrival sequence access was used for file STAFFAccess path suggestion for file STAFFQuery options used to build the OS400 query access plan Ending debug message for query ODP created Blocking used for queryCursor SQLCUR201 opened1 rows fetched from cursor SQLCUR201Row not found for SQLCUR201ODP deleted Cursor SQLCUR201 closedDESCRIBE of prepared statement STMT0201 completed

Figure 20 mdash Joblog with debug messages enabled

So the job log offers fairly detailed information on how the AIX client requests were implemented by the DB2 runtime

39

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 DRDA trace utilityThe DB2 DRDA trace utility (db2drdat) provides detailed information about the data streams exchanged between DB2 Connect and target database server The output file produced by the utility contains send and receive communications buffers TCPIP error messages and SQL Communications Area (SQLCA) information Please refer to lsquoDB2 Connect Userrsquos Guidersquo manual for in-depth discussion of the DRDA trace utility

Accessing DB2 UDB for iSeries from CLI DB2 Call Level Interface (CLI ) is based on the Microsoft Open Database Connectivity (ODBC) specification and the ISO CLI standard The DB2 CLI interface gained popularity among DB2 application providers because the developer can build an ODBC application by simply linking the application with libdb2 library on a UNIX server In other words the developer directly utilizes the DB2 ODBC driver services without a need for an ODBC driver manager Additionally in contrast to embedded SQL the developer does not need to precompile or bind DB2 CLI applications because they use packages provided with DB2 UDB The developer simply compiles and links the application

Prerequisites A DB2 CLI application running in an AIX partition will use DB2 Connect services to access DB2 UDB for iSeries therefore make sure that all components listed in Prerequisites section of this paper on page 24 are installed The developer also needs to create a remote database connection as described in the DB2 Connect configuration section of this paper on page 24

Dynamic SQL and Access Plan Caching A DB2 CLI client application uses the dynamic SQL interface and does not have the capability to utilize the extended dynamic SQL support Therefore it runs lsquopurersquo dynamic SQL statements That does not mean however that the process of parsing validating and optimizing will be repeated for every execution of a given dynamic SQL statement

The DB2 UDB for iSeries database implements an internal object called System-Wide SQL Statement Cache (SWSC) The SWSC can improve the performance of programs using dynamic SQL statements by caching the access plans in a system-wide cache When a dynamic SQL statement is submitted the SQL runtime searches the SWSC to see if this statement has been previously executed If so then DB2 retrieves and reuses the key information associated with the cached statement and thereby the processing time and the resources utilization can be significantly reduced

Simple DB2 CLI C++ ApplicationThis section covers DB2 CLI implementation details for a sample C++ program called testclicpp (the source is provided at the end of this paper in Appendix C) To compile the source with Visual C++ complier use the following command in the AIX partition

xlC ndashI$INSTHOMEsqllibinclude ndashc testclicppxlC ndasho testcli testclio ndashL$INSTHOMEsqlliblib ndashldb2

The application performs a join between STAFF and ORG tables located in DB2USER schema (library) The join statement retrieves the DEPTNAME column from ORG NAME and JOB columns from STAFF and calculates the total compensation for an employee by adding SALARY and COMM columns in STAFF The results are sorted by total compensation The selection criterion is based on the current value of the department name parameter Here is the SELECT statement used by testcli

40

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

select name job salary + coalesce(comm0) as compensationfrom org o staff swhere odeptnumb = sdeptand deptname = order by compensation desc

Figure 21 shows the software components involved in the execution of this sample application

Figure 21 How a DB2 CLI client accesses DB2 UDB on an iSeries server

Although the testcli application is fairly simple it covers some important aspects of efficient CLI programming for DB2 UDB for iSeries

Reusable Open Data Paths (ODPs)An Open Data Path (ODP) definition is an internal i5OS object that is created when certain SQL statements (such as OPEN INSERT UPDATE and DELETE) are executed for the first time in a given job (or connection) The ODP can be thought of as a runtime implementation of an access plan The access plan created at the optimization time provides a recipe or in other words a sequence of steps necessary to execute the statement The ODP on the other hand provides the executable code for all requested IO operations The process of creating new ODP objects is fairly CPU- and IO-intensive so whenever possible the iSeries DB2 runtime tries to reuse existing ODPs For instance a SQLCloseCursor() API call may close the SQL cursor but leave the ODP available to be used the next time the cursor is opened This can significantly reduce the processing and response time in running SQL statements A reusable OPD usually requires 10 to 20 times less CPU resources than a newly created ODP Therefore it is important that the applications employ programming techniques that allow the DB2 runtime to reuse ODPs

With dynamic interfaces such as CLI full opens are avoided by using a prepare once execute many programming paradigm It means that when an SQL statement is going to be executed more than once you should prepare the statement just once and then reuse the prepared

41

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

statements for consecutive executions Although DB2 UDB does try to convert literals to parameter markers so that similar statements can be reused it is a better programming practice to explicitly implement parameter markers That way the chances for reusable ODPs are quite significantly improved The code snippet in Figure 22 illustrates how to implement the prepare once execute many programming technique

Define A SELECT SQL Statementstrcpy((char ) SQLStmt select name job salary + ifnull(comm0) ascompensation )ptr = strcat( (char ) SQLStmt from org o staff s )ptr = strcat( (char ) SQLStmt where odeptnumb = sdept)ptr = strcat( (char ) SQLStmt and deptname = )ptr = strcat( (char ) SQLStmt order by compensation desc) [1]

Prepare The SQL Statementrc = SQLPrepare(ExampleStmtHandle SQLStmt SQL_NTS) [2]

Bind The Columns In The Result Data Set Returned To Application Variablesrc = SQLBindCol(ExampleStmtHandle 1 SQL_C_CHAR (SQLPOINTER)

ExampleName sizeof(ExampleName) NULL)rc = SQLBindCol(ExampleStmtHandle 2 SQL_C_CHAR (SQLPOINTER)

ExampleJob sizeof(ExampleJob) NULL)rc = SQLBindCol(ExampleStmtHandle 3 SQL_C_DOUBLE (SQLPOINTER)

ampExampleComp sizeof(ExampleComp) NULL)

for (int i = 0 i lt LOOPS i++)rc=SQLBindParameter(ExampleStmtHandle

1SQL_PARAM_INPUTSQL_C_CHARSQL_CHAR10(SQLPOINTER) currentDepartment[i8]0NULL) [3]

rc = SQLExecute(ExampleStmtHandle) [4]cout ltlt endl ltlt Current Dept ltlt currentDepartment[i8] ltlt endl Display The Results Of The SQL QueryExampleShowResults()

Figure 22 Use the prepare once execute many programming technique

The error-handling code has been removed for clarity At [1] the statement text is assigned to a variable Note that a parameter marker is used in the WHERE clause The statement is then prepared just once at [2] The current value of the parameter is bound to the prepared statement at [3] The prepared statement is executed at [4] Steps [3] and [4] are repeatedly executed in a for loop

Techniques to Further Improve DB2 CLI Performance Thus far this paper has discussed the techniques used by a sample application to tune the CLI performance However depending on the application architecture other methods of improving CLI performance may be considered

Connection PoolingCurrently the CLI application connecting through DB2 Connect to DB2 UDB for iSeries does not take advantage of the connection pooling mechanism implemented by DB2 Connect Therefore for performance reasons the author strongly recommends that the application server that obtains and drops connections very frequently implements its own database connection pooling mechanism that would assign an existing pooled database connection to a new AIX process or thread

42

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Blocking

For queries which result in returning large data blocks from the iSeries server (usually 32K of data and above) ensure that the database manager configuration parameter RQRIOBLK is set to 32767 This can be done using the Command Line Processor (CLP) as follows

db2 update database manager configuration using RQRIOBLK 32767

TroubleshootingThe experience of the author shows that two tools are particularly useful for pinning down the potential problem areas bull Joblog messages for a database server job usually provides enough details to isolate DB2

runtime issues bull CLI trace utility provides granular information about the data flow between the AIX application

and the database server job

Job Log MessagesThe process of finding and analyzing the job log for a DB2 CLI connection is identical to the process outlined for an embedded SQL application in the Job Log Message section of this paper on page 39

CLI Trace The DB2 CLIODBCJDBC trace utility provides very detailed information about the data streams exchanged between DB2 Connect and target database server Refer to the DB2 Information Center for more information on how to set up and analyze the CLI traces httppublibboulderibmcominfocenterdb2v8luwindexjsptopic=comibmdb2udbdocadc000 7959htm

43

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Trademarks

IBM eServer iSeries AIX AIX 5L i5OS WebSphere DB2 DB2 Universal Database DB2 Connect OS400 zOS OS390 Distributed Relational Database Architecture DRDA and DB2 Information Integration are trademarks or registered trademarks of International Business Machines Corporation in the United States and other countries

Java and all Java-based trademarks are trademarks of Sun Microsystems Inc in the United States other countries or both

Linux is a registered trademark of Linus Torvalds in the United States other countries or both

UNIX is a registered trademark of The Open Group in the United States and other countries

Microsoft and Windows are registered trademarks of Microsoft Corporation in the United States andor other countries

All other registered trademarks and trademarks are properties of their respective owners

IBM makes no commitment to make available any products referred to herein

References in this publication to IBM products or services do not imply that IBM intends to make them available in every country in which IBM operates

Additional Information ITSO offers a Redbook that can be helpful to those who want to learn more about i5OS AIX integration

bull AIX Integration with I5OS on the IBM eServer iSeries Server (SG24-6551)

Jarek Miszczyk is the Senior Software Engineer IBM eServer Solutions Enablement IBM Rochester

[Portions of this white paper reprinted with permission from MC Mag Online published by MC Press LLP httpwwwmcpressonlinecom]

Acknowledgments The author would like to thank the following people for their advice contributions and support on this paper

Bob Bittner IBM Rochester Jon Rush IBM Rochester Prasad Vallurupalli IBM Rochester Neil Willis IBM Rochester

44

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix A Source Listing of TestJDBCjava

package comibmiseriespwdimport javasqlimport javaxnamingimport javautilHashtableimport javautilimport javaxsqlimport comibmas400access

public class TestJDBC public static void main(javalangString[] args)

throws Exception

int numOfLoops = 5000int outerNumOfLoops = 5boolean firstExec = trueConnection conStatement sPreparedStatement psPreparedStatement pstmtdelCallableStatement cstmPreparedStatement pstmtHashtable env = new Hashtable()

envput(ContextINITIAL_CONTEXT_FACTORYcomsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env)Systemoutprintln(Deploying connection pooling data source)deployDataSource() Do the work with connection pooling onlyAS400JDBCConnectionPoolDataSource tkcpds =

(AS400JDBCConnectionPoolDataSource)ctxlookup(jdbcToolkitDataSource) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPool pool = new AS400JDBCConnectionPool(tkcpds) Adds 1 connection to the pool that can be used by theapplication (creates the physical database connections based onthe data source)poolfill(1)Systemoutprintln(nStart timing Toolkit connection pooling)long startTime = SystemcurrentTimeMillis()

for (int i = 0 i lt outerNumOfLoops i++) con = poolgetConnection()consetAutoCommit(false) deleteif ( i == 0)

long startDelete = SystemcurrentTimeMillis()cstm = cstm = conprepareCall(

CALL qsysqcmdexc(CLRPFM FILE(DB2USERCOFFEES) + 000000002800000))

cstmexecuteUpdate()cstmclose()long endDelete = SystemcurrentTimeMillis()Systemoutprintln(Delete all records +

(endDelete - startDelete) + ms elapsed)

45

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

String sqlinstrlong startInsert = SystemcurrentTimeMillis() insert

pstmt =conprepareStatement(INSERT INTO COFFEES VALUES( ))for (int j = 0 j lt numOfLoops j++) pstmtsetString(1 Kona_ + IntegertoString(i))pstmtsetInt(2 150)pstmtsetFloat(3 999f)pstmtsetInt(4 0)pstmtsetInt(5 0)pstmtaddBatch()int [] updateCounts = pstmtexecuteBatch()concommit()pstmtclose()long endInsert = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for + numOfLoops + inserts

+ (endInsert - startInsert)) selectlong startSelect = SystemcurrentTimeMillis()ps = conprepareStatement(SELECT FROM COFFEES)ResultSet rs = psexecuteQuery()rsnext()rsclose()concommit()psclose()long endSelect = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for select +

(endSelect - startSelect))consetAutoCommit(true)conclose()long endTime = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for + outerNumOfLoops +

loops + (endTime - startTime))Systemexit(0)

private static void deployDataSource()throws ExceptionString serverName = teraplex String databaseName = TERAPLEX String userName = db2user String password = db2pwd

Establish a JNDI context and bind the connection pool data sourceHashtable env = new Hashtable()envput(ContextINITIAL_CONTEXT_FACTORY

comsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPoolDataSource tkcpds = new

AS400JDBCConnectionPoolDataSource()tkcpdssetServerName(serverName) tkcpdssetDatabaseName(databaseName) tkcpdssetUser(userName) tkcpdssetPassword(password) tkcpdssetDescription(Toolkit Connection Pooling DataSource)tkcpdssetSavePasswordWhenSerialized(true)tkcpdssetExtendedDynamic(true)

46

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

tkcpdssetPackage(JDBCDS)tkcpdssetPackageCache(true)tkcpdssetPackageCriteria(select)enable the following properties as requiredcpdssetTrace(true)tkcpdssetServerTraceCategories( AS400JDBCDataSourceSERVER_TRACE_DEBUG_SERVER_JOB)

ctxrebind(jdbcToolkitDataSource tkcpds)

47

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix B mdash Source Listing of cursorsjsqc

Source File Name = cursorsjsqc Licensed Materials - Property of IBM (C) COPYRIGHT International Business Machines Corp 1995 2000 2004 All Rights Reserved US Government Users Restricted Rights - Use duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp PURPOSE This sample program demonstrates the use of a CURSOR The CURSOR is processed using static SQL EXTERNAL DEPENDENCIES - Ensure existence of database for precompile purposes - Precompile with the SQL precompiler (PREP in DB2) - Bind to a database (BIND in DB2) - Compile and link with the IBM Cset++ compiler (AIX and OS2) or the Microsoft Visual C++ compiler (Windows) or the compiler supported on your platform For more information about these samples see the README file For more information on programming in C see the - Programming in C and C++ section of the Application Development Guide For more information on building C applications see the - Building C Applications section of the Application Building Guide For more information on the SQL language see the SQL Reference

include ltstdiohgt include ltstdlibhgt include ltstringhgtinclude ltsqlhgtinclude ltsqlenvhgtinclude ltsqldahgtinclude ltsqlcahgt

int SqlInfoPrint( char struct sqlca int char )void TransRollback( void)

define EMB_SQL_CHECK( MSG_STR ) rc = SqlInfoPrint( MSG_STR ampsqlca __LINE__ __FILE__) if ( rc = 0 ) TransRollback( )

return 1

EXEC SQL INCLUDE SQLCA

int main(int argc char argv[])

EXEC SQL BEGIN DECLARE SECTIONchar dname[15]

48

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

char pname[10]double compchar userid[9]char passwd[19]

EXEC SQL END DECLARE SECTION

int rc = 0printf( Sample C program CURSORSJ n )if (argc == 1)

EXEC SQL CONNECT TO TPLXEMB_SQL_CHECK(CONNECT TO TPLX)

else if (argc == 3)

strcpy (userid argv[1])strcpy (passwd argv[2])EXEC SQL CONNECT TO TPLX USER userid USING passwdEMB_SQL_CHECK(CONNECT TO TPLX)

else

printf (nUSAGE cursor [userid passwd]nn)return 1

endif

EXEC SQL DECLARE c1 CURSOR FORselect deptname name salary + ifnull(comm0) as compensationfrom org o staff swhere odeptnumb = sdeptorder by deptname compensation desc

EXEC SQL OPEN c1EMB_SQL_CHECK(OPEN CURSOR)

printf(DEPARTMENT NAME COMPENSn)printf(-----------------------------------n)do

EXEC SQL FETCH c1 INTO dname pname compif (SQLCODE = 0) breakprintf( -1515s -1010s 72fn dname pname comp )

while ( 1 )

EXEC SQL CLOSE c1EMB_SQL_CHECK(CLOSE CURSOR)

EXEC SQL CONNECT RESETEMB_SQL_CHECK(CONNECT RESET)

exit(0)

end of program CURSORSJSQC

int SqlInfoPrint( char appMsgstruct sqlca pSqlcaint linechar file )

int rc = 0char sqlInfo[1024]char sqlInfoToken[1024]char sqlstateMsg[1024]char errorMsg[1024]

if (pSqlca-gtsqlcode = 0 ampamp pSqlca-gtsqlcode = 100)

49

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

strcpy(sqlInfo )if( pSqlca-gtsqlcode lt 0) sprintf( sqlInfoToken n---- error report ----n)

strcat( sqlInfo sqlInfoToken)else sprintf( sqlInfoToken n---- warning report ----n)

strcat( sqlInfo sqlInfoToken) endif

sprintf( sqlInfoToken app message = sn appMsg)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken line = dn line)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken file = sn file)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken SQLCODE = ldn pSqlca-gtsqlcode)strcat( sqlInfo sqlInfoToken)

get error message rc = sqlaintp( errorMsg 1024 80 pSqlca) return code is the length of the errorMsg string if( rc gt 0) sprintf( sqlInfoToken sn errorMsg)

strcat( sqlInfo sqlInfoToken)

get SQLSTATE message rc = sqlogstt( sqlstateMsg 1024 80 pSqlca-gtsqlstate)if (rc == 0) sprintf( sqlInfoToken sn sqlstateMsg)

strcat( sqlInfo sqlInfoToken)

if( pSqlca-gtsqlcode lt 0) sprintf( sqlInfoToken --- end error report ---n)

strcat( sqlInfo sqlInfoToken)printf(s sqlInfo)return 1

else sprintf( sqlInfoToken --- end warning report ---n)

strcat( sqlInfo sqlInfoToken)printf(s sqlInfo)return 0

endif endif

return 0

void TransRollback( ) struct sqlca sqlca

int rc = 0 rollback the transaction printf( nRolling back the transaction n)

EXEC SQL ROLLBACKrc = SqlInfoPrint( ROLLBACK ampsqlca __LINE__ __FILE__)if( rc == 0) printf( The transaction was rolled backn)

50

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

51

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix C mdash Source Listing of testclicpp

Include The Appropriate Header Filesinclude ltsqlclihgtinclude ltsqlcli1hgtinclude ltsqlutilhgtinclude ltsqlenvhgtinclude ltstdiohgt include ltiostreamgt include ltlocalehgt include ltstringhgtdefine SQL_SQLSTATE_SIZE 5define LOOPS 8

using namespace std

Define The CLI_Class Classclass CLI_Class

Attributespublic

SQLHANDLE EnvHandleSQLHANDLE ConHandleSQLHANDLE StmtHandleSQLRETURN rcSQLCHAR Job[6]SQLCHAR Name[10]SQLDOUBLE Comp

Operationspublic

CLI_Class()~CLI_Class()SQLRETURN ShowResults()

Constructor Destructor

SQLRETURN printError( SQLHDBC SQLHSTMT)

Define The Class ConstructorCLI_ClassCLI_Class()

setlocale( LC_ALL )

Initialize The Return Code Variablerc = SQL_SUCCESS

Allocate An Environment Handlerc = SQLAllocHandle(SQL_HANDLE_ENV SQL_NULL_HANDLE ampEnvHandle)

Allocate A Connection Handleif (rc == SQL_SUCCESS)

rc = SQLAllocHandle(SQL_HANDLE_DBC EnvHandle ampConHandle)

Define The Class DestructorCLI_Class~CLI_Class()

Free The Connection Handleif (ConHandle = NULL)

SQLFreeHandle(SQL_HANDLE_DBC ConHandle)

Free The Environment Handle

52

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

if (EnvHandle = NULL)SQLFreeHandle(SQL_HANDLE_ENV EnvHandle)

Define The ShowResults() Member FunctionSQLRETURN CLI_ClassShowResults(void)

While There Are Records In The Result Data Set Generated Retrieve And Display Themcout ltlt Name Job Compensation ltlt endlcout ltlt --------- ------ ------------ ltlt endlcoutsetf(iosleft)coutprecision(2)coutsetf(iosfixed)while (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)

rc = SQLFetch(StmtHandle)if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)

coutwidth(15)cout ltlt Name

coutwidth(10)cout ltlt Job

coutwidth(7)cout ltlt Comp ltltendl

if(rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO ampamp rc = SQL_NO_DATA)printError(ConHandle StmtHandle)

else

rc = 0SQLCloseCursor(StmtHandle)

Return The ODBC API Return Code To The Calling Functionreturn(rc)

SQLRETURN CLI_ClassprintError (SQLHDBC hdbc

SQLHSTMT hstmt)

SQLCHAR buffer[SQL_MAX_MESSAGE_LENGTH + 1]SQLCHAR sqlstate[SQL_SQLSTATE_SIZE + 1]SQLINTEGER sqlcodeSQLSMALLINT lengthSQLRETURN rcwhile ((rc = SQLError(SQL_NULL_HENV hdbc hstmt

sqlstateampsqlcodebufferSQL_MAX_MESSAGE_LENGTH + 1amplength)) == SQL_SUCCESS || rc ==

SQL_SUCCESS_WITH_INFO)

cout ltlt SQLSTATE ltlt sqlstate ltlt endlcout ltlt SQLCODE ltlt sqlcode ltlt endlcout ltlt Error msg ltlt buffer ltlt endl

53

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

cout ltlt----------------------------- ltlt endl ltlt endl

return(SQL_ERROR)

----------------------------------------------------------------- The Main Function -----------------------------------------------------------------int main()

Declare The Local Memory Variables

(SQLCHAR ) db2user SQL_NTS (SQLCHAR ) test26t SQL_NTS)

SQLRETURNSQLCHARSQLCHARSQLCHARchar

SQLCHAR

rc = SQL_SUCCESSDBName[10] = TPLXSQLStmt[255]c[10]ptrcurrentDepartment[8][15] = Head Office

New England Mid Atlantic South Atlantic Great Lakes PlainsPacificMountain

Create An Instance Of The CLI_Class ClassCLI_Class Example

Connect To iSeries Database if (ExampleConHandle = NULL)

rc = SQLConnect(ExampleConHandle DBName SQL_NTS

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)ExampleprintError(ExampleConHandle SQL_NULL_HSTMT)

return(rc)

cout ltlt Successfully connected to ltlt DBName ltlt ltlt endlrc = SQLSetConnectAttr(ExampleConHandle SQL_ATTR_AUTOCOMMIT

(SQLPOINTER) SQL_AUTOCOMMIT_OFF SQL_IS_UINTEGER) Allocate An SQL Statement Handlerc = SQLAllocHandle(SQL_HANDLE_STMT ExampleConHandle

ampExampleStmtHandle)if (rc == SQL_SUCCESS)

Define A SELECT SQL Statement

strcpy((char ) SQLStmt select name job salary + ifnull(comm0) ascompensation )

ptr = strcat( (char ) SQLStmt from org o staff s )ptr = strcat( (char ) SQLStmt where odeptnumb = sdept)ptr = strcat( (char ) SQLStmt and deptname = )ptr = strcat( (char ) SQLStmt order by compensation desc)

Prepare The SQL Statementrc = SQLPrepare(ExampleStmtHandle SQLStmt SQL_NTS)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)ExampleprintError(ExampleConHandle ExampleStmtHandle)

54

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

return(rc)

Bind The Columns In The Result Data Set Returned To Application Variables

rc = SQLBindCol(ExampleStmtHandle 1 SQL_C_CHAR (SQLPOINTER)ExampleName sizeof(ExampleName) NULL)

rc = SQLBindCol(ExampleStmtHandle 2 SQL_C_CHAR (SQLPOINTER)ExampleJob sizeof(ExampleJob) NULL)

rc = SQLBindCol(ExampleStmtHandle 3 SQL_C_DOUBLE (SQLPOINTER)ampExampleComp sizeof(ExampleComp) NULL)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO) ExampleprintError(ExampleConHandle ExampleStmtHandle)

return(rc)

while (true)

for (int i = 0 i lt LOOPS i++)

rc=SQLBindParameter(ExampleStmtHandle1SQL_PARAM_INPUTSQL_C_CHARSQL_CHAR

150(SQLPOINTER) currentDepartment[i8]0NULL)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)

ExampleprintError(ExampleConHandle ExampleStmtHandle)return(rc)

rc = SQLExecute(ExampleStmtHandle)if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)

ExampleprintError(ExampleConHandle ExampleStmtHandle)return(rc)

cout ltlt endl ltlt Current Dept ltlt currentDepartment[i8] ltlt

endl Display The Results Of The SQL QueryExampleShowResults()if(rc = 0)break

if ( i500 == 0 ampamp i gt 0 )cout ltlt Loops ltlt i ltlt ltlt endl

cout ltlt AFTER ltlt LOOPS ltlt loops Press X to exit ltlt endlcin gtgt cif (c[0] == x || c[0] == X)

break

Free The SQL Statement Handleif (ExampleStmtHandle = NULL )

SQLFreeHandle(SQL_HANDLE_STMT ExampleStmtHandle) Disconnect From The Northwind Sample Databaserc = SQLDisconnect(ExampleConHandle)

Return To The Operating Systemreturn(rc)

55

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 7 Adding a resource reference for an EJB

When you click ldquoFinishrdquo the reference definition is added to the EJB descriptor The new definition needs to be further modified To do so click on the (+) sign next to the EJB in the References list Click the new reference TestJDBCJ2C in this example to open the properties for the reference Change WebSphere Bindings and WebSphere Extensions sections as illustrated in Figure 8

15

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 8 Defining a resource reference for an EJB

Save the modified definition and then change the EJB source code to use the reference rather than directly DataSource

TroubleshootingTroubleshooting a multi-tier application may be a bit tricky because the developer needs to deal with software components that reside in separate partitions Three tools are particularly useful for pinning down the potential problem areas bull Joblog messages for a database server job mdash Provides enough details to isolate DB2 UDB for

iSeries runtime issues bull JDBC trace utility mdash Provides granular information about the data flow between the AIX

application and the iSeries server job bull Database Monitor ndash Provides detailed SQL runtime trace

Job Log MessagesAs mentioned a DB2 client communicates with a corresponding iSeries server job This server job runs the SQL requests on behalf of the client The iSeries database server jobs are called QZDASOINIT and they run in the QUSRWRK subsystem At any given time a large number of database server jobs may be active on the server so the first step is to identify the job that serves the particular client connection The easiest method to accomplish this task is to run the following CL command from the i5OS prompt

WRKOBJLCK OBJ(DB2USER) OBJTYPE(USRPRF)

Here DB2USER is the user profile that is used to connect to the iSeries server Note that a QZDASONIT job is assigned to a client after the connection has been established so the developer needs to set a breakpoint in the client application after the database connection has been established

Once the Work with Object Locks appears key in 5 (Work with Job) next to the only QZDASOINIT job that should be listed This shows the Work with Job dialog Select option 10 to

16

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

display the job log for the database server job Now the job log can be searched for any error messages generated by the DB2 runtime

Sometimes it is also useful to include debug messages in the job log The debug messages are informational messages written to the job log about the implementation of a query They describe query implementation methods such as the use of indexes join order ODP implementation (reusable versus non-reusable) and so on The easiest way to instruct an iSeries server to include the debug messages is to set the ServerTraceCategories property on the data source object

tkcpdssetServerTraceCategories(AS400JDBCDataSourceSERVER_TRACE_DEBUG_SERVER_JOB)

A sample of the job log messages with debug messages enabled is shown below

SET TRANSACTION completeSTATEMENT NAME FOUND QZ868F0A458E13AF8C Starting optimizer debug message for query Arrival sequence access was used for file COFFEESODP created ODP not deleted 5000 rows inserted in COFFEES in DB2USER STATEMENT NAME FOUND QZ868F0A4C144BF12EBlocking used for queryCursor CRSR0001 opened606 rows fetched from cursor CRSR0001 ODP not deleted Cursor CRSR0001 closed

So the job log offers fairly detailed information on how the AIX client requests were implemented by the DB2 runtime

JDBC Trace UtilityThe JTOpen driver provides a tracing utility which can be used to collect detailed client-side traces The JDBC tracing is turned off by default It can be enabled by setting the Trace property to true Heres an example of how to switch on tracing using the setTrace method on the data source object

tkcpdssetTrace(true)

The trace can also be enabled when using the DriverManagergetConnection() method for obtaining a connection to DB2 UDB for iSeries In this case the developer could add the trace property to the connection string This approach is illustrated in the following code snippet

ClassforName(comibmas400accessAS400JDBCDriver) [1] hellip con = DriverManagergetConnection(jdbcas400teraplextrace=true

db2userdb2pwd) [2]

At [1] an instance of the JTOpen JDBC Driver is initiated Then at [2] the driver is used to obtain a connection to the iSeries server Note how the trace property has been added to the database URL See the IBM Toolbox for Java JDBC properties documentation on the iSeries Information Center Web site for a complete list of properties supported by the JTOpen driver

Although the level of details provided by the trace utility is sufficient in most troubleshooting scenarios sometimes the developer may need to collect low-level traces scoped to a certain type

17

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

of information In V5R3 the IBM Toolbox for Java (as well as the latest JTOpen) added a comprehensive detailed trace facility The following is the complete list of detailed trace parameters and their purpose

bull None or ldquordquo ndash This setting disables the detailed trace bull datastream - This category is used by Toolbox classes to log dataflow between the local host

and the remote system It is not intended for use by application classes bull diagnostic - This category is used to log object state information bull error - This category is used to log errors that cause an exception bull information - This category is used to track the flow of control through the code bull warning - This category is used to log errors that are recoverable bull conversion - This category is used by Toolbox classes to log character set conversions

between Unicode and native code pages bull proxy - This category is used by Toolbox classes to log data flow between the client and the

proxy server bull pcml - This category is used to determine how PCML interprets the data that is sent to and

from the server bull jdbc - This category is used to track JDBC calls throughout the program bull thread - This category is used to enable tracing of thread information This is useful when

debugging multi-threaded applications bull all - This category will enable all previous categories

The detailed trace can be enabled when using the DriverManagergetConnection() method for obtaining a connection to DB2 UDB for iSeries In this case the developer could add the toolbox trace property to the connection string This is illustrated in the following code sample

String dbUrl = jdbcas400pwd1toolbox trace=diagnostic con = DriverManagergetConnection(dbUrl dbUser dbPassword)

Note that currently the driverrsquos DataSource interfaces do not allow the developer to directly activate the detailed tracing However they could set the server from the command line at the time the java program is launched The example below shows how the detailed trace properties could be enabled at the command line

java -Dcomibmas400accessTracecategory=diagnostic TestJDBC

The -D switch indicates to the java interpreter that the information following it will be a system property

In case of a WebSphere application the trace property can be set through the admin console In the console select Application Servers-gt server1-gt Process Definition -gt Java Virtual Machine Figure 9 shows how to set the Generic JVM Arguments for an application server instance

18

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 9 Setting JVM arguments to enable detailed Toolbox tracing

Database Monitor

The database monitor is the ultimate tool available on DB2 UDB for iSeries to collect low-level SQL traces It is mainly used to pin down the SQL performance problems Refer to the lsquoUsing iSeries Database Monitor to Identify and Tune SQL Queriesrsquo white paper for a detailed discussion on how to collect and analyze the database monitor traces httpibmcomserversenablesiteeducationiborecordhtmldtmon

IBM DB2 JDBC Universal Driver DB2 JDBC Universal Driver is one of the new features delivered with DB2 UDB Version 8 DB2 JDBC Universal Driver has been designed to eliminate the dependency on DB2 CLI runtime modules as well as to enable direct Type 4 connectivity to DB2 UDB for iSeries and DB2 UDB for zOSreg

The pure-Java (Type 4) remote connectivity is based on the DRDA open distributed protocol for cross-platform access to DB2 DRDA defines the rules the protocols and the semantics for accessing distributed data Applications can access data in a distributed relational environment by using SQL statements The iSeries DRDA application server implementation is based on multiple connection-oriented server jobs running in the QSYSWRK subsystem A DRDA listener job (QRWTLSTN) listens for TCP connect requests on port 446 Once an application requester connects to the listener job the listener wakes up one of the QRWTSRVR prestart jobs and assigns it to a given client connection Any further communication occurs directly between the client application and the QRWTSRVR job These concepts are illustrated in Figure 10

19

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 10 Accessing DB2 UDB for iSeries with DB2 Universal Driver

The DB2 Universal Driver can be loaded in an AIX partition by installing one of the DB2 Connect for AIX products (see the Additional Information section for details) It is also a part of a DB2 Enterprise Server Edition for AIX install Specifically the developer needs three JAR files in a AIX partition to successfully connect to an iSeries server db2jccjar db2jcc_license_cisuzjar and db2jcc_license_cujar The iSeries license is contained in db2jcc_license_cisuzjar Note that this file is not a part of DB2 Client In other words a DB2 Connect license is required to use the driver in production environments The location of the JAR files needs to be added to the CLASSPATH environment variable For instance the following entry could be added to the AIX profile script

CLASSPATH=homedb2inst2sqllibjavadb2jccjarCLASSPATH=$CLASSPATHhomedb2inst2sqllibjavadb2jcc_license_cujarCLASSPATH=$CLASSPATHhomedb2inst2sqllibjavadb2jcc_license_cisuzjarexport CLASSPATH

Java Runtime 131 is a prerequisite

Additionally the developer should install the latest database group PTF (SF99503 for i5OS V5R3) on the iSeries server The Informational APAR ii13348 is keeping track of any fixes relevant to DRDA above and beyond the current database group PTF

Obtaining a Connection to DB2 UDB for iSeries When Type 4 connectivity is used the DB2 Universal Driver connects directly to the DB2 on iSeries through TCPIP Note that this is different from the legacy DB2 Type 2 JDBC driver that requires a DB2 node and remote database configurations on the client accessing iSeries The following code snippet illustrates how to use the DB2 JDBC Universal Driver to obtain a connection to DB2 UDB for iSeries

20

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

try ClassforName(comibmdb2jccDB2Driver) [1] catch(javalangClassNotFoundException e) Systemerrprint(ClassNotFoundException )Systemerrprintln(egetMessage())

try DriverManagergetConnection(jdbcdb2teraplex446TERAPLEX[2]

db2userdb2pwd) hellip catch(SQLException ex) Systemerrprintln(

SQLException + exgetMessage())

At [1] an instance of the DB2 JDBC Universal Driver is instantiated Then at [2] the driver is used to obtain a connection to the iSeries server Note the proper form of the database URL required by the driver

Considerations There are several advantages of DB2 JDBC Universal Driver bull Ease of cross-platform development mdash Consistent coding techniques and consistent error

codes and messages bull Ease of deployment mdash Pure Java (no runtime client required) and a single driver for accessing

DB2 on different platforms

The ease of use comes at a price though The iSeries JTOpen driver is optimized for accessing DB2 UDB for iSeries data and it uses native iSeries protocol to communicate with the back-end database server job This usually results in better performance and more-efficient system resources utilization For instance when using the DB2 JDBC Universal Driver to access an iSeries server the executeBatch method results in a single record insert There are also some restrictions when using DB2 Universal JDBC Driver with Type 4 connectivity

bull Support for distributed transactions (JTA) is not enabled bull Driver built-in connection pooling is not supported

Refer to Java application support in DB2 for more details on DB2 JDBC Universal Driver

21

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 Connect data access This section will explore the most important aspects of DB2 Connect ndash iSeries integration - including configuration tips and coding examples

DB2 Connect provides functionality for accessing data stored in DB2 UDB for iSeries as well as DB2 UDB for zOS and DB2 UDB for OS390reg DB2 Connect offers capabilities to access DB2 family members via several SQL interfaces gateway functions such as connection pooling and federated database functionality Many applications supporting the DB2 family of products leverage DB2 Connect as a key middleware component DB2 Connect is offered as separate AIX license products

Enterprise Edition Application Server Edition

In addition to DB2 Connect there are several other DB2 UDB Version 81 products that are supported on AIX

DB2 Universal Database Enterprise Server Edition DB2 Universal Database Workgroup Server Unlimited Edition DB2 Universal Database Workgroup Server Edition DB2 Universal Database Universal Developers Edition All Clients

The DB2 Connect Enterprise Edition functionality is also contained in DB2 Enterprise Server Edition for AIX

22

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 Connect in a nutshell In the scenario described in this paper the DB2 Connect functions contained in DB2 Enterprise Edition for AIX are utilized DB2 Connect Enterprise Edition provides support for both local and remote DB2 clients This is illustrated in Figure 11 Accessing DB2 UDB for iSeries with DB2 Connect

Figure 11 Accessing DB2 UDB for iSeries with DB2 Connect

DB2 Connect implements the Distributed Relational Database Architecturetrade (DRDAreg) to reduce the cost and complexity of accessing data stored in DB2 UDB for iSeries and other DRDA-compliant database servers DRDA defines the rules the protocols and the semantics for accessing distributed data Applications can access data in a distributed relational environment by using SQL statements In a distributed environment the system running the application and sending the SQL requests across the network is called the application requester (AR) A remote database server that executes SQL requests submitted by an application requester is known as the application server (AS) In the example shown in Figure 11 (above) DB2 Connect plays the role of an application requester while DB2 UDB for iSeries is an application server In this case DB2 Connect communicates with the iSeries database through TCPIP The iSeries DRDA application server implementation is based on multiple connection-oriented server jobs running in the QSYSWRK subsystem A DRDA listener job (QRWTLSTN) listens for TCP connect requests on port 446 Once an application requester connects to the listener job the listener wakes up one of the QRWTSRVR prestart jobs and assigns it to a given client connection Any further communication occurs directly between the client application and the QRWTSRVR job

DB2 Connect supports a wide range of programming interfaces that can be used by AIX applications to access the iSeries database Embedded SQL frac34 Both static and dynamic SQL frac34 Various programming languages (Java CC++ Cobol Fortran REXX)

DB2 Call Level Interface (DB2 CLI) ODBC JDBC frac34 DB2 JDBC Type 2 Driver frac34 DB2 JDBC Type 4 Driver (Universal JDBC Driver)

23

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Note that DB2 Connect supports access to DB2 UDB for iSeries through DB2 JDBC Universal driver However for performance and ease of maintenance reasons IBM recommends that Java applications running in AIX use native iSeries Toolbox JDBC driver See the JDBC Data Access section of this paper (above) for more details On the other hand DB2 Connect is a very efficient and robust connectivity option for AIX applications especially in the environments that are not directly supported by the native iSeries JDBC driver Here are several possible scenarios that would require DB2 Connect installed in a AIX partition

Embedded SQL interface is used to access DB2 CLI or ODBC interface is used to access DB2 A single SQL interface is needed to access multiple back end DB2 server Specific DB2 Connect functionality is needed such as distributed join or connection

pooling

Prerequisites One of the DB2 Connect products or DB2 Enterprise Server Edition for AIX V81 is needed Additionally DB2 Application Development Client is required in the AIX partition to compile DB2 applications

For maximum database server stability the developer should install the latest database group PTF (SF99503 for i5OS V5R3) on the iSeries server The Informational APAR ii13348 is keeping track of any fixes relevant to DRDA above and beyond the current database group PTF

DB2 Connect configuration The following example employs i5OS V5R3 and DB2 UDB Enterprise Server Edition for AIX Version 81 FixPak 6

Configuration steps in the iSeries partition The following process lists the necessary steps to be performed on the iSeries server 1) Verify that the TCPIP stack is working correctly It is assumed that the Virtual LAN is used to

communicate with the i5OS partition First obtain the IP address of the iSeries server or its hostname and ping the iSeries server from the AIX partition

2) Create a relational database (RDB) entry for the iSeries database in the i5OS partition If this has already been created it can be displayed by using the DSPRDBDIRE command Make sure that the RDB entry with a location of LOCAL exists on the iSeries server If it does not exist use the ADDRDBDIRE command to add the appropriate RDB entry For example the following command would add an RDB entry named TPLX For simplicity it is recommended that the TCPIP host name and RDB entry remain the same

ADDRDBDIRE RDB(TPLX) RMTLOCNAME(LOCAL)

3) Create a collection called NULLID This is necessary because the utilities shipped with DB2 Connect and DB2 UDB for AIX store their packages in the NULLID collection Since it does not exist by default in the iSeries server you must create it using the following command

CRTLIB LIB(NULLID)

4) Products that support DRDA automatically perform any necessary code page conversions at the receiving system For this to happen both systems need a translation table from their code page to the partner code page The default Coded Character Set Identifier (CCSID) on the iSeries server is 65535 Since DB2 Connect does not have a translation table for this code page the developer needs to change the individual user profiles to contain a CCSID that can be converted properly by DB2 Connect For US English this is 037 For other languages see DB2 Connect Personal Edition Quick Beginning GC09-2967 The following command changes the CCSID for an individual user profile to 037

24

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

CHGUSRPRF userid CCSID(037)

5) Verify that the default port 446 for DRDA service is being used To do this go to the Configure TCPIP menu (CFGTCP) select Configure Related Tables and then select Work with service table entries Verify that the DRDA service is set for port 446

6) The Distributed Data Management (DDM) job must be started for DRDA to work If you want the DDM job to be automatically started whenever TCPIP is started change the attributes of the DDM job using the CHGDDMTCPA command and set the Autostart server parameter to YES

7) If the system administrator chooses not to autostart the server issue the following command to start the DDM server job

STRTCPSVR SERVER(DDM)

8) Make sure that the user profiles that will be used to connect to the iSeries server exist on the server

25

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Configuration steps in the AIX partition The following steps are required for DB2 Connect to be configured in the AIX partition 1) Sign on to the AIX partition as the DB2 administrator 2) Launch Client Configuration Assistant (db2ca from the command prompt) It is assumed that

VNC or an X-Windows server are being used on the workstation so that the db2ca GUI can be properly rendered

3) From the Selected pull-down menu select the Add Database using Wizard option The Select how you want to setup a connection dialog appears Select Manually configure a connection to a database and click Next This is shown in Figure 12

Figure 12 Accessing DB2 UDB for iSeries with DB2 Connect

26

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

4) On the Select a communications protocol choose TCPIP and select The database physical resides on a host or OS400 system Then select the option Connect directly to the server as shown in Figure 13 Click Next

Figure 13 mdash Selecting communications protocol

27

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

5) On the TCPIP tab fill in the host name of the iSeries server The port number should be 446 This is shown in Figure 14 Click Next

Figure 14 mdash Specifying TCPIP communication parameters

28

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

6) On the Database tab fill in the Relational Database name Use the RDB entry name (specified in step 2) in the Configuration steps in the iSeries partition section as shown in Figure 15 Click Next

Figure 15 mdash Specifying the remote database

7) If you plan to use the ODBC applications select Register this database for ODBC as a system data source on the ODBC tab Click Next

29

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

8) On the Specify the node option dialog select OS400 from the Operating System pull-down menu This is shown in Figure 16 Click Finish

Figure 16 mdash Specifying the node options

30

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

9) The Test Connection dialog appears This allows the developer to verify that the connection works Select both CLI and JDBC check boxes You are also prompted for an iSeries user ID and password as shown in Figure 17

Figure 17 mdash Testing the connection

31

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

10) The successful connection to the database server is confirmed by the message box shown in Figure 18

Figure 18 mdash Test Connection results 11) At this time a newly configured database connection should appear in the main DB2

Configuration Assistant window It is recommended that the DB2 utilities are also bound to the iSeries database The bind process creates the necessary SQL packages on the remote database In the main Configuration Assistant window click the TPLX database entry and then select Selected-gtBindhellip

32

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

12) The Bind dialog appears Click Select All and then enter the connection information as shown in Figure 19 Click Bind The Results message box appears This allows the developer to monitor the progress of the binding process Watch for any error and warning messages

Figure 19 mdash Binding the DB2 utilities This concludes the DB2 Connect configuration steps

33

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Accessing DB2 UDB for iSeries from C embedded SQL

As mentioned earlier DB2 Connect allows developers to compile and run embedded SQL applications that access DB2 UDB for iSeries data This section covers implementation details for a C embedded SQL application called cursorsjsqc (see Appendix B for source code)

Prerequisites An embedded SQL application running in an AIX partition will use DB2 Connect services to access DB2 UDB for iSeries therefore the developer needs to make sure that all components listed in section Prerequisites on page 24 are installed The developer also needs to create a remote database connection as described in the DB2 Connect configuration section of this paper on page 24

Static SQL and SQL packages To successfully run against a DB2 UDB for iSeries database an embedded SQL application needs to be first precompiled and bound to the back-end database This process creates an SQL package on the target iSeries server The SQL package contains the access plan information for the SQL statements executed by the application The internal structure of the package as well as the method how its content is used by the SQL runtime to facilitate the access plan reuse is similar to the Extended Dynamic SQL support covered in detail in the Extended Dynamic SQL and Statement Caching section of this paper (on page 9) There are however important differences between the packages created by the extended dynamic SQL support and the packages created for embedded SQL DRDA client applications The extended dynamic SQL packages support dynamic SQL interfaces such as JDBC

that can submit ad hoc SQL statements at the run time The SQL runtime can prepare the dynamic statements and add them to the package On the other hand the DRDA packages are created at the precompile time and contain static SQL In order to add new statements to the package the application needs to be precompiled and rebound again

The extended dynamic SQL package can dynamically grow up to 500MB by allocating new space as required The DRDA packages since they are created at the precompile time have a fix size and do not grow over their life time

Simple embedded SQL application The application is based on a source code provided in the DB2 UDB samples directory typically to be found at homedb2inst1sqllibsamples The cursorsjsqc performs a join between STAFF and ORG tables located in DB2USER schema (library) on the TPLX database server (the source is provided at the end of this paper in Appendix B) The join statement retrieves the DEPTNAME column from ORG NAME column from STAFF and calculates the total compensation for an employee by adding SALARY and COMM columns in STAFF The results are sorted by department name and total compensation Here is the SELECT statement used by the application

SELECT deptname name salary + IFNULL(comm0) as compensationFROM org o staff sWHERE odeptnumb = sdeptORDER BY deptname compensation DESC

The application iterates through the selected records and prints out the data to the standard output device The sample DB2USER schema was created with the following SQL statements

db2 CONNECT TO tplx USER db2user USING mypassworddb2 CALL QSYSCREATE_SQL_SAMPLE(DB2USER)

34

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Make sure that the AIX partition is logged into with the DB2 admin user profile If the defaults were selected at the DB2 installation time this profile name is db2inst1 It is also assumed that DB2USER user exists on the iSeries server and that it has appropriate authority

There are several steps that are required to create an executable for the cursorsjsqc source code First the DB2 PRECOMPILE utility needs to be called The utility creates a bind file that is used to bind the required SQL package to the TPLX database It also converts embedded SQL statements into DB2 run-time API calls and produces a pure C source file that can be processed by an AIX C compiler

db2 CONNECT TO tplx USER db2user USING mypassworddb2 prep cursorsjsqc bindfile

Note that the connect statement is required only if the developer is not already connected to the database on an iSeries server Watch for any error or warning messages returned by the DB2 prep utility The prepare step should produce cursorsjbnd and cursorsjc files in the current directory Now the developer can invoke the bind utility to prepare the statements contained in the bind file and create the package on the target iSeries database server

db2 bind cursorsjbnd

It is assumed that Visual C++ 60 is installed and configured in the AIX partition Refer to the ldquoDeveloping and Porting C and C++ Applications on AIXrdquo redbook for more information on how to use the Visual C++ compiler httpibmcomredbooksabstractssg245674htmlOpen

Use the following commands to compile the C source generated by the precompile utility

xlc -I$INSTHOMEsqllibinclude ndashc cursorsjcxlc ndasho cursorsj cursorsjo -L$INSTHOMEsqlliblib ndashldb2

Run the program from the AIX prompt

cursorsj db2user mypassword

Distributed Join DB2 UDB Version 8 provides core federated server functionality A federated system consists of a DB2 UDB instance that operates as a federated server a database that acts as the federated database one or more data sources and clients (users and applications) that access the database and data sources Federated server permits objects stored in multiple databases to be accessed together in the same query For example a query can refer to a table that resides in DB2 UDB for iSeries and join it to a table stored in DB2 UDB for AIX Such a query would constitute so called distributed join The support for DB2 UDB for iSeries as a federated data source is provided by core federated server functionality directly implemented in DB2 UDB Enterprise Server Edition and DB2 UDB Connect Enterprise Edition All other DB2 UDB family members are also supported directly by core DB2 UDB federated server An additional software product DB2 Information Integratortrade is required to access non-DB2 UDB databases such as Oracle Sybase or Microsoftreg SQL Server Consult the following white papers for a detailed discussion on DB2 federated server support Heterogeneous data access for iSeries applications Version 2 httpibmcomserversenablesiteeducationiborecordhtmlhetdata Fundamentals of IBM DB2 Federated Server and Relational Connect httpwww7bsoftwareibmcomdmddlibrarytecharticle0206purnell0206purnellhtml

35

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Distributed Join Example In this section the steps that are required to configure DB2 UDB for iSeries as a federated data source will be illustrated Then the cursorsjsqc program will be ldquotweakedrdquo so that it executes a distributed join query that accesses data stored on an iSeries server and in the local DB2 UDB for AIX database It is assumed that the developer is familiar with the DB2 federated server concepts

Note Run the following commands from the Command Line Processor prompt Load the utility by executing the db2 command at the AIX prompt 1) First the local DB2 UDB for AIX instance needs to be enabled as a DB2 federated server

This is done by setting the database manager configuration parameter FEDERATED to YES

db2=gt update dbm cfg using FEDERATED YES

The database instance needs to be restarted for the change to take effect

NOTE A federated database is a regular database in a DB2 UDB instance that has the FEDERATED parameter enabled Therefore in this example the SAMPLE database that was created earlier is used as the federated database A new database can also be created using the CREATE DATABASE command

2) Connect to the federated database

db2=gt connect to sample

3) Use the CREATE WRAPPER statement to register a wrapper for the iSeries data source Wrappers are library routines that are used by the federated server to perform operations such as connecting to a data source and retrieving data from it The default wrapper name for DB2 UDB for iSeries is DRDA Here is the command to register the DRDA wrapper

db2=gt create wrapper drda

4) Use the CREATE SERVER statement to register a data source as a server within the federated database The server definition specifies the type and version of the data source and the wrapper used for communications with this data source For the DB2 UDB for iSeries data source the node and the database names are also needed The node and database name parameters have been configured for our TPLX database in the Configuration steps in the AIX partition section (on page 24) Use the following DB2 UDB command to lookup these parameter on the federated server

db2=gt list database directory

In this case the command produced the following output

Database alias = TPLX Database name = DCSE99E1 Node name = NDE9BF76 Database release level = a00 Comment = Directory entry type = Remote Authentication = SERVER Catalog database partition number = -1

36

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Note that the node name is set to NDE9BF76 The name was generated by the Configuration Administrator utility (db2ca)

Here is the command to register the TPLX database as a federated server

db2=gt create server tplx type db2400 version 530 wrapperdrda authorization db2user password mypassword options(nodeNDE9BF76 dbname TPLX)

The command is quite complex so make sure that the syntax is correct

5) Define the user mappings that instructs the federated server what user ID and password should be used when connecting to the iSeries data source

db2=gt create user mapping for user server tplxoptions(remote_authid db2user remote_password mypassword)

Specify the nickname for the iSeries table or view A nickname is an identifier that is used by the federated server to reference an object located at the data source The following command creates a nickname for the STAFF table located in the DB2USER schema on the TPLX database

db2=gt create nickname tplx_staff for tplxdb2userstaff

6) Test the distributed join query

db2=gt SELECT deptname name salary + COALESCE(comm0) ascompensation FROM org o tplx_staff s WHERE odeptnumb =sdept ORDER BY deptname compensation DESC

Note that the native iSeries function IFNULL has been substituted with an equivalent DB2 UDB function COALESCE COALESCE is also supported on iSeries servers For better portability IBM encourages the use of COALESCE rather than IFNULL Note also that the query runs on the federated server rather than on TPLX It accesses the ORG table in the local DB2 UDB for AIX SAMPLE database and the STAFF table that resides in TPLX The federated server performs the necessary distributed join

7) Modify the cursorsjsqc so that it executes a distributed join There are two source code modifications - Change the CONNECT TO statements Now the application needs to connect to the

federated database SAMPLE rather than to TPLX

EXEC SQL CONNECT TO SAMPLEEXEC SQL CONNECT TO SAMPLE USER userid USING passwd

- Modify the select statement so that it performs a distributed join Use the statement (shown in step 6) above Save the new source version as cursordjsqc

- Prepare bind and compile the distributed join version of the program as described in the Simple C embedded SQL application section (on page 34)

db2 prep cursordjsqc bindfiledb2 bind cursordjbndxlc -I$INSTHOMEsqllibinclude ndashc cursordjcxlc ndasho cursordj cursordjo -L$INSTHOMEsqlliblib ndashldb2

37

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

- Run the program from the AIX prompt

cursordj

Connection Pooling and Connection ConcentratorA modern Web-based application typically executes a large number of short-lived transactions Executing a transaction in this environment means establishing a database connection executing a few SQL statements and terminating this connection Creating connections to the database server is a very costly process To reduce the unnecessary workload DB2 Connect implements connection pooling and connection concentrator Connection pooling mechanism allows DB2 Connect to reuse an existing connection infrastructure for subsequent connection requests The connection concentrator is an advanced technology that allows DB2 Connect to serve a potentially very large number of clients with a limited number of database connections This is accomplished by decoupling clients from a particular database connection

Note that currently neither connection pooling nor connection concentrator support DB2 UDB for iSeries Therefore for performance reasons the author strongly recommends that the application server that obtains and drops connections very frequently implements its own database connection pooling mechanism that would assign an existing pooled database connection to a new AIX process or thread

TroubleshootingTroubleshooting a multi-tier application may be a bit tricky because the developer needs to deal with software components that reside in separate partitions The authorrsquos experience shows that two tools are particularly useful for pinning down the potential problem areas The joblog messages for a database server job usually provide enough details to isolate DB2

UDB for iSeries runtime issues The DRDA trace utility provides granular information about the data flow between the AIX

application and the iSeries server job

38

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Job Log MessagesAs mentioned earlier a DB2 client communicates with a corresponding iSeries server job This server job runs the SQL requests on behalf of the client More precisely when a DB2 client submits an SQL statement the statement is passed to a server job that in turn calls the DB2 runtime to execute the statement The results are then reformatted and marshaled to the client The iSeries DRDA server jobs are called QRWTSRVR and they run in the QUSRWRK subsystem At any given time there may be a large number of DRDA server jobs active on the system so the first step is to identify the job that serves the particular client connection The easiest method to accomplish this task is to run the following CL command from the i5OS prompt

WRKOBJLCK OBJ(DB2USER) OBJTYPE(USRPRF)

Here DB2USER is the user profile that is used to connect to the iSeries server Note that a QRWTSRVR job is assigned to a client after the connection has been established so the developer needs to set a breakpoint in the client application below the CONNECT TO statement

Once the Work with Object Locks appears key in 5 (Work with Job) next to the only QRWTSRVR job that should be listed This shows the Work with Job dialog Select option 10 to display the job log for the database server job Now the developer can search the job log for any error messages generated by the DB2 runtime

Sometimes it is also useful to include debug messages in the job log The debug messages are informational messages written to the job log about the implementation of a query They describe query implementation methods such as use of indexes join order ODP implementation (reusable versus non-reusable) and so on The easiest way to instruct the iSeries server to include the debug messages is to call the following stored procedure just after the connection to the iSeries server is established

EXEC SQL call qsysqcmdexc(STRDBGUPDPROD(YES)000000002000000)

A sample of the job log messages with debug messages enabled is shown below in Figure 20

Arrival sequence access was used for file STAFFAccess path suggestion for file STAFFQuery options used to build the OS400 query access plan Ending debug message for query ODP created Blocking used for queryCursor SQLCUR201 opened1 rows fetched from cursor SQLCUR201Row not found for SQLCUR201ODP deleted Cursor SQLCUR201 closedDESCRIBE of prepared statement STMT0201 completed

Figure 20 mdash Joblog with debug messages enabled

So the job log offers fairly detailed information on how the AIX client requests were implemented by the DB2 runtime

39

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 DRDA trace utilityThe DB2 DRDA trace utility (db2drdat) provides detailed information about the data streams exchanged between DB2 Connect and target database server The output file produced by the utility contains send and receive communications buffers TCPIP error messages and SQL Communications Area (SQLCA) information Please refer to lsquoDB2 Connect Userrsquos Guidersquo manual for in-depth discussion of the DRDA trace utility

Accessing DB2 UDB for iSeries from CLI DB2 Call Level Interface (CLI ) is based on the Microsoft Open Database Connectivity (ODBC) specification and the ISO CLI standard The DB2 CLI interface gained popularity among DB2 application providers because the developer can build an ODBC application by simply linking the application with libdb2 library on a UNIX server In other words the developer directly utilizes the DB2 ODBC driver services without a need for an ODBC driver manager Additionally in contrast to embedded SQL the developer does not need to precompile or bind DB2 CLI applications because they use packages provided with DB2 UDB The developer simply compiles and links the application

Prerequisites A DB2 CLI application running in an AIX partition will use DB2 Connect services to access DB2 UDB for iSeries therefore make sure that all components listed in Prerequisites section of this paper on page 24 are installed The developer also needs to create a remote database connection as described in the DB2 Connect configuration section of this paper on page 24

Dynamic SQL and Access Plan Caching A DB2 CLI client application uses the dynamic SQL interface and does not have the capability to utilize the extended dynamic SQL support Therefore it runs lsquopurersquo dynamic SQL statements That does not mean however that the process of parsing validating and optimizing will be repeated for every execution of a given dynamic SQL statement

The DB2 UDB for iSeries database implements an internal object called System-Wide SQL Statement Cache (SWSC) The SWSC can improve the performance of programs using dynamic SQL statements by caching the access plans in a system-wide cache When a dynamic SQL statement is submitted the SQL runtime searches the SWSC to see if this statement has been previously executed If so then DB2 retrieves and reuses the key information associated with the cached statement and thereby the processing time and the resources utilization can be significantly reduced

Simple DB2 CLI C++ ApplicationThis section covers DB2 CLI implementation details for a sample C++ program called testclicpp (the source is provided at the end of this paper in Appendix C) To compile the source with Visual C++ complier use the following command in the AIX partition

xlC ndashI$INSTHOMEsqllibinclude ndashc testclicppxlC ndasho testcli testclio ndashL$INSTHOMEsqlliblib ndashldb2

The application performs a join between STAFF and ORG tables located in DB2USER schema (library) The join statement retrieves the DEPTNAME column from ORG NAME and JOB columns from STAFF and calculates the total compensation for an employee by adding SALARY and COMM columns in STAFF The results are sorted by total compensation The selection criterion is based on the current value of the department name parameter Here is the SELECT statement used by testcli

40

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

select name job salary + coalesce(comm0) as compensationfrom org o staff swhere odeptnumb = sdeptand deptname = order by compensation desc

Figure 21 shows the software components involved in the execution of this sample application

Figure 21 How a DB2 CLI client accesses DB2 UDB on an iSeries server

Although the testcli application is fairly simple it covers some important aspects of efficient CLI programming for DB2 UDB for iSeries

Reusable Open Data Paths (ODPs)An Open Data Path (ODP) definition is an internal i5OS object that is created when certain SQL statements (such as OPEN INSERT UPDATE and DELETE) are executed for the first time in a given job (or connection) The ODP can be thought of as a runtime implementation of an access plan The access plan created at the optimization time provides a recipe or in other words a sequence of steps necessary to execute the statement The ODP on the other hand provides the executable code for all requested IO operations The process of creating new ODP objects is fairly CPU- and IO-intensive so whenever possible the iSeries DB2 runtime tries to reuse existing ODPs For instance a SQLCloseCursor() API call may close the SQL cursor but leave the ODP available to be used the next time the cursor is opened This can significantly reduce the processing and response time in running SQL statements A reusable OPD usually requires 10 to 20 times less CPU resources than a newly created ODP Therefore it is important that the applications employ programming techniques that allow the DB2 runtime to reuse ODPs

With dynamic interfaces such as CLI full opens are avoided by using a prepare once execute many programming paradigm It means that when an SQL statement is going to be executed more than once you should prepare the statement just once and then reuse the prepared

41

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

statements for consecutive executions Although DB2 UDB does try to convert literals to parameter markers so that similar statements can be reused it is a better programming practice to explicitly implement parameter markers That way the chances for reusable ODPs are quite significantly improved The code snippet in Figure 22 illustrates how to implement the prepare once execute many programming technique

Define A SELECT SQL Statementstrcpy((char ) SQLStmt select name job salary + ifnull(comm0) ascompensation )ptr = strcat( (char ) SQLStmt from org o staff s )ptr = strcat( (char ) SQLStmt where odeptnumb = sdept)ptr = strcat( (char ) SQLStmt and deptname = )ptr = strcat( (char ) SQLStmt order by compensation desc) [1]

Prepare The SQL Statementrc = SQLPrepare(ExampleStmtHandle SQLStmt SQL_NTS) [2]

Bind The Columns In The Result Data Set Returned To Application Variablesrc = SQLBindCol(ExampleStmtHandle 1 SQL_C_CHAR (SQLPOINTER)

ExampleName sizeof(ExampleName) NULL)rc = SQLBindCol(ExampleStmtHandle 2 SQL_C_CHAR (SQLPOINTER)

ExampleJob sizeof(ExampleJob) NULL)rc = SQLBindCol(ExampleStmtHandle 3 SQL_C_DOUBLE (SQLPOINTER)

ampExampleComp sizeof(ExampleComp) NULL)

for (int i = 0 i lt LOOPS i++)rc=SQLBindParameter(ExampleStmtHandle

1SQL_PARAM_INPUTSQL_C_CHARSQL_CHAR10(SQLPOINTER) currentDepartment[i8]0NULL) [3]

rc = SQLExecute(ExampleStmtHandle) [4]cout ltlt endl ltlt Current Dept ltlt currentDepartment[i8] ltlt endl Display The Results Of The SQL QueryExampleShowResults()

Figure 22 Use the prepare once execute many programming technique

The error-handling code has been removed for clarity At [1] the statement text is assigned to a variable Note that a parameter marker is used in the WHERE clause The statement is then prepared just once at [2] The current value of the parameter is bound to the prepared statement at [3] The prepared statement is executed at [4] Steps [3] and [4] are repeatedly executed in a for loop

Techniques to Further Improve DB2 CLI Performance Thus far this paper has discussed the techniques used by a sample application to tune the CLI performance However depending on the application architecture other methods of improving CLI performance may be considered

Connection PoolingCurrently the CLI application connecting through DB2 Connect to DB2 UDB for iSeries does not take advantage of the connection pooling mechanism implemented by DB2 Connect Therefore for performance reasons the author strongly recommends that the application server that obtains and drops connections very frequently implements its own database connection pooling mechanism that would assign an existing pooled database connection to a new AIX process or thread

42

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Blocking

For queries which result in returning large data blocks from the iSeries server (usually 32K of data and above) ensure that the database manager configuration parameter RQRIOBLK is set to 32767 This can be done using the Command Line Processor (CLP) as follows

db2 update database manager configuration using RQRIOBLK 32767

TroubleshootingThe experience of the author shows that two tools are particularly useful for pinning down the potential problem areas bull Joblog messages for a database server job usually provides enough details to isolate DB2

runtime issues bull CLI trace utility provides granular information about the data flow between the AIX application

and the database server job

Job Log MessagesThe process of finding and analyzing the job log for a DB2 CLI connection is identical to the process outlined for an embedded SQL application in the Job Log Message section of this paper on page 39

CLI Trace The DB2 CLIODBCJDBC trace utility provides very detailed information about the data streams exchanged between DB2 Connect and target database server Refer to the DB2 Information Center for more information on how to set up and analyze the CLI traces httppublibboulderibmcominfocenterdb2v8luwindexjsptopic=comibmdb2udbdocadc000 7959htm

43

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Trademarks

IBM eServer iSeries AIX AIX 5L i5OS WebSphere DB2 DB2 Universal Database DB2 Connect OS400 zOS OS390 Distributed Relational Database Architecture DRDA and DB2 Information Integration are trademarks or registered trademarks of International Business Machines Corporation in the United States and other countries

Java and all Java-based trademarks are trademarks of Sun Microsystems Inc in the United States other countries or both

Linux is a registered trademark of Linus Torvalds in the United States other countries or both

UNIX is a registered trademark of The Open Group in the United States and other countries

Microsoft and Windows are registered trademarks of Microsoft Corporation in the United States andor other countries

All other registered trademarks and trademarks are properties of their respective owners

IBM makes no commitment to make available any products referred to herein

References in this publication to IBM products or services do not imply that IBM intends to make them available in every country in which IBM operates

Additional Information ITSO offers a Redbook that can be helpful to those who want to learn more about i5OS AIX integration

bull AIX Integration with I5OS on the IBM eServer iSeries Server (SG24-6551)

Jarek Miszczyk is the Senior Software Engineer IBM eServer Solutions Enablement IBM Rochester

[Portions of this white paper reprinted with permission from MC Mag Online published by MC Press LLP httpwwwmcpressonlinecom]

Acknowledgments The author would like to thank the following people for their advice contributions and support on this paper

Bob Bittner IBM Rochester Jon Rush IBM Rochester Prasad Vallurupalli IBM Rochester Neil Willis IBM Rochester

44

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix A Source Listing of TestJDBCjava

package comibmiseriespwdimport javasqlimport javaxnamingimport javautilHashtableimport javautilimport javaxsqlimport comibmas400access

public class TestJDBC public static void main(javalangString[] args)

throws Exception

int numOfLoops = 5000int outerNumOfLoops = 5boolean firstExec = trueConnection conStatement sPreparedStatement psPreparedStatement pstmtdelCallableStatement cstmPreparedStatement pstmtHashtable env = new Hashtable()

envput(ContextINITIAL_CONTEXT_FACTORYcomsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env)Systemoutprintln(Deploying connection pooling data source)deployDataSource() Do the work with connection pooling onlyAS400JDBCConnectionPoolDataSource tkcpds =

(AS400JDBCConnectionPoolDataSource)ctxlookup(jdbcToolkitDataSource) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPool pool = new AS400JDBCConnectionPool(tkcpds) Adds 1 connection to the pool that can be used by theapplication (creates the physical database connections based onthe data source)poolfill(1)Systemoutprintln(nStart timing Toolkit connection pooling)long startTime = SystemcurrentTimeMillis()

for (int i = 0 i lt outerNumOfLoops i++) con = poolgetConnection()consetAutoCommit(false) deleteif ( i == 0)

long startDelete = SystemcurrentTimeMillis()cstm = cstm = conprepareCall(

CALL qsysqcmdexc(CLRPFM FILE(DB2USERCOFFEES) + 000000002800000))

cstmexecuteUpdate()cstmclose()long endDelete = SystemcurrentTimeMillis()Systemoutprintln(Delete all records +

(endDelete - startDelete) + ms elapsed)

45

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

String sqlinstrlong startInsert = SystemcurrentTimeMillis() insert

pstmt =conprepareStatement(INSERT INTO COFFEES VALUES( ))for (int j = 0 j lt numOfLoops j++) pstmtsetString(1 Kona_ + IntegertoString(i))pstmtsetInt(2 150)pstmtsetFloat(3 999f)pstmtsetInt(4 0)pstmtsetInt(5 0)pstmtaddBatch()int [] updateCounts = pstmtexecuteBatch()concommit()pstmtclose()long endInsert = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for + numOfLoops + inserts

+ (endInsert - startInsert)) selectlong startSelect = SystemcurrentTimeMillis()ps = conprepareStatement(SELECT FROM COFFEES)ResultSet rs = psexecuteQuery()rsnext()rsclose()concommit()psclose()long endSelect = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for select +

(endSelect - startSelect))consetAutoCommit(true)conclose()long endTime = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for + outerNumOfLoops +

loops + (endTime - startTime))Systemexit(0)

private static void deployDataSource()throws ExceptionString serverName = teraplex String databaseName = TERAPLEX String userName = db2user String password = db2pwd

Establish a JNDI context and bind the connection pool data sourceHashtable env = new Hashtable()envput(ContextINITIAL_CONTEXT_FACTORY

comsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPoolDataSource tkcpds = new

AS400JDBCConnectionPoolDataSource()tkcpdssetServerName(serverName) tkcpdssetDatabaseName(databaseName) tkcpdssetUser(userName) tkcpdssetPassword(password) tkcpdssetDescription(Toolkit Connection Pooling DataSource)tkcpdssetSavePasswordWhenSerialized(true)tkcpdssetExtendedDynamic(true)

46

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

tkcpdssetPackage(JDBCDS)tkcpdssetPackageCache(true)tkcpdssetPackageCriteria(select)enable the following properties as requiredcpdssetTrace(true)tkcpdssetServerTraceCategories( AS400JDBCDataSourceSERVER_TRACE_DEBUG_SERVER_JOB)

ctxrebind(jdbcToolkitDataSource tkcpds)

47

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix B mdash Source Listing of cursorsjsqc

Source File Name = cursorsjsqc Licensed Materials - Property of IBM (C) COPYRIGHT International Business Machines Corp 1995 2000 2004 All Rights Reserved US Government Users Restricted Rights - Use duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp PURPOSE This sample program demonstrates the use of a CURSOR The CURSOR is processed using static SQL EXTERNAL DEPENDENCIES - Ensure existence of database for precompile purposes - Precompile with the SQL precompiler (PREP in DB2) - Bind to a database (BIND in DB2) - Compile and link with the IBM Cset++ compiler (AIX and OS2) or the Microsoft Visual C++ compiler (Windows) or the compiler supported on your platform For more information about these samples see the README file For more information on programming in C see the - Programming in C and C++ section of the Application Development Guide For more information on building C applications see the - Building C Applications section of the Application Building Guide For more information on the SQL language see the SQL Reference

include ltstdiohgt include ltstdlibhgt include ltstringhgtinclude ltsqlhgtinclude ltsqlenvhgtinclude ltsqldahgtinclude ltsqlcahgt

int SqlInfoPrint( char struct sqlca int char )void TransRollback( void)

define EMB_SQL_CHECK( MSG_STR ) rc = SqlInfoPrint( MSG_STR ampsqlca __LINE__ __FILE__) if ( rc = 0 ) TransRollback( )

return 1

EXEC SQL INCLUDE SQLCA

int main(int argc char argv[])

EXEC SQL BEGIN DECLARE SECTIONchar dname[15]

48

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

char pname[10]double compchar userid[9]char passwd[19]

EXEC SQL END DECLARE SECTION

int rc = 0printf( Sample C program CURSORSJ n )if (argc == 1)

EXEC SQL CONNECT TO TPLXEMB_SQL_CHECK(CONNECT TO TPLX)

else if (argc == 3)

strcpy (userid argv[1])strcpy (passwd argv[2])EXEC SQL CONNECT TO TPLX USER userid USING passwdEMB_SQL_CHECK(CONNECT TO TPLX)

else

printf (nUSAGE cursor [userid passwd]nn)return 1

endif

EXEC SQL DECLARE c1 CURSOR FORselect deptname name salary + ifnull(comm0) as compensationfrom org o staff swhere odeptnumb = sdeptorder by deptname compensation desc

EXEC SQL OPEN c1EMB_SQL_CHECK(OPEN CURSOR)

printf(DEPARTMENT NAME COMPENSn)printf(-----------------------------------n)do

EXEC SQL FETCH c1 INTO dname pname compif (SQLCODE = 0) breakprintf( -1515s -1010s 72fn dname pname comp )

while ( 1 )

EXEC SQL CLOSE c1EMB_SQL_CHECK(CLOSE CURSOR)

EXEC SQL CONNECT RESETEMB_SQL_CHECK(CONNECT RESET)

exit(0)

end of program CURSORSJSQC

int SqlInfoPrint( char appMsgstruct sqlca pSqlcaint linechar file )

int rc = 0char sqlInfo[1024]char sqlInfoToken[1024]char sqlstateMsg[1024]char errorMsg[1024]

if (pSqlca-gtsqlcode = 0 ampamp pSqlca-gtsqlcode = 100)

49

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

strcpy(sqlInfo )if( pSqlca-gtsqlcode lt 0) sprintf( sqlInfoToken n---- error report ----n)

strcat( sqlInfo sqlInfoToken)else sprintf( sqlInfoToken n---- warning report ----n)

strcat( sqlInfo sqlInfoToken) endif

sprintf( sqlInfoToken app message = sn appMsg)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken line = dn line)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken file = sn file)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken SQLCODE = ldn pSqlca-gtsqlcode)strcat( sqlInfo sqlInfoToken)

get error message rc = sqlaintp( errorMsg 1024 80 pSqlca) return code is the length of the errorMsg string if( rc gt 0) sprintf( sqlInfoToken sn errorMsg)

strcat( sqlInfo sqlInfoToken)

get SQLSTATE message rc = sqlogstt( sqlstateMsg 1024 80 pSqlca-gtsqlstate)if (rc == 0) sprintf( sqlInfoToken sn sqlstateMsg)

strcat( sqlInfo sqlInfoToken)

if( pSqlca-gtsqlcode lt 0) sprintf( sqlInfoToken --- end error report ---n)

strcat( sqlInfo sqlInfoToken)printf(s sqlInfo)return 1

else sprintf( sqlInfoToken --- end warning report ---n)

strcat( sqlInfo sqlInfoToken)printf(s sqlInfo)return 0

endif endif

return 0

void TransRollback( ) struct sqlca sqlca

int rc = 0 rollback the transaction printf( nRolling back the transaction n)

EXEC SQL ROLLBACKrc = SqlInfoPrint( ROLLBACK ampsqlca __LINE__ __FILE__)if( rc == 0) printf( The transaction was rolled backn)

50

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

51

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix C mdash Source Listing of testclicpp

Include The Appropriate Header Filesinclude ltsqlclihgtinclude ltsqlcli1hgtinclude ltsqlutilhgtinclude ltsqlenvhgtinclude ltstdiohgt include ltiostreamgt include ltlocalehgt include ltstringhgtdefine SQL_SQLSTATE_SIZE 5define LOOPS 8

using namespace std

Define The CLI_Class Classclass CLI_Class

Attributespublic

SQLHANDLE EnvHandleSQLHANDLE ConHandleSQLHANDLE StmtHandleSQLRETURN rcSQLCHAR Job[6]SQLCHAR Name[10]SQLDOUBLE Comp

Operationspublic

CLI_Class()~CLI_Class()SQLRETURN ShowResults()

Constructor Destructor

SQLRETURN printError( SQLHDBC SQLHSTMT)

Define The Class ConstructorCLI_ClassCLI_Class()

setlocale( LC_ALL )

Initialize The Return Code Variablerc = SQL_SUCCESS

Allocate An Environment Handlerc = SQLAllocHandle(SQL_HANDLE_ENV SQL_NULL_HANDLE ampEnvHandle)

Allocate A Connection Handleif (rc == SQL_SUCCESS)

rc = SQLAllocHandle(SQL_HANDLE_DBC EnvHandle ampConHandle)

Define The Class DestructorCLI_Class~CLI_Class()

Free The Connection Handleif (ConHandle = NULL)

SQLFreeHandle(SQL_HANDLE_DBC ConHandle)

Free The Environment Handle

52

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

if (EnvHandle = NULL)SQLFreeHandle(SQL_HANDLE_ENV EnvHandle)

Define The ShowResults() Member FunctionSQLRETURN CLI_ClassShowResults(void)

While There Are Records In The Result Data Set Generated Retrieve And Display Themcout ltlt Name Job Compensation ltlt endlcout ltlt --------- ------ ------------ ltlt endlcoutsetf(iosleft)coutprecision(2)coutsetf(iosfixed)while (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)

rc = SQLFetch(StmtHandle)if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)

coutwidth(15)cout ltlt Name

coutwidth(10)cout ltlt Job

coutwidth(7)cout ltlt Comp ltltendl

if(rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO ampamp rc = SQL_NO_DATA)printError(ConHandle StmtHandle)

else

rc = 0SQLCloseCursor(StmtHandle)

Return The ODBC API Return Code To The Calling Functionreturn(rc)

SQLRETURN CLI_ClassprintError (SQLHDBC hdbc

SQLHSTMT hstmt)

SQLCHAR buffer[SQL_MAX_MESSAGE_LENGTH + 1]SQLCHAR sqlstate[SQL_SQLSTATE_SIZE + 1]SQLINTEGER sqlcodeSQLSMALLINT lengthSQLRETURN rcwhile ((rc = SQLError(SQL_NULL_HENV hdbc hstmt

sqlstateampsqlcodebufferSQL_MAX_MESSAGE_LENGTH + 1amplength)) == SQL_SUCCESS || rc ==

SQL_SUCCESS_WITH_INFO)

cout ltlt SQLSTATE ltlt sqlstate ltlt endlcout ltlt SQLCODE ltlt sqlcode ltlt endlcout ltlt Error msg ltlt buffer ltlt endl

53

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

cout ltlt----------------------------- ltlt endl ltlt endl

return(SQL_ERROR)

----------------------------------------------------------------- The Main Function -----------------------------------------------------------------int main()

Declare The Local Memory Variables

(SQLCHAR ) db2user SQL_NTS (SQLCHAR ) test26t SQL_NTS)

SQLRETURNSQLCHARSQLCHARSQLCHARchar

SQLCHAR

rc = SQL_SUCCESSDBName[10] = TPLXSQLStmt[255]c[10]ptrcurrentDepartment[8][15] = Head Office

New England Mid Atlantic South Atlantic Great Lakes PlainsPacificMountain

Create An Instance Of The CLI_Class ClassCLI_Class Example

Connect To iSeries Database if (ExampleConHandle = NULL)

rc = SQLConnect(ExampleConHandle DBName SQL_NTS

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)ExampleprintError(ExampleConHandle SQL_NULL_HSTMT)

return(rc)

cout ltlt Successfully connected to ltlt DBName ltlt ltlt endlrc = SQLSetConnectAttr(ExampleConHandle SQL_ATTR_AUTOCOMMIT

(SQLPOINTER) SQL_AUTOCOMMIT_OFF SQL_IS_UINTEGER) Allocate An SQL Statement Handlerc = SQLAllocHandle(SQL_HANDLE_STMT ExampleConHandle

ampExampleStmtHandle)if (rc == SQL_SUCCESS)

Define A SELECT SQL Statement

strcpy((char ) SQLStmt select name job salary + ifnull(comm0) ascompensation )

ptr = strcat( (char ) SQLStmt from org o staff s )ptr = strcat( (char ) SQLStmt where odeptnumb = sdept)ptr = strcat( (char ) SQLStmt and deptname = )ptr = strcat( (char ) SQLStmt order by compensation desc)

Prepare The SQL Statementrc = SQLPrepare(ExampleStmtHandle SQLStmt SQL_NTS)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)ExampleprintError(ExampleConHandle ExampleStmtHandle)

54

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

return(rc)

Bind The Columns In The Result Data Set Returned To Application Variables

rc = SQLBindCol(ExampleStmtHandle 1 SQL_C_CHAR (SQLPOINTER)ExampleName sizeof(ExampleName) NULL)

rc = SQLBindCol(ExampleStmtHandle 2 SQL_C_CHAR (SQLPOINTER)ExampleJob sizeof(ExampleJob) NULL)

rc = SQLBindCol(ExampleStmtHandle 3 SQL_C_DOUBLE (SQLPOINTER)ampExampleComp sizeof(ExampleComp) NULL)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO) ExampleprintError(ExampleConHandle ExampleStmtHandle)

return(rc)

while (true)

for (int i = 0 i lt LOOPS i++)

rc=SQLBindParameter(ExampleStmtHandle1SQL_PARAM_INPUTSQL_C_CHARSQL_CHAR

150(SQLPOINTER) currentDepartment[i8]0NULL)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)

ExampleprintError(ExampleConHandle ExampleStmtHandle)return(rc)

rc = SQLExecute(ExampleStmtHandle)if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)

ExampleprintError(ExampleConHandle ExampleStmtHandle)return(rc)

cout ltlt endl ltlt Current Dept ltlt currentDepartment[i8] ltlt

endl Display The Results Of The SQL QueryExampleShowResults()if(rc = 0)break

if ( i500 == 0 ampamp i gt 0 )cout ltlt Loops ltlt i ltlt ltlt endl

cout ltlt AFTER ltlt LOOPS ltlt loops Press X to exit ltlt endlcin gtgt cif (c[0] == x || c[0] == X)

break

Free The SQL Statement Handleif (ExampleStmtHandle = NULL )

SQLFreeHandle(SQL_HANDLE_STMT ExampleStmtHandle) Disconnect From The Northwind Sample Databaserc = SQLDisconnect(ExampleConHandle)

Return To The Operating Systemreturn(rc)

55

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 8 Defining a resource reference for an EJB

Save the modified definition and then change the EJB source code to use the reference rather than directly DataSource

TroubleshootingTroubleshooting a multi-tier application may be a bit tricky because the developer needs to deal with software components that reside in separate partitions Three tools are particularly useful for pinning down the potential problem areas bull Joblog messages for a database server job mdash Provides enough details to isolate DB2 UDB for

iSeries runtime issues bull JDBC trace utility mdash Provides granular information about the data flow between the AIX

application and the iSeries server job bull Database Monitor ndash Provides detailed SQL runtime trace

Job Log MessagesAs mentioned a DB2 client communicates with a corresponding iSeries server job This server job runs the SQL requests on behalf of the client The iSeries database server jobs are called QZDASOINIT and they run in the QUSRWRK subsystem At any given time a large number of database server jobs may be active on the server so the first step is to identify the job that serves the particular client connection The easiest method to accomplish this task is to run the following CL command from the i5OS prompt

WRKOBJLCK OBJ(DB2USER) OBJTYPE(USRPRF)

Here DB2USER is the user profile that is used to connect to the iSeries server Note that a QZDASONIT job is assigned to a client after the connection has been established so the developer needs to set a breakpoint in the client application after the database connection has been established

Once the Work with Object Locks appears key in 5 (Work with Job) next to the only QZDASOINIT job that should be listed This shows the Work with Job dialog Select option 10 to

16

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

display the job log for the database server job Now the job log can be searched for any error messages generated by the DB2 runtime

Sometimes it is also useful to include debug messages in the job log The debug messages are informational messages written to the job log about the implementation of a query They describe query implementation methods such as the use of indexes join order ODP implementation (reusable versus non-reusable) and so on The easiest way to instruct an iSeries server to include the debug messages is to set the ServerTraceCategories property on the data source object

tkcpdssetServerTraceCategories(AS400JDBCDataSourceSERVER_TRACE_DEBUG_SERVER_JOB)

A sample of the job log messages with debug messages enabled is shown below

SET TRANSACTION completeSTATEMENT NAME FOUND QZ868F0A458E13AF8C Starting optimizer debug message for query Arrival sequence access was used for file COFFEESODP created ODP not deleted 5000 rows inserted in COFFEES in DB2USER STATEMENT NAME FOUND QZ868F0A4C144BF12EBlocking used for queryCursor CRSR0001 opened606 rows fetched from cursor CRSR0001 ODP not deleted Cursor CRSR0001 closed

So the job log offers fairly detailed information on how the AIX client requests were implemented by the DB2 runtime

JDBC Trace UtilityThe JTOpen driver provides a tracing utility which can be used to collect detailed client-side traces The JDBC tracing is turned off by default It can be enabled by setting the Trace property to true Heres an example of how to switch on tracing using the setTrace method on the data source object

tkcpdssetTrace(true)

The trace can also be enabled when using the DriverManagergetConnection() method for obtaining a connection to DB2 UDB for iSeries In this case the developer could add the trace property to the connection string This approach is illustrated in the following code snippet

ClassforName(comibmas400accessAS400JDBCDriver) [1] hellip con = DriverManagergetConnection(jdbcas400teraplextrace=true

db2userdb2pwd) [2]

At [1] an instance of the JTOpen JDBC Driver is initiated Then at [2] the driver is used to obtain a connection to the iSeries server Note how the trace property has been added to the database URL See the IBM Toolbox for Java JDBC properties documentation on the iSeries Information Center Web site for a complete list of properties supported by the JTOpen driver

Although the level of details provided by the trace utility is sufficient in most troubleshooting scenarios sometimes the developer may need to collect low-level traces scoped to a certain type

17

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

of information In V5R3 the IBM Toolbox for Java (as well as the latest JTOpen) added a comprehensive detailed trace facility The following is the complete list of detailed trace parameters and their purpose

bull None or ldquordquo ndash This setting disables the detailed trace bull datastream - This category is used by Toolbox classes to log dataflow between the local host

and the remote system It is not intended for use by application classes bull diagnostic - This category is used to log object state information bull error - This category is used to log errors that cause an exception bull information - This category is used to track the flow of control through the code bull warning - This category is used to log errors that are recoverable bull conversion - This category is used by Toolbox classes to log character set conversions

between Unicode and native code pages bull proxy - This category is used by Toolbox classes to log data flow between the client and the

proxy server bull pcml - This category is used to determine how PCML interprets the data that is sent to and

from the server bull jdbc - This category is used to track JDBC calls throughout the program bull thread - This category is used to enable tracing of thread information This is useful when

debugging multi-threaded applications bull all - This category will enable all previous categories

The detailed trace can be enabled when using the DriverManagergetConnection() method for obtaining a connection to DB2 UDB for iSeries In this case the developer could add the toolbox trace property to the connection string This is illustrated in the following code sample

String dbUrl = jdbcas400pwd1toolbox trace=diagnostic con = DriverManagergetConnection(dbUrl dbUser dbPassword)

Note that currently the driverrsquos DataSource interfaces do not allow the developer to directly activate the detailed tracing However they could set the server from the command line at the time the java program is launched The example below shows how the detailed trace properties could be enabled at the command line

java -Dcomibmas400accessTracecategory=diagnostic TestJDBC

The -D switch indicates to the java interpreter that the information following it will be a system property

In case of a WebSphere application the trace property can be set through the admin console In the console select Application Servers-gt server1-gt Process Definition -gt Java Virtual Machine Figure 9 shows how to set the Generic JVM Arguments for an application server instance

18

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 9 Setting JVM arguments to enable detailed Toolbox tracing

Database Monitor

The database monitor is the ultimate tool available on DB2 UDB for iSeries to collect low-level SQL traces It is mainly used to pin down the SQL performance problems Refer to the lsquoUsing iSeries Database Monitor to Identify and Tune SQL Queriesrsquo white paper for a detailed discussion on how to collect and analyze the database monitor traces httpibmcomserversenablesiteeducationiborecordhtmldtmon

IBM DB2 JDBC Universal Driver DB2 JDBC Universal Driver is one of the new features delivered with DB2 UDB Version 8 DB2 JDBC Universal Driver has been designed to eliminate the dependency on DB2 CLI runtime modules as well as to enable direct Type 4 connectivity to DB2 UDB for iSeries and DB2 UDB for zOSreg

The pure-Java (Type 4) remote connectivity is based on the DRDA open distributed protocol for cross-platform access to DB2 DRDA defines the rules the protocols and the semantics for accessing distributed data Applications can access data in a distributed relational environment by using SQL statements The iSeries DRDA application server implementation is based on multiple connection-oriented server jobs running in the QSYSWRK subsystem A DRDA listener job (QRWTLSTN) listens for TCP connect requests on port 446 Once an application requester connects to the listener job the listener wakes up one of the QRWTSRVR prestart jobs and assigns it to a given client connection Any further communication occurs directly between the client application and the QRWTSRVR job These concepts are illustrated in Figure 10

19

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 10 Accessing DB2 UDB for iSeries with DB2 Universal Driver

The DB2 Universal Driver can be loaded in an AIX partition by installing one of the DB2 Connect for AIX products (see the Additional Information section for details) It is also a part of a DB2 Enterprise Server Edition for AIX install Specifically the developer needs three JAR files in a AIX partition to successfully connect to an iSeries server db2jccjar db2jcc_license_cisuzjar and db2jcc_license_cujar The iSeries license is contained in db2jcc_license_cisuzjar Note that this file is not a part of DB2 Client In other words a DB2 Connect license is required to use the driver in production environments The location of the JAR files needs to be added to the CLASSPATH environment variable For instance the following entry could be added to the AIX profile script

CLASSPATH=homedb2inst2sqllibjavadb2jccjarCLASSPATH=$CLASSPATHhomedb2inst2sqllibjavadb2jcc_license_cujarCLASSPATH=$CLASSPATHhomedb2inst2sqllibjavadb2jcc_license_cisuzjarexport CLASSPATH

Java Runtime 131 is a prerequisite

Additionally the developer should install the latest database group PTF (SF99503 for i5OS V5R3) on the iSeries server The Informational APAR ii13348 is keeping track of any fixes relevant to DRDA above and beyond the current database group PTF

Obtaining a Connection to DB2 UDB for iSeries When Type 4 connectivity is used the DB2 Universal Driver connects directly to the DB2 on iSeries through TCPIP Note that this is different from the legacy DB2 Type 2 JDBC driver that requires a DB2 node and remote database configurations on the client accessing iSeries The following code snippet illustrates how to use the DB2 JDBC Universal Driver to obtain a connection to DB2 UDB for iSeries

20

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

try ClassforName(comibmdb2jccDB2Driver) [1] catch(javalangClassNotFoundException e) Systemerrprint(ClassNotFoundException )Systemerrprintln(egetMessage())

try DriverManagergetConnection(jdbcdb2teraplex446TERAPLEX[2]

db2userdb2pwd) hellip catch(SQLException ex) Systemerrprintln(

SQLException + exgetMessage())

At [1] an instance of the DB2 JDBC Universal Driver is instantiated Then at [2] the driver is used to obtain a connection to the iSeries server Note the proper form of the database URL required by the driver

Considerations There are several advantages of DB2 JDBC Universal Driver bull Ease of cross-platform development mdash Consistent coding techniques and consistent error

codes and messages bull Ease of deployment mdash Pure Java (no runtime client required) and a single driver for accessing

DB2 on different platforms

The ease of use comes at a price though The iSeries JTOpen driver is optimized for accessing DB2 UDB for iSeries data and it uses native iSeries protocol to communicate with the back-end database server job This usually results in better performance and more-efficient system resources utilization For instance when using the DB2 JDBC Universal Driver to access an iSeries server the executeBatch method results in a single record insert There are also some restrictions when using DB2 Universal JDBC Driver with Type 4 connectivity

bull Support for distributed transactions (JTA) is not enabled bull Driver built-in connection pooling is not supported

Refer to Java application support in DB2 for more details on DB2 JDBC Universal Driver

21

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 Connect data access This section will explore the most important aspects of DB2 Connect ndash iSeries integration - including configuration tips and coding examples

DB2 Connect provides functionality for accessing data stored in DB2 UDB for iSeries as well as DB2 UDB for zOS and DB2 UDB for OS390reg DB2 Connect offers capabilities to access DB2 family members via several SQL interfaces gateway functions such as connection pooling and federated database functionality Many applications supporting the DB2 family of products leverage DB2 Connect as a key middleware component DB2 Connect is offered as separate AIX license products

Enterprise Edition Application Server Edition

In addition to DB2 Connect there are several other DB2 UDB Version 81 products that are supported on AIX

DB2 Universal Database Enterprise Server Edition DB2 Universal Database Workgroup Server Unlimited Edition DB2 Universal Database Workgroup Server Edition DB2 Universal Database Universal Developers Edition All Clients

The DB2 Connect Enterprise Edition functionality is also contained in DB2 Enterprise Server Edition for AIX

22

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 Connect in a nutshell In the scenario described in this paper the DB2 Connect functions contained in DB2 Enterprise Edition for AIX are utilized DB2 Connect Enterprise Edition provides support for both local and remote DB2 clients This is illustrated in Figure 11 Accessing DB2 UDB for iSeries with DB2 Connect

Figure 11 Accessing DB2 UDB for iSeries with DB2 Connect

DB2 Connect implements the Distributed Relational Database Architecturetrade (DRDAreg) to reduce the cost and complexity of accessing data stored in DB2 UDB for iSeries and other DRDA-compliant database servers DRDA defines the rules the protocols and the semantics for accessing distributed data Applications can access data in a distributed relational environment by using SQL statements In a distributed environment the system running the application and sending the SQL requests across the network is called the application requester (AR) A remote database server that executes SQL requests submitted by an application requester is known as the application server (AS) In the example shown in Figure 11 (above) DB2 Connect plays the role of an application requester while DB2 UDB for iSeries is an application server In this case DB2 Connect communicates with the iSeries database through TCPIP The iSeries DRDA application server implementation is based on multiple connection-oriented server jobs running in the QSYSWRK subsystem A DRDA listener job (QRWTLSTN) listens for TCP connect requests on port 446 Once an application requester connects to the listener job the listener wakes up one of the QRWTSRVR prestart jobs and assigns it to a given client connection Any further communication occurs directly between the client application and the QRWTSRVR job

DB2 Connect supports a wide range of programming interfaces that can be used by AIX applications to access the iSeries database Embedded SQL frac34 Both static and dynamic SQL frac34 Various programming languages (Java CC++ Cobol Fortran REXX)

DB2 Call Level Interface (DB2 CLI) ODBC JDBC frac34 DB2 JDBC Type 2 Driver frac34 DB2 JDBC Type 4 Driver (Universal JDBC Driver)

23

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Note that DB2 Connect supports access to DB2 UDB for iSeries through DB2 JDBC Universal driver However for performance and ease of maintenance reasons IBM recommends that Java applications running in AIX use native iSeries Toolbox JDBC driver See the JDBC Data Access section of this paper (above) for more details On the other hand DB2 Connect is a very efficient and robust connectivity option for AIX applications especially in the environments that are not directly supported by the native iSeries JDBC driver Here are several possible scenarios that would require DB2 Connect installed in a AIX partition

Embedded SQL interface is used to access DB2 CLI or ODBC interface is used to access DB2 A single SQL interface is needed to access multiple back end DB2 server Specific DB2 Connect functionality is needed such as distributed join or connection

pooling

Prerequisites One of the DB2 Connect products or DB2 Enterprise Server Edition for AIX V81 is needed Additionally DB2 Application Development Client is required in the AIX partition to compile DB2 applications

For maximum database server stability the developer should install the latest database group PTF (SF99503 for i5OS V5R3) on the iSeries server The Informational APAR ii13348 is keeping track of any fixes relevant to DRDA above and beyond the current database group PTF

DB2 Connect configuration The following example employs i5OS V5R3 and DB2 UDB Enterprise Server Edition for AIX Version 81 FixPak 6

Configuration steps in the iSeries partition The following process lists the necessary steps to be performed on the iSeries server 1) Verify that the TCPIP stack is working correctly It is assumed that the Virtual LAN is used to

communicate with the i5OS partition First obtain the IP address of the iSeries server or its hostname and ping the iSeries server from the AIX partition

2) Create a relational database (RDB) entry for the iSeries database in the i5OS partition If this has already been created it can be displayed by using the DSPRDBDIRE command Make sure that the RDB entry with a location of LOCAL exists on the iSeries server If it does not exist use the ADDRDBDIRE command to add the appropriate RDB entry For example the following command would add an RDB entry named TPLX For simplicity it is recommended that the TCPIP host name and RDB entry remain the same

ADDRDBDIRE RDB(TPLX) RMTLOCNAME(LOCAL)

3) Create a collection called NULLID This is necessary because the utilities shipped with DB2 Connect and DB2 UDB for AIX store their packages in the NULLID collection Since it does not exist by default in the iSeries server you must create it using the following command

CRTLIB LIB(NULLID)

4) Products that support DRDA automatically perform any necessary code page conversions at the receiving system For this to happen both systems need a translation table from their code page to the partner code page The default Coded Character Set Identifier (CCSID) on the iSeries server is 65535 Since DB2 Connect does not have a translation table for this code page the developer needs to change the individual user profiles to contain a CCSID that can be converted properly by DB2 Connect For US English this is 037 For other languages see DB2 Connect Personal Edition Quick Beginning GC09-2967 The following command changes the CCSID for an individual user profile to 037

24

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

CHGUSRPRF userid CCSID(037)

5) Verify that the default port 446 for DRDA service is being used To do this go to the Configure TCPIP menu (CFGTCP) select Configure Related Tables and then select Work with service table entries Verify that the DRDA service is set for port 446

6) The Distributed Data Management (DDM) job must be started for DRDA to work If you want the DDM job to be automatically started whenever TCPIP is started change the attributes of the DDM job using the CHGDDMTCPA command and set the Autostart server parameter to YES

7) If the system administrator chooses not to autostart the server issue the following command to start the DDM server job

STRTCPSVR SERVER(DDM)

8) Make sure that the user profiles that will be used to connect to the iSeries server exist on the server

25

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Configuration steps in the AIX partition The following steps are required for DB2 Connect to be configured in the AIX partition 1) Sign on to the AIX partition as the DB2 administrator 2) Launch Client Configuration Assistant (db2ca from the command prompt) It is assumed that

VNC or an X-Windows server are being used on the workstation so that the db2ca GUI can be properly rendered

3) From the Selected pull-down menu select the Add Database using Wizard option The Select how you want to setup a connection dialog appears Select Manually configure a connection to a database and click Next This is shown in Figure 12

Figure 12 Accessing DB2 UDB for iSeries with DB2 Connect

26

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

4) On the Select a communications protocol choose TCPIP and select The database physical resides on a host or OS400 system Then select the option Connect directly to the server as shown in Figure 13 Click Next

Figure 13 mdash Selecting communications protocol

27

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

5) On the TCPIP tab fill in the host name of the iSeries server The port number should be 446 This is shown in Figure 14 Click Next

Figure 14 mdash Specifying TCPIP communication parameters

28

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

6) On the Database tab fill in the Relational Database name Use the RDB entry name (specified in step 2) in the Configuration steps in the iSeries partition section as shown in Figure 15 Click Next

Figure 15 mdash Specifying the remote database

7) If you plan to use the ODBC applications select Register this database for ODBC as a system data source on the ODBC tab Click Next

29

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

8) On the Specify the node option dialog select OS400 from the Operating System pull-down menu This is shown in Figure 16 Click Finish

Figure 16 mdash Specifying the node options

30

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

9) The Test Connection dialog appears This allows the developer to verify that the connection works Select both CLI and JDBC check boxes You are also prompted for an iSeries user ID and password as shown in Figure 17

Figure 17 mdash Testing the connection

31

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

10) The successful connection to the database server is confirmed by the message box shown in Figure 18

Figure 18 mdash Test Connection results 11) At this time a newly configured database connection should appear in the main DB2

Configuration Assistant window It is recommended that the DB2 utilities are also bound to the iSeries database The bind process creates the necessary SQL packages on the remote database In the main Configuration Assistant window click the TPLX database entry and then select Selected-gtBindhellip

32

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

12) The Bind dialog appears Click Select All and then enter the connection information as shown in Figure 19 Click Bind The Results message box appears This allows the developer to monitor the progress of the binding process Watch for any error and warning messages

Figure 19 mdash Binding the DB2 utilities This concludes the DB2 Connect configuration steps

33

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Accessing DB2 UDB for iSeries from C embedded SQL

As mentioned earlier DB2 Connect allows developers to compile and run embedded SQL applications that access DB2 UDB for iSeries data This section covers implementation details for a C embedded SQL application called cursorsjsqc (see Appendix B for source code)

Prerequisites An embedded SQL application running in an AIX partition will use DB2 Connect services to access DB2 UDB for iSeries therefore the developer needs to make sure that all components listed in section Prerequisites on page 24 are installed The developer also needs to create a remote database connection as described in the DB2 Connect configuration section of this paper on page 24

Static SQL and SQL packages To successfully run against a DB2 UDB for iSeries database an embedded SQL application needs to be first precompiled and bound to the back-end database This process creates an SQL package on the target iSeries server The SQL package contains the access plan information for the SQL statements executed by the application The internal structure of the package as well as the method how its content is used by the SQL runtime to facilitate the access plan reuse is similar to the Extended Dynamic SQL support covered in detail in the Extended Dynamic SQL and Statement Caching section of this paper (on page 9) There are however important differences between the packages created by the extended dynamic SQL support and the packages created for embedded SQL DRDA client applications The extended dynamic SQL packages support dynamic SQL interfaces such as JDBC

that can submit ad hoc SQL statements at the run time The SQL runtime can prepare the dynamic statements and add them to the package On the other hand the DRDA packages are created at the precompile time and contain static SQL In order to add new statements to the package the application needs to be precompiled and rebound again

The extended dynamic SQL package can dynamically grow up to 500MB by allocating new space as required The DRDA packages since they are created at the precompile time have a fix size and do not grow over their life time

Simple embedded SQL application The application is based on a source code provided in the DB2 UDB samples directory typically to be found at homedb2inst1sqllibsamples The cursorsjsqc performs a join between STAFF and ORG tables located in DB2USER schema (library) on the TPLX database server (the source is provided at the end of this paper in Appendix B) The join statement retrieves the DEPTNAME column from ORG NAME column from STAFF and calculates the total compensation for an employee by adding SALARY and COMM columns in STAFF The results are sorted by department name and total compensation Here is the SELECT statement used by the application

SELECT deptname name salary + IFNULL(comm0) as compensationFROM org o staff sWHERE odeptnumb = sdeptORDER BY deptname compensation DESC

The application iterates through the selected records and prints out the data to the standard output device The sample DB2USER schema was created with the following SQL statements

db2 CONNECT TO tplx USER db2user USING mypassworddb2 CALL QSYSCREATE_SQL_SAMPLE(DB2USER)

34

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Make sure that the AIX partition is logged into with the DB2 admin user profile If the defaults were selected at the DB2 installation time this profile name is db2inst1 It is also assumed that DB2USER user exists on the iSeries server and that it has appropriate authority

There are several steps that are required to create an executable for the cursorsjsqc source code First the DB2 PRECOMPILE utility needs to be called The utility creates a bind file that is used to bind the required SQL package to the TPLX database It also converts embedded SQL statements into DB2 run-time API calls and produces a pure C source file that can be processed by an AIX C compiler

db2 CONNECT TO tplx USER db2user USING mypassworddb2 prep cursorsjsqc bindfile

Note that the connect statement is required only if the developer is not already connected to the database on an iSeries server Watch for any error or warning messages returned by the DB2 prep utility The prepare step should produce cursorsjbnd and cursorsjc files in the current directory Now the developer can invoke the bind utility to prepare the statements contained in the bind file and create the package on the target iSeries database server

db2 bind cursorsjbnd

It is assumed that Visual C++ 60 is installed and configured in the AIX partition Refer to the ldquoDeveloping and Porting C and C++ Applications on AIXrdquo redbook for more information on how to use the Visual C++ compiler httpibmcomredbooksabstractssg245674htmlOpen

Use the following commands to compile the C source generated by the precompile utility

xlc -I$INSTHOMEsqllibinclude ndashc cursorsjcxlc ndasho cursorsj cursorsjo -L$INSTHOMEsqlliblib ndashldb2

Run the program from the AIX prompt

cursorsj db2user mypassword

Distributed Join DB2 UDB Version 8 provides core federated server functionality A federated system consists of a DB2 UDB instance that operates as a federated server a database that acts as the federated database one or more data sources and clients (users and applications) that access the database and data sources Federated server permits objects stored in multiple databases to be accessed together in the same query For example a query can refer to a table that resides in DB2 UDB for iSeries and join it to a table stored in DB2 UDB for AIX Such a query would constitute so called distributed join The support for DB2 UDB for iSeries as a federated data source is provided by core federated server functionality directly implemented in DB2 UDB Enterprise Server Edition and DB2 UDB Connect Enterprise Edition All other DB2 UDB family members are also supported directly by core DB2 UDB federated server An additional software product DB2 Information Integratortrade is required to access non-DB2 UDB databases such as Oracle Sybase or Microsoftreg SQL Server Consult the following white papers for a detailed discussion on DB2 federated server support Heterogeneous data access for iSeries applications Version 2 httpibmcomserversenablesiteeducationiborecordhtmlhetdata Fundamentals of IBM DB2 Federated Server and Relational Connect httpwww7bsoftwareibmcomdmddlibrarytecharticle0206purnell0206purnellhtml

35

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Distributed Join Example In this section the steps that are required to configure DB2 UDB for iSeries as a federated data source will be illustrated Then the cursorsjsqc program will be ldquotweakedrdquo so that it executes a distributed join query that accesses data stored on an iSeries server and in the local DB2 UDB for AIX database It is assumed that the developer is familiar with the DB2 federated server concepts

Note Run the following commands from the Command Line Processor prompt Load the utility by executing the db2 command at the AIX prompt 1) First the local DB2 UDB for AIX instance needs to be enabled as a DB2 federated server

This is done by setting the database manager configuration parameter FEDERATED to YES

db2=gt update dbm cfg using FEDERATED YES

The database instance needs to be restarted for the change to take effect

NOTE A federated database is a regular database in a DB2 UDB instance that has the FEDERATED parameter enabled Therefore in this example the SAMPLE database that was created earlier is used as the federated database A new database can also be created using the CREATE DATABASE command

2) Connect to the federated database

db2=gt connect to sample

3) Use the CREATE WRAPPER statement to register a wrapper for the iSeries data source Wrappers are library routines that are used by the federated server to perform operations such as connecting to a data source and retrieving data from it The default wrapper name for DB2 UDB for iSeries is DRDA Here is the command to register the DRDA wrapper

db2=gt create wrapper drda

4) Use the CREATE SERVER statement to register a data source as a server within the federated database The server definition specifies the type and version of the data source and the wrapper used for communications with this data source For the DB2 UDB for iSeries data source the node and the database names are also needed The node and database name parameters have been configured for our TPLX database in the Configuration steps in the AIX partition section (on page 24) Use the following DB2 UDB command to lookup these parameter on the federated server

db2=gt list database directory

In this case the command produced the following output

Database alias = TPLX Database name = DCSE99E1 Node name = NDE9BF76 Database release level = a00 Comment = Directory entry type = Remote Authentication = SERVER Catalog database partition number = -1

36

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Note that the node name is set to NDE9BF76 The name was generated by the Configuration Administrator utility (db2ca)

Here is the command to register the TPLX database as a federated server

db2=gt create server tplx type db2400 version 530 wrapperdrda authorization db2user password mypassword options(nodeNDE9BF76 dbname TPLX)

The command is quite complex so make sure that the syntax is correct

5) Define the user mappings that instructs the federated server what user ID and password should be used when connecting to the iSeries data source

db2=gt create user mapping for user server tplxoptions(remote_authid db2user remote_password mypassword)

Specify the nickname for the iSeries table or view A nickname is an identifier that is used by the federated server to reference an object located at the data source The following command creates a nickname for the STAFF table located in the DB2USER schema on the TPLX database

db2=gt create nickname tplx_staff for tplxdb2userstaff

6) Test the distributed join query

db2=gt SELECT deptname name salary + COALESCE(comm0) ascompensation FROM org o tplx_staff s WHERE odeptnumb =sdept ORDER BY deptname compensation DESC

Note that the native iSeries function IFNULL has been substituted with an equivalent DB2 UDB function COALESCE COALESCE is also supported on iSeries servers For better portability IBM encourages the use of COALESCE rather than IFNULL Note also that the query runs on the federated server rather than on TPLX It accesses the ORG table in the local DB2 UDB for AIX SAMPLE database and the STAFF table that resides in TPLX The federated server performs the necessary distributed join

7) Modify the cursorsjsqc so that it executes a distributed join There are two source code modifications - Change the CONNECT TO statements Now the application needs to connect to the

federated database SAMPLE rather than to TPLX

EXEC SQL CONNECT TO SAMPLEEXEC SQL CONNECT TO SAMPLE USER userid USING passwd

- Modify the select statement so that it performs a distributed join Use the statement (shown in step 6) above Save the new source version as cursordjsqc

- Prepare bind and compile the distributed join version of the program as described in the Simple C embedded SQL application section (on page 34)

db2 prep cursordjsqc bindfiledb2 bind cursordjbndxlc -I$INSTHOMEsqllibinclude ndashc cursordjcxlc ndasho cursordj cursordjo -L$INSTHOMEsqlliblib ndashldb2

37

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

- Run the program from the AIX prompt

cursordj

Connection Pooling and Connection ConcentratorA modern Web-based application typically executes a large number of short-lived transactions Executing a transaction in this environment means establishing a database connection executing a few SQL statements and terminating this connection Creating connections to the database server is a very costly process To reduce the unnecessary workload DB2 Connect implements connection pooling and connection concentrator Connection pooling mechanism allows DB2 Connect to reuse an existing connection infrastructure for subsequent connection requests The connection concentrator is an advanced technology that allows DB2 Connect to serve a potentially very large number of clients with a limited number of database connections This is accomplished by decoupling clients from a particular database connection

Note that currently neither connection pooling nor connection concentrator support DB2 UDB for iSeries Therefore for performance reasons the author strongly recommends that the application server that obtains and drops connections very frequently implements its own database connection pooling mechanism that would assign an existing pooled database connection to a new AIX process or thread

TroubleshootingTroubleshooting a multi-tier application may be a bit tricky because the developer needs to deal with software components that reside in separate partitions The authorrsquos experience shows that two tools are particularly useful for pinning down the potential problem areas The joblog messages for a database server job usually provide enough details to isolate DB2

UDB for iSeries runtime issues The DRDA trace utility provides granular information about the data flow between the AIX

application and the iSeries server job

38

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Job Log MessagesAs mentioned earlier a DB2 client communicates with a corresponding iSeries server job This server job runs the SQL requests on behalf of the client More precisely when a DB2 client submits an SQL statement the statement is passed to a server job that in turn calls the DB2 runtime to execute the statement The results are then reformatted and marshaled to the client The iSeries DRDA server jobs are called QRWTSRVR and they run in the QUSRWRK subsystem At any given time there may be a large number of DRDA server jobs active on the system so the first step is to identify the job that serves the particular client connection The easiest method to accomplish this task is to run the following CL command from the i5OS prompt

WRKOBJLCK OBJ(DB2USER) OBJTYPE(USRPRF)

Here DB2USER is the user profile that is used to connect to the iSeries server Note that a QRWTSRVR job is assigned to a client after the connection has been established so the developer needs to set a breakpoint in the client application below the CONNECT TO statement

Once the Work with Object Locks appears key in 5 (Work with Job) next to the only QRWTSRVR job that should be listed This shows the Work with Job dialog Select option 10 to display the job log for the database server job Now the developer can search the job log for any error messages generated by the DB2 runtime

Sometimes it is also useful to include debug messages in the job log The debug messages are informational messages written to the job log about the implementation of a query They describe query implementation methods such as use of indexes join order ODP implementation (reusable versus non-reusable) and so on The easiest way to instruct the iSeries server to include the debug messages is to call the following stored procedure just after the connection to the iSeries server is established

EXEC SQL call qsysqcmdexc(STRDBGUPDPROD(YES)000000002000000)

A sample of the job log messages with debug messages enabled is shown below in Figure 20

Arrival sequence access was used for file STAFFAccess path suggestion for file STAFFQuery options used to build the OS400 query access plan Ending debug message for query ODP created Blocking used for queryCursor SQLCUR201 opened1 rows fetched from cursor SQLCUR201Row not found for SQLCUR201ODP deleted Cursor SQLCUR201 closedDESCRIBE of prepared statement STMT0201 completed

Figure 20 mdash Joblog with debug messages enabled

So the job log offers fairly detailed information on how the AIX client requests were implemented by the DB2 runtime

39

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 DRDA trace utilityThe DB2 DRDA trace utility (db2drdat) provides detailed information about the data streams exchanged between DB2 Connect and target database server The output file produced by the utility contains send and receive communications buffers TCPIP error messages and SQL Communications Area (SQLCA) information Please refer to lsquoDB2 Connect Userrsquos Guidersquo manual for in-depth discussion of the DRDA trace utility

Accessing DB2 UDB for iSeries from CLI DB2 Call Level Interface (CLI ) is based on the Microsoft Open Database Connectivity (ODBC) specification and the ISO CLI standard The DB2 CLI interface gained popularity among DB2 application providers because the developer can build an ODBC application by simply linking the application with libdb2 library on a UNIX server In other words the developer directly utilizes the DB2 ODBC driver services without a need for an ODBC driver manager Additionally in contrast to embedded SQL the developer does not need to precompile or bind DB2 CLI applications because they use packages provided with DB2 UDB The developer simply compiles and links the application

Prerequisites A DB2 CLI application running in an AIX partition will use DB2 Connect services to access DB2 UDB for iSeries therefore make sure that all components listed in Prerequisites section of this paper on page 24 are installed The developer also needs to create a remote database connection as described in the DB2 Connect configuration section of this paper on page 24

Dynamic SQL and Access Plan Caching A DB2 CLI client application uses the dynamic SQL interface and does not have the capability to utilize the extended dynamic SQL support Therefore it runs lsquopurersquo dynamic SQL statements That does not mean however that the process of parsing validating and optimizing will be repeated for every execution of a given dynamic SQL statement

The DB2 UDB for iSeries database implements an internal object called System-Wide SQL Statement Cache (SWSC) The SWSC can improve the performance of programs using dynamic SQL statements by caching the access plans in a system-wide cache When a dynamic SQL statement is submitted the SQL runtime searches the SWSC to see if this statement has been previously executed If so then DB2 retrieves and reuses the key information associated with the cached statement and thereby the processing time and the resources utilization can be significantly reduced

Simple DB2 CLI C++ ApplicationThis section covers DB2 CLI implementation details for a sample C++ program called testclicpp (the source is provided at the end of this paper in Appendix C) To compile the source with Visual C++ complier use the following command in the AIX partition

xlC ndashI$INSTHOMEsqllibinclude ndashc testclicppxlC ndasho testcli testclio ndashL$INSTHOMEsqlliblib ndashldb2

The application performs a join between STAFF and ORG tables located in DB2USER schema (library) The join statement retrieves the DEPTNAME column from ORG NAME and JOB columns from STAFF and calculates the total compensation for an employee by adding SALARY and COMM columns in STAFF The results are sorted by total compensation The selection criterion is based on the current value of the department name parameter Here is the SELECT statement used by testcli

40

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

select name job salary + coalesce(comm0) as compensationfrom org o staff swhere odeptnumb = sdeptand deptname = order by compensation desc

Figure 21 shows the software components involved in the execution of this sample application

Figure 21 How a DB2 CLI client accesses DB2 UDB on an iSeries server

Although the testcli application is fairly simple it covers some important aspects of efficient CLI programming for DB2 UDB for iSeries

Reusable Open Data Paths (ODPs)An Open Data Path (ODP) definition is an internal i5OS object that is created when certain SQL statements (such as OPEN INSERT UPDATE and DELETE) are executed for the first time in a given job (or connection) The ODP can be thought of as a runtime implementation of an access plan The access plan created at the optimization time provides a recipe or in other words a sequence of steps necessary to execute the statement The ODP on the other hand provides the executable code for all requested IO operations The process of creating new ODP objects is fairly CPU- and IO-intensive so whenever possible the iSeries DB2 runtime tries to reuse existing ODPs For instance a SQLCloseCursor() API call may close the SQL cursor but leave the ODP available to be used the next time the cursor is opened This can significantly reduce the processing and response time in running SQL statements A reusable OPD usually requires 10 to 20 times less CPU resources than a newly created ODP Therefore it is important that the applications employ programming techniques that allow the DB2 runtime to reuse ODPs

With dynamic interfaces such as CLI full opens are avoided by using a prepare once execute many programming paradigm It means that when an SQL statement is going to be executed more than once you should prepare the statement just once and then reuse the prepared

41

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

statements for consecutive executions Although DB2 UDB does try to convert literals to parameter markers so that similar statements can be reused it is a better programming practice to explicitly implement parameter markers That way the chances for reusable ODPs are quite significantly improved The code snippet in Figure 22 illustrates how to implement the prepare once execute many programming technique

Define A SELECT SQL Statementstrcpy((char ) SQLStmt select name job salary + ifnull(comm0) ascompensation )ptr = strcat( (char ) SQLStmt from org o staff s )ptr = strcat( (char ) SQLStmt where odeptnumb = sdept)ptr = strcat( (char ) SQLStmt and deptname = )ptr = strcat( (char ) SQLStmt order by compensation desc) [1]

Prepare The SQL Statementrc = SQLPrepare(ExampleStmtHandle SQLStmt SQL_NTS) [2]

Bind The Columns In The Result Data Set Returned To Application Variablesrc = SQLBindCol(ExampleStmtHandle 1 SQL_C_CHAR (SQLPOINTER)

ExampleName sizeof(ExampleName) NULL)rc = SQLBindCol(ExampleStmtHandle 2 SQL_C_CHAR (SQLPOINTER)

ExampleJob sizeof(ExampleJob) NULL)rc = SQLBindCol(ExampleStmtHandle 3 SQL_C_DOUBLE (SQLPOINTER)

ampExampleComp sizeof(ExampleComp) NULL)

for (int i = 0 i lt LOOPS i++)rc=SQLBindParameter(ExampleStmtHandle

1SQL_PARAM_INPUTSQL_C_CHARSQL_CHAR10(SQLPOINTER) currentDepartment[i8]0NULL) [3]

rc = SQLExecute(ExampleStmtHandle) [4]cout ltlt endl ltlt Current Dept ltlt currentDepartment[i8] ltlt endl Display The Results Of The SQL QueryExampleShowResults()

Figure 22 Use the prepare once execute many programming technique

The error-handling code has been removed for clarity At [1] the statement text is assigned to a variable Note that a parameter marker is used in the WHERE clause The statement is then prepared just once at [2] The current value of the parameter is bound to the prepared statement at [3] The prepared statement is executed at [4] Steps [3] and [4] are repeatedly executed in a for loop

Techniques to Further Improve DB2 CLI Performance Thus far this paper has discussed the techniques used by a sample application to tune the CLI performance However depending on the application architecture other methods of improving CLI performance may be considered

Connection PoolingCurrently the CLI application connecting through DB2 Connect to DB2 UDB for iSeries does not take advantage of the connection pooling mechanism implemented by DB2 Connect Therefore for performance reasons the author strongly recommends that the application server that obtains and drops connections very frequently implements its own database connection pooling mechanism that would assign an existing pooled database connection to a new AIX process or thread

42

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Blocking

For queries which result in returning large data blocks from the iSeries server (usually 32K of data and above) ensure that the database manager configuration parameter RQRIOBLK is set to 32767 This can be done using the Command Line Processor (CLP) as follows

db2 update database manager configuration using RQRIOBLK 32767

TroubleshootingThe experience of the author shows that two tools are particularly useful for pinning down the potential problem areas bull Joblog messages for a database server job usually provides enough details to isolate DB2

runtime issues bull CLI trace utility provides granular information about the data flow between the AIX application

and the database server job

Job Log MessagesThe process of finding and analyzing the job log for a DB2 CLI connection is identical to the process outlined for an embedded SQL application in the Job Log Message section of this paper on page 39

CLI Trace The DB2 CLIODBCJDBC trace utility provides very detailed information about the data streams exchanged between DB2 Connect and target database server Refer to the DB2 Information Center for more information on how to set up and analyze the CLI traces httppublibboulderibmcominfocenterdb2v8luwindexjsptopic=comibmdb2udbdocadc000 7959htm

43

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Trademarks

IBM eServer iSeries AIX AIX 5L i5OS WebSphere DB2 DB2 Universal Database DB2 Connect OS400 zOS OS390 Distributed Relational Database Architecture DRDA and DB2 Information Integration are trademarks or registered trademarks of International Business Machines Corporation in the United States and other countries

Java and all Java-based trademarks are trademarks of Sun Microsystems Inc in the United States other countries or both

Linux is a registered trademark of Linus Torvalds in the United States other countries or both

UNIX is a registered trademark of The Open Group in the United States and other countries

Microsoft and Windows are registered trademarks of Microsoft Corporation in the United States andor other countries

All other registered trademarks and trademarks are properties of their respective owners

IBM makes no commitment to make available any products referred to herein

References in this publication to IBM products or services do not imply that IBM intends to make them available in every country in which IBM operates

Additional Information ITSO offers a Redbook that can be helpful to those who want to learn more about i5OS AIX integration

bull AIX Integration with I5OS on the IBM eServer iSeries Server (SG24-6551)

Jarek Miszczyk is the Senior Software Engineer IBM eServer Solutions Enablement IBM Rochester

[Portions of this white paper reprinted with permission from MC Mag Online published by MC Press LLP httpwwwmcpressonlinecom]

Acknowledgments The author would like to thank the following people for their advice contributions and support on this paper

Bob Bittner IBM Rochester Jon Rush IBM Rochester Prasad Vallurupalli IBM Rochester Neil Willis IBM Rochester

44

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix A Source Listing of TestJDBCjava

package comibmiseriespwdimport javasqlimport javaxnamingimport javautilHashtableimport javautilimport javaxsqlimport comibmas400access

public class TestJDBC public static void main(javalangString[] args)

throws Exception

int numOfLoops = 5000int outerNumOfLoops = 5boolean firstExec = trueConnection conStatement sPreparedStatement psPreparedStatement pstmtdelCallableStatement cstmPreparedStatement pstmtHashtable env = new Hashtable()

envput(ContextINITIAL_CONTEXT_FACTORYcomsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env)Systemoutprintln(Deploying connection pooling data source)deployDataSource() Do the work with connection pooling onlyAS400JDBCConnectionPoolDataSource tkcpds =

(AS400JDBCConnectionPoolDataSource)ctxlookup(jdbcToolkitDataSource) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPool pool = new AS400JDBCConnectionPool(tkcpds) Adds 1 connection to the pool that can be used by theapplication (creates the physical database connections based onthe data source)poolfill(1)Systemoutprintln(nStart timing Toolkit connection pooling)long startTime = SystemcurrentTimeMillis()

for (int i = 0 i lt outerNumOfLoops i++) con = poolgetConnection()consetAutoCommit(false) deleteif ( i == 0)

long startDelete = SystemcurrentTimeMillis()cstm = cstm = conprepareCall(

CALL qsysqcmdexc(CLRPFM FILE(DB2USERCOFFEES) + 000000002800000))

cstmexecuteUpdate()cstmclose()long endDelete = SystemcurrentTimeMillis()Systemoutprintln(Delete all records +

(endDelete - startDelete) + ms elapsed)

45

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

String sqlinstrlong startInsert = SystemcurrentTimeMillis() insert

pstmt =conprepareStatement(INSERT INTO COFFEES VALUES( ))for (int j = 0 j lt numOfLoops j++) pstmtsetString(1 Kona_ + IntegertoString(i))pstmtsetInt(2 150)pstmtsetFloat(3 999f)pstmtsetInt(4 0)pstmtsetInt(5 0)pstmtaddBatch()int [] updateCounts = pstmtexecuteBatch()concommit()pstmtclose()long endInsert = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for + numOfLoops + inserts

+ (endInsert - startInsert)) selectlong startSelect = SystemcurrentTimeMillis()ps = conprepareStatement(SELECT FROM COFFEES)ResultSet rs = psexecuteQuery()rsnext()rsclose()concommit()psclose()long endSelect = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for select +

(endSelect - startSelect))consetAutoCommit(true)conclose()long endTime = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for + outerNumOfLoops +

loops + (endTime - startTime))Systemexit(0)

private static void deployDataSource()throws ExceptionString serverName = teraplex String databaseName = TERAPLEX String userName = db2user String password = db2pwd

Establish a JNDI context and bind the connection pool data sourceHashtable env = new Hashtable()envput(ContextINITIAL_CONTEXT_FACTORY

comsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPoolDataSource tkcpds = new

AS400JDBCConnectionPoolDataSource()tkcpdssetServerName(serverName) tkcpdssetDatabaseName(databaseName) tkcpdssetUser(userName) tkcpdssetPassword(password) tkcpdssetDescription(Toolkit Connection Pooling DataSource)tkcpdssetSavePasswordWhenSerialized(true)tkcpdssetExtendedDynamic(true)

46

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

tkcpdssetPackage(JDBCDS)tkcpdssetPackageCache(true)tkcpdssetPackageCriteria(select)enable the following properties as requiredcpdssetTrace(true)tkcpdssetServerTraceCategories( AS400JDBCDataSourceSERVER_TRACE_DEBUG_SERVER_JOB)

ctxrebind(jdbcToolkitDataSource tkcpds)

47

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix B mdash Source Listing of cursorsjsqc

Source File Name = cursorsjsqc Licensed Materials - Property of IBM (C) COPYRIGHT International Business Machines Corp 1995 2000 2004 All Rights Reserved US Government Users Restricted Rights - Use duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp PURPOSE This sample program demonstrates the use of a CURSOR The CURSOR is processed using static SQL EXTERNAL DEPENDENCIES - Ensure existence of database for precompile purposes - Precompile with the SQL precompiler (PREP in DB2) - Bind to a database (BIND in DB2) - Compile and link with the IBM Cset++ compiler (AIX and OS2) or the Microsoft Visual C++ compiler (Windows) or the compiler supported on your platform For more information about these samples see the README file For more information on programming in C see the - Programming in C and C++ section of the Application Development Guide For more information on building C applications see the - Building C Applications section of the Application Building Guide For more information on the SQL language see the SQL Reference

include ltstdiohgt include ltstdlibhgt include ltstringhgtinclude ltsqlhgtinclude ltsqlenvhgtinclude ltsqldahgtinclude ltsqlcahgt

int SqlInfoPrint( char struct sqlca int char )void TransRollback( void)

define EMB_SQL_CHECK( MSG_STR ) rc = SqlInfoPrint( MSG_STR ampsqlca __LINE__ __FILE__) if ( rc = 0 ) TransRollback( )

return 1

EXEC SQL INCLUDE SQLCA

int main(int argc char argv[])

EXEC SQL BEGIN DECLARE SECTIONchar dname[15]

48

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

char pname[10]double compchar userid[9]char passwd[19]

EXEC SQL END DECLARE SECTION

int rc = 0printf( Sample C program CURSORSJ n )if (argc == 1)

EXEC SQL CONNECT TO TPLXEMB_SQL_CHECK(CONNECT TO TPLX)

else if (argc == 3)

strcpy (userid argv[1])strcpy (passwd argv[2])EXEC SQL CONNECT TO TPLX USER userid USING passwdEMB_SQL_CHECK(CONNECT TO TPLX)

else

printf (nUSAGE cursor [userid passwd]nn)return 1

endif

EXEC SQL DECLARE c1 CURSOR FORselect deptname name salary + ifnull(comm0) as compensationfrom org o staff swhere odeptnumb = sdeptorder by deptname compensation desc

EXEC SQL OPEN c1EMB_SQL_CHECK(OPEN CURSOR)

printf(DEPARTMENT NAME COMPENSn)printf(-----------------------------------n)do

EXEC SQL FETCH c1 INTO dname pname compif (SQLCODE = 0) breakprintf( -1515s -1010s 72fn dname pname comp )

while ( 1 )

EXEC SQL CLOSE c1EMB_SQL_CHECK(CLOSE CURSOR)

EXEC SQL CONNECT RESETEMB_SQL_CHECK(CONNECT RESET)

exit(0)

end of program CURSORSJSQC

int SqlInfoPrint( char appMsgstruct sqlca pSqlcaint linechar file )

int rc = 0char sqlInfo[1024]char sqlInfoToken[1024]char sqlstateMsg[1024]char errorMsg[1024]

if (pSqlca-gtsqlcode = 0 ampamp pSqlca-gtsqlcode = 100)

49

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

strcpy(sqlInfo )if( pSqlca-gtsqlcode lt 0) sprintf( sqlInfoToken n---- error report ----n)

strcat( sqlInfo sqlInfoToken)else sprintf( sqlInfoToken n---- warning report ----n)

strcat( sqlInfo sqlInfoToken) endif

sprintf( sqlInfoToken app message = sn appMsg)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken line = dn line)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken file = sn file)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken SQLCODE = ldn pSqlca-gtsqlcode)strcat( sqlInfo sqlInfoToken)

get error message rc = sqlaintp( errorMsg 1024 80 pSqlca) return code is the length of the errorMsg string if( rc gt 0) sprintf( sqlInfoToken sn errorMsg)

strcat( sqlInfo sqlInfoToken)

get SQLSTATE message rc = sqlogstt( sqlstateMsg 1024 80 pSqlca-gtsqlstate)if (rc == 0) sprintf( sqlInfoToken sn sqlstateMsg)

strcat( sqlInfo sqlInfoToken)

if( pSqlca-gtsqlcode lt 0) sprintf( sqlInfoToken --- end error report ---n)

strcat( sqlInfo sqlInfoToken)printf(s sqlInfo)return 1

else sprintf( sqlInfoToken --- end warning report ---n)

strcat( sqlInfo sqlInfoToken)printf(s sqlInfo)return 0

endif endif

return 0

void TransRollback( ) struct sqlca sqlca

int rc = 0 rollback the transaction printf( nRolling back the transaction n)

EXEC SQL ROLLBACKrc = SqlInfoPrint( ROLLBACK ampsqlca __LINE__ __FILE__)if( rc == 0) printf( The transaction was rolled backn)

50

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

51

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix C mdash Source Listing of testclicpp

Include The Appropriate Header Filesinclude ltsqlclihgtinclude ltsqlcli1hgtinclude ltsqlutilhgtinclude ltsqlenvhgtinclude ltstdiohgt include ltiostreamgt include ltlocalehgt include ltstringhgtdefine SQL_SQLSTATE_SIZE 5define LOOPS 8

using namespace std

Define The CLI_Class Classclass CLI_Class

Attributespublic

SQLHANDLE EnvHandleSQLHANDLE ConHandleSQLHANDLE StmtHandleSQLRETURN rcSQLCHAR Job[6]SQLCHAR Name[10]SQLDOUBLE Comp

Operationspublic

CLI_Class()~CLI_Class()SQLRETURN ShowResults()

Constructor Destructor

SQLRETURN printError( SQLHDBC SQLHSTMT)

Define The Class ConstructorCLI_ClassCLI_Class()

setlocale( LC_ALL )

Initialize The Return Code Variablerc = SQL_SUCCESS

Allocate An Environment Handlerc = SQLAllocHandle(SQL_HANDLE_ENV SQL_NULL_HANDLE ampEnvHandle)

Allocate A Connection Handleif (rc == SQL_SUCCESS)

rc = SQLAllocHandle(SQL_HANDLE_DBC EnvHandle ampConHandle)

Define The Class DestructorCLI_Class~CLI_Class()

Free The Connection Handleif (ConHandle = NULL)

SQLFreeHandle(SQL_HANDLE_DBC ConHandle)

Free The Environment Handle

52

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

if (EnvHandle = NULL)SQLFreeHandle(SQL_HANDLE_ENV EnvHandle)

Define The ShowResults() Member FunctionSQLRETURN CLI_ClassShowResults(void)

While There Are Records In The Result Data Set Generated Retrieve And Display Themcout ltlt Name Job Compensation ltlt endlcout ltlt --------- ------ ------------ ltlt endlcoutsetf(iosleft)coutprecision(2)coutsetf(iosfixed)while (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)

rc = SQLFetch(StmtHandle)if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)

coutwidth(15)cout ltlt Name

coutwidth(10)cout ltlt Job

coutwidth(7)cout ltlt Comp ltltendl

if(rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO ampamp rc = SQL_NO_DATA)printError(ConHandle StmtHandle)

else

rc = 0SQLCloseCursor(StmtHandle)

Return The ODBC API Return Code To The Calling Functionreturn(rc)

SQLRETURN CLI_ClassprintError (SQLHDBC hdbc

SQLHSTMT hstmt)

SQLCHAR buffer[SQL_MAX_MESSAGE_LENGTH + 1]SQLCHAR sqlstate[SQL_SQLSTATE_SIZE + 1]SQLINTEGER sqlcodeSQLSMALLINT lengthSQLRETURN rcwhile ((rc = SQLError(SQL_NULL_HENV hdbc hstmt

sqlstateampsqlcodebufferSQL_MAX_MESSAGE_LENGTH + 1amplength)) == SQL_SUCCESS || rc ==

SQL_SUCCESS_WITH_INFO)

cout ltlt SQLSTATE ltlt sqlstate ltlt endlcout ltlt SQLCODE ltlt sqlcode ltlt endlcout ltlt Error msg ltlt buffer ltlt endl

53

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

cout ltlt----------------------------- ltlt endl ltlt endl

return(SQL_ERROR)

----------------------------------------------------------------- The Main Function -----------------------------------------------------------------int main()

Declare The Local Memory Variables

(SQLCHAR ) db2user SQL_NTS (SQLCHAR ) test26t SQL_NTS)

SQLRETURNSQLCHARSQLCHARSQLCHARchar

SQLCHAR

rc = SQL_SUCCESSDBName[10] = TPLXSQLStmt[255]c[10]ptrcurrentDepartment[8][15] = Head Office

New England Mid Atlantic South Atlantic Great Lakes PlainsPacificMountain

Create An Instance Of The CLI_Class ClassCLI_Class Example

Connect To iSeries Database if (ExampleConHandle = NULL)

rc = SQLConnect(ExampleConHandle DBName SQL_NTS

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)ExampleprintError(ExampleConHandle SQL_NULL_HSTMT)

return(rc)

cout ltlt Successfully connected to ltlt DBName ltlt ltlt endlrc = SQLSetConnectAttr(ExampleConHandle SQL_ATTR_AUTOCOMMIT

(SQLPOINTER) SQL_AUTOCOMMIT_OFF SQL_IS_UINTEGER) Allocate An SQL Statement Handlerc = SQLAllocHandle(SQL_HANDLE_STMT ExampleConHandle

ampExampleStmtHandle)if (rc == SQL_SUCCESS)

Define A SELECT SQL Statement

strcpy((char ) SQLStmt select name job salary + ifnull(comm0) ascompensation )

ptr = strcat( (char ) SQLStmt from org o staff s )ptr = strcat( (char ) SQLStmt where odeptnumb = sdept)ptr = strcat( (char ) SQLStmt and deptname = )ptr = strcat( (char ) SQLStmt order by compensation desc)

Prepare The SQL Statementrc = SQLPrepare(ExampleStmtHandle SQLStmt SQL_NTS)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)ExampleprintError(ExampleConHandle ExampleStmtHandle)

54

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

return(rc)

Bind The Columns In The Result Data Set Returned To Application Variables

rc = SQLBindCol(ExampleStmtHandle 1 SQL_C_CHAR (SQLPOINTER)ExampleName sizeof(ExampleName) NULL)

rc = SQLBindCol(ExampleStmtHandle 2 SQL_C_CHAR (SQLPOINTER)ExampleJob sizeof(ExampleJob) NULL)

rc = SQLBindCol(ExampleStmtHandle 3 SQL_C_DOUBLE (SQLPOINTER)ampExampleComp sizeof(ExampleComp) NULL)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO) ExampleprintError(ExampleConHandle ExampleStmtHandle)

return(rc)

while (true)

for (int i = 0 i lt LOOPS i++)

rc=SQLBindParameter(ExampleStmtHandle1SQL_PARAM_INPUTSQL_C_CHARSQL_CHAR

150(SQLPOINTER) currentDepartment[i8]0NULL)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)

ExampleprintError(ExampleConHandle ExampleStmtHandle)return(rc)

rc = SQLExecute(ExampleStmtHandle)if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)

ExampleprintError(ExampleConHandle ExampleStmtHandle)return(rc)

cout ltlt endl ltlt Current Dept ltlt currentDepartment[i8] ltlt

endl Display The Results Of The SQL QueryExampleShowResults()if(rc = 0)break

if ( i500 == 0 ampamp i gt 0 )cout ltlt Loops ltlt i ltlt ltlt endl

cout ltlt AFTER ltlt LOOPS ltlt loops Press X to exit ltlt endlcin gtgt cif (c[0] == x || c[0] == X)

break

Free The SQL Statement Handleif (ExampleStmtHandle = NULL )

SQLFreeHandle(SQL_HANDLE_STMT ExampleStmtHandle) Disconnect From The Northwind Sample Databaserc = SQLDisconnect(ExampleConHandle)

Return To The Operating Systemreturn(rc)

55

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

display the job log for the database server job Now the job log can be searched for any error messages generated by the DB2 runtime

Sometimes it is also useful to include debug messages in the job log The debug messages are informational messages written to the job log about the implementation of a query They describe query implementation methods such as the use of indexes join order ODP implementation (reusable versus non-reusable) and so on The easiest way to instruct an iSeries server to include the debug messages is to set the ServerTraceCategories property on the data source object

tkcpdssetServerTraceCategories(AS400JDBCDataSourceSERVER_TRACE_DEBUG_SERVER_JOB)

A sample of the job log messages with debug messages enabled is shown below

SET TRANSACTION completeSTATEMENT NAME FOUND QZ868F0A458E13AF8C Starting optimizer debug message for query Arrival sequence access was used for file COFFEESODP created ODP not deleted 5000 rows inserted in COFFEES in DB2USER STATEMENT NAME FOUND QZ868F0A4C144BF12EBlocking used for queryCursor CRSR0001 opened606 rows fetched from cursor CRSR0001 ODP not deleted Cursor CRSR0001 closed

So the job log offers fairly detailed information on how the AIX client requests were implemented by the DB2 runtime

JDBC Trace UtilityThe JTOpen driver provides a tracing utility which can be used to collect detailed client-side traces The JDBC tracing is turned off by default It can be enabled by setting the Trace property to true Heres an example of how to switch on tracing using the setTrace method on the data source object

tkcpdssetTrace(true)

The trace can also be enabled when using the DriverManagergetConnection() method for obtaining a connection to DB2 UDB for iSeries In this case the developer could add the trace property to the connection string This approach is illustrated in the following code snippet

ClassforName(comibmas400accessAS400JDBCDriver) [1] hellip con = DriverManagergetConnection(jdbcas400teraplextrace=true

db2userdb2pwd) [2]

At [1] an instance of the JTOpen JDBC Driver is initiated Then at [2] the driver is used to obtain a connection to the iSeries server Note how the trace property has been added to the database URL See the IBM Toolbox for Java JDBC properties documentation on the iSeries Information Center Web site for a complete list of properties supported by the JTOpen driver

Although the level of details provided by the trace utility is sufficient in most troubleshooting scenarios sometimes the developer may need to collect low-level traces scoped to a certain type

17

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

of information In V5R3 the IBM Toolbox for Java (as well as the latest JTOpen) added a comprehensive detailed trace facility The following is the complete list of detailed trace parameters and their purpose

bull None or ldquordquo ndash This setting disables the detailed trace bull datastream - This category is used by Toolbox classes to log dataflow between the local host

and the remote system It is not intended for use by application classes bull diagnostic - This category is used to log object state information bull error - This category is used to log errors that cause an exception bull information - This category is used to track the flow of control through the code bull warning - This category is used to log errors that are recoverable bull conversion - This category is used by Toolbox classes to log character set conversions

between Unicode and native code pages bull proxy - This category is used by Toolbox classes to log data flow between the client and the

proxy server bull pcml - This category is used to determine how PCML interprets the data that is sent to and

from the server bull jdbc - This category is used to track JDBC calls throughout the program bull thread - This category is used to enable tracing of thread information This is useful when

debugging multi-threaded applications bull all - This category will enable all previous categories

The detailed trace can be enabled when using the DriverManagergetConnection() method for obtaining a connection to DB2 UDB for iSeries In this case the developer could add the toolbox trace property to the connection string This is illustrated in the following code sample

String dbUrl = jdbcas400pwd1toolbox trace=diagnostic con = DriverManagergetConnection(dbUrl dbUser dbPassword)

Note that currently the driverrsquos DataSource interfaces do not allow the developer to directly activate the detailed tracing However they could set the server from the command line at the time the java program is launched The example below shows how the detailed trace properties could be enabled at the command line

java -Dcomibmas400accessTracecategory=diagnostic TestJDBC

The -D switch indicates to the java interpreter that the information following it will be a system property

In case of a WebSphere application the trace property can be set through the admin console In the console select Application Servers-gt server1-gt Process Definition -gt Java Virtual Machine Figure 9 shows how to set the Generic JVM Arguments for an application server instance

18

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 9 Setting JVM arguments to enable detailed Toolbox tracing

Database Monitor

The database monitor is the ultimate tool available on DB2 UDB for iSeries to collect low-level SQL traces It is mainly used to pin down the SQL performance problems Refer to the lsquoUsing iSeries Database Monitor to Identify and Tune SQL Queriesrsquo white paper for a detailed discussion on how to collect and analyze the database monitor traces httpibmcomserversenablesiteeducationiborecordhtmldtmon

IBM DB2 JDBC Universal Driver DB2 JDBC Universal Driver is one of the new features delivered with DB2 UDB Version 8 DB2 JDBC Universal Driver has been designed to eliminate the dependency on DB2 CLI runtime modules as well as to enable direct Type 4 connectivity to DB2 UDB for iSeries and DB2 UDB for zOSreg

The pure-Java (Type 4) remote connectivity is based on the DRDA open distributed protocol for cross-platform access to DB2 DRDA defines the rules the protocols and the semantics for accessing distributed data Applications can access data in a distributed relational environment by using SQL statements The iSeries DRDA application server implementation is based on multiple connection-oriented server jobs running in the QSYSWRK subsystem A DRDA listener job (QRWTLSTN) listens for TCP connect requests on port 446 Once an application requester connects to the listener job the listener wakes up one of the QRWTSRVR prestart jobs and assigns it to a given client connection Any further communication occurs directly between the client application and the QRWTSRVR job These concepts are illustrated in Figure 10

19

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 10 Accessing DB2 UDB for iSeries with DB2 Universal Driver

The DB2 Universal Driver can be loaded in an AIX partition by installing one of the DB2 Connect for AIX products (see the Additional Information section for details) It is also a part of a DB2 Enterprise Server Edition for AIX install Specifically the developer needs three JAR files in a AIX partition to successfully connect to an iSeries server db2jccjar db2jcc_license_cisuzjar and db2jcc_license_cujar The iSeries license is contained in db2jcc_license_cisuzjar Note that this file is not a part of DB2 Client In other words a DB2 Connect license is required to use the driver in production environments The location of the JAR files needs to be added to the CLASSPATH environment variable For instance the following entry could be added to the AIX profile script

CLASSPATH=homedb2inst2sqllibjavadb2jccjarCLASSPATH=$CLASSPATHhomedb2inst2sqllibjavadb2jcc_license_cujarCLASSPATH=$CLASSPATHhomedb2inst2sqllibjavadb2jcc_license_cisuzjarexport CLASSPATH

Java Runtime 131 is a prerequisite

Additionally the developer should install the latest database group PTF (SF99503 for i5OS V5R3) on the iSeries server The Informational APAR ii13348 is keeping track of any fixes relevant to DRDA above and beyond the current database group PTF

Obtaining a Connection to DB2 UDB for iSeries When Type 4 connectivity is used the DB2 Universal Driver connects directly to the DB2 on iSeries through TCPIP Note that this is different from the legacy DB2 Type 2 JDBC driver that requires a DB2 node and remote database configurations on the client accessing iSeries The following code snippet illustrates how to use the DB2 JDBC Universal Driver to obtain a connection to DB2 UDB for iSeries

20

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

try ClassforName(comibmdb2jccDB2Driver) [1] catch(javalangClassNotFoundException e) Systemerrprint(ClassNotFoundException )Systemerrprintln(egetMessage())

try DriverManagergetConnection(jdbcdb2teraplex446TERAPLEX[2]

db2userdb2pwd) hellip catch(SQLException ex) Systemerrprintln(

SQLException + exgetMessage())

At [1] an instance of the DB2 JDBC Universal Driver is instantiated Then at [2] the driver is used to obtain a connection to the iSeries server Note the proper form of the database URL required by the driver

Considerations There are several advantages of DB2 JDBC Universal Driver bull Ease of cross-platform development mdash Consistent coding techniques and consistent error

codes and messages bull Ease of deployment mdash Pure Java (no runtime client required) and a single driver for accessing

DB2 on different platforms

The ease of use comes at a price though The iSeries JTOpen driver is optimized for accessing DB2 UDB for iSeries data and it uses native iSeries protocol to communicate with the back-end database server job This usually results in better performance and more-efficient system resources utilization For instance when using the DB2 JDBC Universal Driver to access an iSeries server the executeBatch method results in a single record insert There are also some restrictions when using DB2 Universal JDBC Driver with Type 4 connectivity

bull Support for distributed transactions (JTA) is not enabled bull Driver built-in connection pooling is not supported

Refer to Java application support in DB2 for more details on DB2 JDBC Universal Driver

21

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 Connect data access This section will explore the most important aspects of DB2 Connect ndash iSeries integration - including configuration tips and coding examples

DB2 Connect provides functionality for accessing data stored in DB2 UDB for iSeries as well as DB2 UDB for zOS and DB2 UDB for OS390reg DB2 Connect offers capabilities to access DB2 family members via several SQL interfaces gateway functions such as connection pooling and federated database functionality Many applications supporting the DB2 family of products leverage DB2 Connect as a key middleware component DB2 Connect is offered as separate AIX license products

Enterprise Edition Application Server Edition

In addition to DB2 Connect there are several other DB2 UDB Version 81 products that are supported on AIX

DB2 Universal Database Enterprise Server Edition DB2 Universal Database Workgroup Server Unlimited Edition DB2 Universal Database Workgroup Server Edition DB2 Universal Database Universal Developers Edition All Clients

The DB2 Connect Enterprise Edition functionality is also contained in DB2 Enterprise Server Edition for AIX

22

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 Connect in a nutshell In the scenario described in this paper the DB2 Connect functions contained in DB2 Enterprise Edition for AIX are utilized DB2 Connect Enterprise Edition provides support for both local and remote DB2 clients This is illustrated in Figure 11 Accessing DB2 UDB for iSeries with DB2 Connect

Figure 11 Accessing DB2 UDB for iSeries with DB2 Connect

DB2 Connect implements the Distributed Relational Database Architecturetrade (DRDAreg) to reduce the cost and complexity of accessing data stored in DB2 UDB for iSeries and other DRDA-compliant database servers DRDA defines the rules the protocols and the semantics for accessing distributed data Applications can access data in a distributed relational environment by using SQL statements In a distributed environment the system running the application and sending the SQL requests across the network is called the application requester (AR) A remote database server that executes SQL requests submitted by an application requester is known as the application server (AS) In the example shown in Figure 11 (above) DB2 Connect plays the role of an application requester while DB2 UDB for iSeries is an application server In this case DB2 Connect communicates with the iSeries database through TCPIP The iSeries DRDA application server implementation is based on multiple connection-oriented server jobs running in the QSYSWRK subsystem A DRDA listener job (QRWTLSTN) listens for TCP connect requests on port 446 Once an application requester connects to the listener job the listener wakes up one of the QRWTSRVR prestart jobs and assigns it to a given client connection Any further communication occurs directly between the client application and the QRWTSRVR job

DB2 Connect supports a wide range of programming interfaces that can be used by AIX applications to access the iSeries database Embedded SQL frac34 Both static and dynamic SQL frac34 Various programming languages (Java CC++ Cobol Fortran REXX)

DB2 Call Level Interface (DB2 CLI) ODBC JDBC frac34 DB2 JDBC Type 2 Driver frac34 DB2 JDBC Type 4 Driver (Universal JDBC Driver)

23

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Note that DB2 Connect supports access to DB2 UDB for iSeries through DB2 JDBC Universal driver However for performance and ease of maintenance reasons IBM recommends that Java applications running in AIX use native iSeries Toolbox JDBC driver See the JDBC Data Access section of this paper (above) for more details On the other hand DB2 Connect is a very efficient and robust connectivity option for AIX applications especially in the environments that are not directly supported by the native iSeries JDBC driver Here are several possible scenarios that would require DB2 Connect installed in a AIX partition

Embedded SQL interface is used to access DB2 CLI or ODBC interface is used to access DB2 A single SQL interface is needed to access multiple back end DB2 server Specific DB2 Connect functionality is needed such as distributed join or connection

pooling

Prerequisites One of the DB2 Connect products or DB2 Enterprise Server Edition for AIX V81 is needed Additionally DB2 Application Development Client is required in the AIX partition to compile DB2 applications

For maximum database server stability the developer should install the latest database group PTF (SF99503 for i5OS V5R3) on the iSeries server The Informational APAR ii13348 is keeping track of any fixes relevant to DRDA above and beyond the current database group PTF

DB2 Connect configuration The following example employs i5OS V5R3 and DB2 UDB Enterprise Server Edition for AIX Version 81 FixPak 6

Configuration steps in the iSeries partition The following process lists the necessary steps to be performed on the iSeries server 1) Verify that the TCPIP stack is working correctly It is assumed that the Virtual LAN is used to

communicate with the i5OS partition First obtain the IP address of the iSeries server or its hostname and ping the iSeries server from the AIX partition

2) Create a relational database (RDB) entry for the iSeries database in the i5OS partition If this has already been created it can be displayed by using the DSPRDBDIRE command Make sure that the RDB entry with a location of LOCAL exists on the iSeries server If it does not exist use the ADDRDBDIRE command to add the appropriate RDB entry For example the following command would add an RDB entry named TPLX For simplicity it is recommended that the TCPIP host name and RDB entry remain the same

ADDRDBDIRE RDB(TPLX) RMTLOCNAME(LOCAL)

3) Create a collection called NULLID This is necessary because the utilities shipped with DB2 Connect and DB2 UDB for AIX store their packages in the NULLID collection Since it does not exist by default in the iSeries server you must create it using the following command

CRTLIB LIB(NULLID)

4) Products that support DRDA automatically perform any necessary code page conversions at the receiving system For this to happen both systems need a translation table from their code page to the partner code page The default Coded Character Set Identifier (CCSID) on the iSeries server is 65535 Since DB2 Connect does not have a translation table for this code page the developer needs to change the individual user profiles to contain a CCSID that can be converted properly by DB2 Connect For US English this is 037 For other languages see DB2 Connect Personal Edition Quick Beginning GC09-2967 The following command changes the CCSID for an individual user profile to 037

24

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

CHGUSRPRF userid CCSID(037)

5) Verify that the default port 446 for DRDA service is being used To do this go to the Configure TCPIP menu (CFGTCP) select Configure Related Tables and then select Work with service table entries Verify that the DRDA service is set for port 446

6) The Distributed Data Management (DDM) job must be started for DRDA to work If you want the DDM job to be automatically started whenever TCPIP is started change the attributes of the DDM job using the CHGDDMTCPA command and set the Autostart server parameter to YES

7) If the system administrator chooses not to autostart the server issue the following command to start the DDM server job

STRTCPSVR SERVER(DDM)

8) Make sure that the user profiles that will be used to connect to the iSeries server exist on the server

25

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Configuration steps in the AIX partition The following steps are required for DB2 Connect to be configured in the AIX partition 1) Sign on to the AIX partition as the DB2 administrator 2) Launch Client Configuration Assistant (db2ca from the command prompt) It is assumed that

VNC or an X-Windows server are being used on the workstation so that the db2ca GUI can be properly rendered

3) From the Selected pull-down menu select the Add Database using Wizard option The Select how you want to setup a connection dialog appears Select Manually configure a connection to a database and click Next This is shown in Figure 12

Figure 12 Accessing DB2 UDB for iSeries with DB2 Connect

26

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

4) On the Select a communications protocol choose TCPIP and select The database physical resides on a host or OS400 system Then select the option Connect directly to the server as shown in Figure 13 Click Next

Figure 13 mdash Selecting communications protocol

27

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

5) On the TCPIP tab fill in the host name of the iSeries server The port number should be 446 This is shown in Figure 14 Click Next

Figure 14 mdash Specifying TCPIP communication parameters

28

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

6) On the Database tab fill in the Relational Database name Use the RDB entry name (specified in step 2) in the Configuration steps in the iSeries partition section as shown in Figure 15 Click Next

Figure 15 mdash Specifying the remote database

7) If you plan to use the ODBC applications select Register this database for ODBC as a system data source on the ODBC tab Click Next

29

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

8) On the Specify the node option dialog select OS400 from the Operating System pull-down menu This is shown in Figure 16 Click Finish

Figure 16 mdash Specifying the node options

30

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

9) The Test Connection dialog appears This allows the developer to verify that the connection works Select both CLI and JDBC check boxes You are also prompted for an iSeries user ID and password as shown in Figure 17

Figure 17 mdash Testing the connection

31

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

10) The successful connection to the database server is confirmed by the message box shown in Figure 18

Figure 18 mdash Test Connection results 11) At this time a newly configured database connection should appear in the main DB2

Configuration Assistant window It is recommended that the DB2 utilities are also bound to the iSeries database The bind process creates the necessary SQL packages on the remote database In the main Configuration Assistant window click the TPLX database entry and then select Selected-gtBindhellip

32

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

12) The Bind dialog appears Click Select All and then enter the connection information as shown in Figure 19 Click Bind The Results message box appears This allows the developer to monitor the progress of the binding process Watch for any error and warning messages

Figure 19 mdash Binding the DB2 utilities This concludes the DB2 Connect configuration steps

33

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Accessing DB2 UDB for iSeries from C embedded SQL

As mentioned earlier DB2 Connect allows developers to compile and run embedded SQL applications that access DB2 UDB for iSeries data This section covers implementation details for a C embedded SQL application called cursorsjsqc (see Appendix B for source code)

Prerequisites An embedded SQL application running in an AIX partition will use DB2 Connect services to access DB2 UDB for iSeries therefore the developer needs to make sure that all components listed in section Prerequisites on page 24 are installed The developer also needs to create a remote database connection as described in the DB2 Connect configuration section of this paper on page 24

Static SQL and SQL packages To successfully run against a DB2 UDB for iSeries database an embedded SQL application needs to be first precompiled and bound to the back-end database This process creates an SQL package on the target iSeries server The SQL package contains the access plan information for the SQL statements executed by the application The internal structure of the package as well as the method how its content is used by the SQL runtime to facilitate the access plan reuse is similar to the Extended Dynamic SQL support covered in detail in the Extended Dynamic SQL and Statement Caching section of this paper (on page 9) There are however important differences between the packages created by the extended dynamic SQL support and the packages created for embedded SQL DRDA client applications The extended dynamic SQL packages support dynamic SQL interfaces such as JDBC

that can submit ad hoc SQL statements at the run time The SQL runtime can prepare the dynamic statements and add them to the package On the other hand the DRDA packages are created at the precompile time and contain static SQL In order to add new statements to the package the application needs to be precompiled and rebound again

The extended dynamic SQL package can dynamically grow up to 500MB by allocating new space as required The DRDA packages since they are created at the precompile time have a fix size and do not grow over their life time

Simple embedded SQL application The application is based on a source code provided in the DB2 UDB samples directory typically to be found at homedb2inst1sqllibsamples The cursorsjsqc performs a join between STAFF and ORG tables located in DB2USER schema (library) on the TPLX database server (the source is provided at the end of this paper in Appendix B) The join statement retrieves the DEPTNAME column from ORG NAME column from STAFF and calculates the total compensation for an employee by adding SALARY and COMM columns in STAFF The results are sorted by department name and total compensation Here is the SELECT statement used by the application

SELECT deptname name salary + IFNULL(comm0) as compensationFROM org o staff sWHERE odeptnumb = sdeptORDER BY deptname compensation DESC

The application iterates through the selected records and prints out the data to the standard output device The sample DB2USER schema was created with the following SQL statements

db2 CONNECT TO tplx USER db2user USING mypassworddb2 CALL QSYSCREATE_SQL_SAMPLE(DB2USER)

34

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Make sure that the AIX partition is logged into with the DB2 admin user profile If the defaults were selected at the DB2 installation time this profile name is db2inst1 It is also assumed that DB2USER user exists on the iSeries server and that it has appropriate authority

There are several steps that are required to create an executable for the cursorsjsqc source code First the DB2 PRECOMPILE utility needs to be called The utility creates a bind file that is used to bind the required SQL package to the TPLX database It also converts embedded SQL statements into DB2 run-time API calls and produces a pure C source file that can be processed by an AIX C compiler

db2 CONNECT TO tplx USER db2user USING mypassworddb2 prep cursorsjsqc bindfile

Note that the connect statement is required only if the developer is not already connected to the database on an iSeries server Watch for any error or warning messages returned by the DB2 prep utility The prepare step should produce cursorsjbnd and cursorsjc files in the current directory Now the developer can invoke the bind utility to prepare the statements contained in the bind file and create the package on the target iSeries database server

db2 bind cursorsjbnd

It is assumed that Visual C++ 60 is installed and configured in the AIX partition Refer to the ldquoDeveloping and Porting C and C++ Applications on AIXrdquo redbook for more information on how to use the Visual C++ compiler httpibmcomredbooksabstractssg245674htmlOpen

Use the following commands to compile the C source generated by the precompile utility

xlc -I$INSTHOMEsqllibinclude ndashc cursorsjcxlc ndasho cursorsj cursorsjo -L$INSTHOMEsqlliblib ndashldb2

Run the program from the AIX prompt

cursorsj db2user mypassword

Distributed Join DB2 UDB Version 8 provides core federated server functionality A federated system consists of a DB2 UDB instance that operates as a federated server a database that acts as the federated database one or more data sources and clients (users and applications) that access the database and data sources Federated server permits objects stored in multiple databases to be accessed together in the same query For example a query can refer to a table that resides in DB2 UDB for iSeries and join it to a table stored in DB2 UDB for AIX Such a query would constitute so called distributed join The support for DB2 UDB for iSeries as a federated data source is provided by core federated server functionality directly implemented in DB2 UDB Enterprise Server Edition and DB2 UDB Connect Enterprise Edition All other DB2 UDB family members are also supported directly by core DB2 UDB federated server An additional software product DB2 Information Integratortrade is required to access non-DB2 UDB databases such as Oracle Sybase or Microsoftreg SQL Server Consult the following white papers for a detailed discussion on DB2 federated server support Heterogeneous data access for iSeries applications Version 2 httpibmcomserversenablesiteeducationiborecordhtmlhetdata Fundamentals of IBM DB2 Federated Server and Relational Connect httpwww7bsoftwareibmcomdmddlibrarytecharticle0206purnell0206purnellhtml

35

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Distributed Join Example In this section the steps that are required to configure DB2 UDB for iSeries as a federated data source will be illustrated Then the cursorsjsqc program will be ldquotweakedrdquo so that it executes a distributed join query that accesses data stored on an iSeries server and in the local DB2 UDB for AIX database It is assumed that the developer is familiar with the DB2 federated server concepts

Note Run the following commands from the Command Line Processor prompt Load the utility by executing the db2 command at the AIX prompt 1) First the local DB2 UDB for AIX instance needs to be enabled as a DB2 federated server

This is done by setting the database manager configuration parameter FEDERATED to YES

db2=gt update dbm cfg using FEDERATED YES

The database instance needs to be restarted for the change to take effect

NOTE A federated database is a regular database in a DB2 UDB instance that has the FEDERATED parameter enabled Therefore in this example the SAMPLE database that was created earlier is used as the federated database A new database can also be created using the CREATE DATABASE command

2) Connect to the federated database

db2=gt connect to sample

3) Use the CREATE WRAPPER statement to register a wrapper for the iSeries data source Wrappers are library routines that are used by the federated server to perform operations such as connecting to a data source and retrieving data from it The default wrapper name for DB2 UDB for iSeries is DRDA Here is the command to register the DRDA wrapper

db2=gt create wrapper drda

4) Use the CREATE SERVER statement to register a data source as a server within the federated database The server definition specifies the type and version of the data source and the wrapper used for communications with this data source For the DB2 UDB for iSeries data source the node and the database names are also needed The node and database name parameters have been configured for our TPLX database in the Configuration steps in the AIX partition section (on page 24) Use the following DB2 UDB command to lookup these parameter on the federated server

db2=gt list database directory

In this case the command produced the following output

Database alias = TPLX Database name = DCSE99E1 Node name = NDE9BF76 Database release level = a00 Comment = Directory entry type = Remote Authentication = SERVER Catalog database partition number = -1

36

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Note that the node name is set to NDE9BF76 The name was generated by the Configuration Administrator utility (db2ca)

Here is the command to register the TPLX database as a federated server

db2=gt create server tplx type db2400 version 530 wrapperdrda authorization db2user password mypassword options(nodeNDE9BF76 dbname TPLX)

The command is quite complex so make sure that the syntax is correct

5) Define the user mappings that instructs the federated server what user ID and password should be used when connecting to the iSeries data source

db2=gt create user mapping for user server tplxoptions(remote_authid db2user remote_password mypassword)

Specify the nickname for the iSeries table or view A nickname is an identifier that is used by the federated server to reference an object located at the data source The following command creates a nickname for the STAFF table located in the DB2USER schema on the TPLX database

db2=gt create nickname tplx_staff for tplxdb2userstaff

6) Test the distributed join query

db2=gt SELECT deptname name salary + COALESCE(comm0) ascompensation FROM org o tplx_staff s WHERE odeptnumb =sdept ORDER BY deptname compensation DESC

Note that the native iSeries function IFNULL has been substituted with an equivalent DB2 UDB function COALESCE COALESCE is also supported on iSeries servers For better portability IBM encourages the use of COALESCE rather than IFNULL Note also that the query runs on the federated server rather than on TPLX It accesses the ORG table in the local DB2 UDB for AIX SAMPLE database and the STAFF table that resides in TPLX The federated server performs the necessary distributed join

7) Modify the cursorsjsqc so that it executes a distributed join There are two source code modifications - Change the CONNECT TO statements Now the application needs to connect to the

federated database SAMPLE rather than to TPLX

EXEC SQL CONNECT TO SAMPLEEXEC SQL CONNECT TO SAMPLE USER userid USING passwd

- Modify the select statement so that it performs a distributed join Use the statement (shown in step 6) above Save the new source version as cursordjsqc

- Prepare bind and compile the distributed join version of the program as described in the Simple C embedded SQL application section (on page 34)

db2 prep cursordjsqc bindfiledb2 bind cursordjbndxlc -I$INSTHOMEsqllibinclude ndashc cursordjcxlc ndasho cursordj cursordjo -L$INSTHOMEsqlliblib ndashldb2

37

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

- Run the program from the AIX prompt

cursordj

Connection Pooling and Connection ConcentratorA modern Web-based application typically executes a large number of short-lived transactions Executing a transaction in this environment means establishing a database connection executing a few SQL statements and terminating this connection Creating connections to the database server is a very costly process To reduce the unnecessary workload DB2 Connect implements connection pooling and connection concentrator Connection pooling mechanism allows DB2 Connect to reuse an existing connection infrastructure for subsequent connection requests The connection concentrator is an advanced technology that allows DB2 Connect to serve a potentially very large number of clients with a limited number of database connections This is accomplished by decoupling clients from a particular database connection

Note that currently neither connection pooling nor connection concentrator support DB2 UDB for iSeries Therefore for performance reasons the author strongly recommends that the application server that obtains and drops connections very frequently implements its own database connection pooling mechanism that would assign an existing pooled database connection to a new AIX process or thread

TroubleshootingTroubleshooting a multi-tier application may be a bit tricky because the developer needs to deal with software components that reside in separate partitions The authorrsquos experience shows that two tools are particularly useful for pinning down the potential problem areas The joblog messages for a database server job usually provide enough details to isolate DB2

UDB for iSeries runtime issues The DRDA trace utility provides granular information about the data flow between the AIX

application and the iSeries server job

38

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Job Log MessagesAs mentioned earlier a DB2 client communicates with a corresponding iSeries server job This server job runs the SQL requests on behalf of the client More precisely when a DB2 client submits an SQL statement the statement is passed to a server job that in turn calls the DB2 runtime to execute the statement The results are then reformatted and marshaled to the client The iSeries DRDA server jobs are called QRWTSRVR and they run in the QUSRWRK subsystem At any given time there may be a large number of DRDA server jobs active on the system so the first step is to identify the job that serves the particular client connection The easiest method to accomplish this task is to run the following CL command from the i5OS prompt

WRKOBJLCK OBJ(DB2USER) OBJTYPE(USRPRF)

Here DB2USER is the user profile that is used to connect to the iSeries server Note that a QRWTSRVR job is assigned to a client after the connection has been established so the developer needs to set a breakpoint in the client application below the CONNECT TO statement

Once the Work with Object Locks appears key in 5 (Work with Job) next to the only QRWTSRVR job that should be listed This shows the Work with Job dialog Select option 10 to display the job log for the database server job Now the developer can search the job log for any error messages generated by the DB2 runtime

Sometimes it is also useful to include debug messages in the job log The debug messages are informational messages written to the job log about the implementation of a query They describe query implementation methods such as use of indexes join order ODP implementation (reusable versus non-reusable) and so on The easiest way to instruct the iSeries server to include the debug messages is to call the following stored procedure just after the connection to the iSeries server is established

EXEC SQL call qsysqcmdexc(STRDBGUPDPROD(YES)000000002000000)

A sample of the job log messages with debug messages enabled is shown below in Figure 20

Arrival sequence access was used for file STAFFAccess path suggestion for file STAFFQuery options used to build the OS400 query access plan Ending debug message for query ODP created Blocking used for queryCursor SQLCUR201 opened1 rows fetched from cursor SQLCUR201Row not found for SQLCUR201ODP deleted Cursor SQLCUR201 closedDESCRIBE of prepared statement STMT0201 completed

Figure 20 mdash Joblog with debug messages enabled

So the job log offers fairly detailed information on how the AIX client requests were implemented by the DB2 runtime

39

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 DRDA trace utilityThe DB2 DRDA trace utility (db2drdat) provides detailed information about the data streams exchanged between DB2 Connect and target database server The output file produced by the utility contains send and receive communications buffers TCPIP error messages and SQL Communications Area (SQLCA) information Please refer to lsquoDB2 Connect Userrsquos Guidersquo manual for in-depth discussion of the DRDA trace utility

Accessing DB2 UDB for iSeries from CLI DB2 Call Level Interface (CLI ) is based on the Microsoft Open Database Connectivity (ODBC) specification and the ISO CLI standard The DB2 CLI interface gained popularity among DB2 application providers because the developer can build an ODBC application by simply linking the application with libdb2 library on a UNIX server In other words the developer directly utilizes the DB2 ODBC driver services without a need for an ODBC driver manager Additionally in contrast to embedded SQL the developer does not need to precompile or bind DB2 CLI applications because they use packages provided with DB2 UDB The developer simply compiles and links the application

Prerequisites A DB2 CLI application running in an AIX partition will use DB2 Connect services to access DB2 UDB for iSeries therefore make sure that all components listed in Prerequisites section of this paper on page 24 are installed The developer also needs to create a remote database connection as described in the DB2 Connect configuration section of this paper on page 24

Dynamic SQL and Access Plan Caching A DB2 CLI client application uses the dynamic SQL interface and does not have the capability to utilize the extended dynamic SQL support Therefore it runs lsquopurersquo dynamic SQL statements That does not mean however that the process of parsing validating and optimizing will be repeated for every execution of a given dynamic SQL statement

The DB2 UDB for iSeries database implements an internal object called System-Wide SQL Statement Cache (SWSC) The SWSC can improve the performance of programs using dynamic SQL statements by caching the access plans in a system-wide cache When a dynamic SQL statement is submitted the SQL runtime searches the SWSC to see if this statement has been previously executed If so then DB2 retrieves and reuses the key information associated with the cached statement and thereby the processing time and the resources utilization can be significantly reduced

Simple DB2 CLI C++ ApplicationThis section covers DB2 CLI implementation details for a sample C++ program called testclicpp (the source is provided at the end of this paper in Appendix C) To compile the source with Visual C++ complier use the following command in the AIX partition

xlC ndashI$INSTHOMEsqllibinclude ndashc testclicppxlC ndasho testcli testclio ndashL$INSTHOMEsqlliblib ndashldb2

The application performs a join between STAFF and ORG tables located in DB2USER schema (library) The join statement retrieves the DEPTNAME column from ORG NAME and JOB columns from STAFF and calculates the total compensation for an employee by adding SALARY and COMM columns in STAFF The results are sorted by total compensation The selection criterion is based on the current value of the department name parameter Here is the SELECT statement used by testcli

40

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

select name job salary + coalesce(comm0) as compensationfrom org o staff swhere odeptnumb = sdeptand deptname = order by compensation desc

Figure 21 shows the software components involved in the execution of this sample application

Figure 21 How a DB2 CLI client accesses DB2 UDB on an iSeries server

Although the testcli application is fairly simple it covers some important aspects of efficient CLI programming for DB2 UDB for iSeries

Reusable Open Data Paths (ODPs)An Open Data Path (ODP) definition is an internal i5OS object that is created when certain SQL statements (such as OPEN INSERT UPDATE and DELETE) are executed for the first time in a given job (or connection) The ODP can be thought of as a runtime implementation of an access plan The access plan created at the optimization time provides a recipe or in other words a sequence of steps necessary to execute the statement The ODP on the other hand provides the executable code for all requested IO operations The process of creating new ODP objects is fairly CPU- and IO-intensive so whenever possible the iSeries DB2 runtime tries to reuse existing ODPs For instance a SQLCloseCursor() API call may close the SQL cursor but leave the ODP available to be used the next time the cursor is opened This can significantly reduce the processing and response time in running SQL statements A reusable OPD usually requires 10 to 20 times less CPU resources than a newly created ODP Therefore it is important that the applications employ programming techniques that allow the DB2 runtime to reuse ODPs

With dynamic interfaces such as CLI full opens are avoided by using a prepare once execute many programming paradigm It means that when an SQL statement is going to be executed more than once you should prepare the statement just once and then reuse the prepared

41

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

statements for consecutive executions Although DB2 UDB does try to convert literals to parameter markers so that similar statements can be reused it is a better programming practice to explicitly implement parameter markers That way the chances for reusable ODPs are quite significantly improved The code snippet in Figure 22 illustrates how to implement the prepare once execute many programming technique

Define A SELECT SQL Statementstrcpy((char ) SQLStmt select name job salary + ifnull(comm0) ascompensation )ptr = strcat( (char ) SQLStmt from org o staff s )ptr = strcat( (char ) SQLStmt where odeptnumb = sdept)ptr = strcat( (char ) SQLStmt and deptname = )ptr = strcat( (char ) SQLStmt order by compensation desc) [1]

Prepare The SQL Statementrc = SQLPrepare(ExampleStmtHandle SQLStmt SQL_NTS) [2]

Bind The Columns In The Result Data Set Returned To Application Variablesrc = SQLBindCol(ExampleStmtHandle 1 SQL_C_CHAR (SQLPOINTER)

ExampleName sizeof(ExampleName) NULL)rc = SQLBindCol(ExampleStmtHandle 2 SQL_C_CHAR (SQLPOINTER)

ExampleJob sizeof(ExampleJob) NULL)rc = SQLBindCol(ExampleStmtHandle 3 SQL_C_DOUBLE (SQLPOINTER)

ampExampleComp sizeof(ExampleComp) NULL)

for (int i = 0 i lt LOOPS i++)rc=SQLBindParameter(ExampleStmtHandle

1SQL_PARAM_INPUTSQL_C_CHARSQL_CHAR10(SQLPOINTER) currentDepartment[i8]0NULL) [3]

rc = SQLExecute(ExampleStmtHandle) [4]cout ltlt endl ltlt Current Dept ltlt currentDepartment[i8] ltlt endl Display The Results Of The SQL QueryExampleShowResults()

Figure 22 Use the prepare once execute many programming technique

The error-handling code has been removed for clarity At [1] the statement text is assigned to a variable Note that a parameter marker is used in the WHERE clause The statement is then prepared just once at [2] The current value of the parameter is bound to the prepared statement at [3] The prepared statement is executed at [4] Steps [3] and [4] are repeatedly executed in a for loop

Techniques to Further Improve DB2 CLI Performance Thus far this paper has discussed the techniques used by a sample application to tune the CLI performance However depending on the application architecture other methods of improving CLI performance may be considered

Connection PoolingCurrently the CLI application connecting through DB2 Connect to DB2 UDB for iSeries does not take advantage of the connection pooling mechanism implemented by DB2 Connect Therefore for performance reasons the author strongly recommends that the application server that obtains and drops connections very frequently implements its own database connection pooling mechanism that would assign an existing pooled database connection to a new AIX process or thread

42

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Blocking

For queries which result in returning large data blocks from the iSeries server (usually 32K of data and above) ensure that the database manager configuration parameter RQRIOBLK is set to 32767 This can be done using the Command Line Processor (CLP) as follows

db2 update database manager configuration using RQRIOBLK 32767

TroubleshootingThe experience of the author shows that two tools are particularly useful for pinning down the potential problem areas bull Joblog messages for a database server job usually provides enough details to isolate DB2

runtime issues bull CLI trace utility provides granular information about the data flow between the AIX application

and the database server job

Job Log MessagesThe process of finding and analyzing the job log for a DB2 CLI connection is identical to the process outlined for an embedded SQL application in the Job Log Message section of this paper on page 39

CLI Trace The DB2 CLIODBCJDBC trace utility provides very detailed information about the data streams exchanged between DB2 Connect and target database server Refer to the DB2 Information Center for more information on how to set up and analyze the CLI traces httppublibboulderibmcominfocenterdb2v8luwindexjsptopic=comibmdb2udbdocadc000 7959htm

43

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Trademarks

IBM eServer iSeries AIX AIX 5L i5OS WebSphere DB2 DB2 Universal Database DB2 Connect OS400 zOS OS390 Distributed Relational Database Architecture DRDA and DB2 Information Integration are trademarks or registered trademarks of International Business Machines Corporation in the United States and other countries

Java and all Java-based trademarks are trademarks of Sun Microsystems Inc in the United States other countries or both

Linux is a registered trademark of Linus Torvalds in the United States other countries or both

UNIX is a registered trademark of The Open Group in the United States and other countries

Microsoft and Windows are registered trademarks of Microsoft Corporation in the United States andor other countries

All other registered trademarks and trademarks are properties of their respective owners

IBM makes no commitment to make available any products referred to herein

References in this publication to IBM products or services do not imply that IBM intends to make them available in every country in which IBM operates

Additional Information ITSO offers a Redbook that can be helpful to those who want to learn more about i5OS AIX integration

bull AIX Integration with I5OS on the IBM eServer iSeries Server (SG24-6551)

Jarek Miszczyk is the Senior Software Engineer IBM eServer Solutions Enablement IBM Rochester

[Portions of this white paper reprinted with permission from MC Mag Online published by MC Press LLP httpwwwmcpressonlinecom]

Acknowledgments The author would like to thank the following people for their advice contributions and support on this paper

Bob Bittner IBM Rochester Jon Rush IBM Rochester Prasad Vallurupalli IBM Rochester Neil Willis IBM Rochester

44

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix A Source Listing of TestJDBCjava

package comibmiseriespwdimport javasqlimport javaxnamingimport javautilHashtableimport javautilimport javaxsqlimport comibmas400access

public class TestJDBC public static void main(javalangString[] args)

throws Exception

int numOfLoops = 5000int outerNumOfLoops = 5boolean firstExec = trueConnection conStatement sPreparedStatement psPreparedStatement pstmtdelCallableStatement cstmPreparedStatement pstmtHashtable env = new Hashtable()

envput(ContextINITIAL_CONTEXT_FACTORYcomsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env)Systemoutprintln(Deploying connection pooling data source)deployDataSource() Do the work with connection pooling onlyAS400JDBCConnectionPoolDataSource tkcpds =

(AS400JDBCConnectionPoolDataSource)ctxlookup(jdbcToolkitDataSource) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPool pool = new AS400JDBCConnectionPool(tkcpds) Adds 1 connection to the pool that can be used by theapplication (creates the physical database connections based onthe data source)poolfill(1)Systemoutprintln(nStart timing Toolkit connection pooling)long startTime = SystemcurrentTimeMillis()

for (int i = 0 i lt outerNumOfLoops i++) con = poolgetConnection()consetAutoCommit(false) deleteif ( i == 0)

long startDelete = SystemcurrentTimeMillis()cstm = cstm = conprepareCall(

CALL qsysqcmdexc(CLRPFM FILE(DB2USERCOFFEES) + 000000002800000))

cstmexecuteUpdate()cstmclose()long endDelete = SystemcurrentTimeMillis()Systemoutprintln(Delete all records +

(endDelete - startDelete) + ms elapsed)

45

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

String sqlinstrlong startInsert = SystemcurrentTimeMillis() insert

pstmt =conprepareStatement(INSERT INTO COFFEES VALUES( ))for (int j = 0 j lt numOfLoops j++) pstmtsetString(1 Kona_ + IntegertoString(i))pstmtsetInt(2 150)pstmtsetFloat(3 999f)pstmtsetInt(4 0)pstmtsetInt(5 0)pstmtaddBatch()int [] updateCounts = pstmtexecuteBatch()concommit()pstmtclose()long endInsert = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for + numOfLoops + inserts

+ (endInsert - startInsert)) selectlong startSelect = SystemcurrentTimeMillis()ps = conprepareStatement(SELECT FROM COFFEES)ResultSet rs = psexecuteQuery()rsnext()rsclose()concommit()psclose()long endSelect = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for select +

(endSelect - startSelect))consetAutoCommit(true)conclose()long endTime = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for + outerNumOfLoops +

loops + (endTime - startTime))Systemexit(0)

private static void deployDataSource()throws ExceptionString serverName = teraplex String databaseName = TERAPLEX String userName = db2user String password = db2pwd

Establish a JNDI context and bind the connection pool data sourceHashtable env = new Hashtable()envput(ContextINITIAL_CONTEXT_FACTORY

comsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPoolDataSource tkcpds = new

AS400JDBCConnectionPoolDataSource()tkcpdssetServerName(serverName) tkcpdssetDatabaseName(databaseName) tkcpdssetUser(userName) tkcpdssetPassword(password) tkcpdssetDescription(Toolkit Connection Pooling DataSource)tkcpdssetSavePasswordWhenSerialized(true)tkcpdssetExtendedDynamic(true)

46

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

tkcpdssetPackage(JDBCDS)tkcpdssetPackageCache(true)tkcpdssetPackageCriteria(select)enable the following properties as requiredcpdssetTrace(true)tkcpdssetServerTraceCategories( AS400JDBCDataSourceSERVER_TRACE_DEBUG_SERVER_JOB)

ctxrebind(jdbcToolkitDataSource tkcpds)

47

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix B mdash Source Listing of cursorsjsqc

Source File Name = cursorsjsqc Licensed Materials - Property of IBM (C) COPYRIGHT International Business Machines Corp 1995 2000 2004 All Rights Reserved US Government Users Restricted Rights - Use duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp PURPOSE This sample program demonstrates the use of a CURSOR The CURSOR is processed using static SQL EXTERNAL DEPENDENCIES - Ensure existence of database for precompile purposes - Precompile with the SQL precompiler (PREP in DB2) - Bind to a database (BIND in DB2) - Compile and link with the IBM Cset++ compiler (AIX and OS2) or the Microsoft Visual C++ compiler (Windows) or the compiler supported on your platform For more information about these samples see the README file For more information on programming in C see the - Programming in C and C++ section of the Application Development Guide For more information on building C applications see the - Building C Applications section of the Application Building Guide For more information on the SQL language see the SQL Reference

include ltstdiohgt include ltstdlibhgt include ltstringhgtinclude ltsqlhgtinclude ltsqlenvhgtinclude ltsqldahgtinclude ltsqlcahgt

int SqlInfoPrint( char struct sqlca int char )void TransRollback( void)

define EMB_SQL_CHECK( MSG_STR ) rc = SqlInfoPrint( MSG_STR ampsqlca __LINE__ __FILE__) if ( rc = 0 ) TransRollback( )

return 1

EXEC SQL INCLUDE SQLCA

int main(int argc char argv[])

EXEC SQL BEGIN DECLARE SECTIONchar dname[15]

48

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

char pname[10]double compchar userid[9]char passwd[19]

EXEC SQL END DECLARE SECTION

int rc = 0printf( Sample C program CURSORSJ n )if (argc == 1)

EXEC SQL CONNECT TO TPLXEMB_SQL_CHECK(CONNECT TO TPLX)

else if (argc == 3)

strcpy (userid argv[1])strcpy (passwd argv[2])EXEC SQL CONNECT TO TPLX USER userid USING passwdEMB_SQL_CHECK(CONNECT TO TPLX)

else

printf (nUSAGE cursor [userid passwd]nn)return 1

endif

EXEC SQL DECLARE c1 CURSOR FORselect deptname name salary + ifnull(comm0) as compensationfrom org o staff swhere odeptnumb = sdeptorder by deptname compensation desc

EXEC SQL OPEN c1EMB_SQL_CHECK(OPEN CURSOR)

printf(DEPARTMENT NAME COMPENSn)printf(-----------------------------------n)do

EXEC SQL FETCH c1 INTO dname pname compif (SQLCODE = 0) breakprintf( -1515s -1010s 72fn dname pname comp )

while ( 1 )

EXEC SQL CLOSE c1EMB_SQL_CHECK(CLOSE CURSOR)

EXEC SQL CONNECT RESETEMB_SQL_CHECK(CONNECT RESET)

exit(0)

end of program CURSORSJSQC

int SqlInfoPrint( char appMsgstruct sqlca pSqlcaint linechar file )

int rc = 0char sqlInfo[1024]char sqlInfoToken[1024]char sqlstateMsg[1024]char errorMsg[1024]

if (pSqlca-gtsqlcode = 0 ampamp pSqlca-gtsqlcode = 100)

49

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

strcpy(sqlInfo )if( pSqlca-gtsqlcode lt 0) sprintf( sqlInfoToken n---- error report ----n)

strcat( sqlInfo sqlInfoToken)else sprintf( sqlInfoToken n---- warning report ----n)

strcat( sqlInfo sqlInfoToken) endif

sprintf( sqlInfoToken app message = sn appMsg)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken line = dn line)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken file = sn file)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken SQLCODE = ldn pSqlca-gtsqlcode)strcat( sqlInfo sqlInfoToken)

get error message rc = sqlaintp( errorMsg 1024 80 pSqlca) return code is the length of the errorMsg string if( rc gt 0) sprintf( sqlInfoToken sn errorMsg)

strcat( sqlInfo sqlInfoToken)

get SQLSTATE message rc = sqlogstt( sqlstateMsg 1024 80 pSqlca-gtsqlstate)if (rc == 0) sprintf( sqlInfoToken sn sqlstateMsg)

strcat( sqlInfo sqlInfoToken)

if( pSqlca-gtsqlcode lt 0) sprintf( sqlInfoToken --- end error report ---n)

strcat( sqlInfo sqlInfoToken)printf(s sqlInfo)return 1

else sprintf( sqlInfoToken --- end warning report ---n)

strcat( sqlInfo sqlInfoToken)printf(s sqlInfo)return 0

endif endif

return 0

void TransRollback( ) struct sqlca sqlca

int rc = 0 rollback the transaction printf( nRolling back the transaction n)

EXEC SQL ROLLBACKrc = SqlInfoPrint( ROLLBACK ampsqlca __LINE__ __FILE__)if( rc == 0) printf( The transaction was rolled backn)

50

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

51

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix C mdash Source Listing of testclicpp

Include The Appropriate Header Filesinclude ltsqlclihgtinclude ltsqlcli1hgtinclude ltsqlutilhgtinclude ltsqlenvhgtinclude ltstdiohgt include ltiostreamgt include ltlocalehgt include ltstringhgtdefine SQL_SQLSTATE_SIZE 5define LOOPS 8

using namespace std

Define The CLI_Class Classclass CLI_Class

Attributespublic

SQLHANDLE EnvHandleSQLHANDLE ConHandleSQLHANDLE StmtHandleSQLRETURN rcSQLCHAR Job[6]SQLCHAR Name[10]SQLDOUBLE Comp

Operationspublic

CLI_Class()~CLI_Class()SQLRETURN ShowResults()

Constructor Destructor

SQLRETURN printError( SQLHDBC SQLHSTMT)

Define The Class ConstructorCLI_ClassCLI_Class()

setlocale( LC_ALL )

Initialize The Return Code Variablerc = SQL_SUCCESS

Allocate An Environment Handlerc = SQLAllocHandle(SQL_HANDLE_ENV SQL_NULL_HANDLE ampEnvHandle)

Allocate A Connection Handleif (rc == SQL_SUCCESS)

rc = SQLAllocHandle(SQL_HANDLE_DBC EnvHandle ampConHandle)

Define The Class DestructorCLI_Class~CLI_Class()

Free The Connection Handleif (ConHandle = NULL)

SQLFreeHandle(SQL_HANDLE_DBC ConHandle)

Free The Environment Handle

52

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

if (EnvHandle = NULL)SQLFreeHandle(SQL_HANDLE_ENV EnvHandle)

Define The ShowResults() Member FunctionSQLRETURN CLI_ClassShowResults(void)

While There Are Records In The Result Data Set Generated Retrieve And Display Themcout ltlt Name Job Compensation ltlt endlcout ltlt --------- ------ ------------ ltlt endlcoutsetf(iosleft)coutprecision(2)coutsetf(iosfixed)while (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)

rc = SQLFetch(StmtHandle)if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)

coutwidth(15)cout ltlt Name

coutwidth(10)cout ltlt Job

coutwidth(7)cout ltlt Comp ltltendl

if(rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO ampamp rc = SQL_NO_DATA)printError(ConHandle StmtHandle)

else

rc = 0SQLCloseCursor(StmtHandle)

Return The ODBC API Return Code To The Calling Functionreturn(rc)

SQLRETURN CLI_ClassprintError (SQLHDBC hdbc

SQLHSTMT hstmt)

SQLCHAR buffer[SQL_MAX_MESSAGE_LENGTH + 1]SQLCHAR sqlstate[SQL_SQLSTATE_SIZE + 1]SQLINTEGER sqlcodeSQLSMALLINT lengthSQLRETURN rcwhile ((rc = SQLError(SQL_NULL_HENV hdbc hstmt

sqlstateampsqlcodebufferSQL_MAX_MESSAGE_LENGTH + 1amplength)) == SQL_SUCCESS || rc ==

SQL_SUCCESS_WITH_INFO)

cout ltlt SQLSTATE ltlt sqlstate ltlt endlcout ltlt SQLCODE ltlt sqlcode ltlt endlcout ltlt Error msg ltlt buffer ltlt endl

53

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

cout ltlt----------------------------- ltlt endl ltlt endl

return(SQL_ERROR)

----------------------------------------------------------------- The Main Function -----------------------------------------------------------------int main()

Declare The Local Memory Variables

(SQLCHAR ) db2user SQL_NTS (SQLCHAR ) test26t SQL_NTS)

SQLRETURNSQLCHARSQLCHARSQLCHARchar

SQLCHAR

rc = SQL_SUCCESSDBName[10] = TPLXSQLStmt[255]c[10]ptrcurrentDepartment[8][15] = Head Office

New England Mid Atlantic South Atlantic Great Lakes PlainsPacificMountain

Create An Instance Of The CLI_Class ClassCLI_Class Example

Connect To iSeries Database if (ExampleConHandle = NULL)

rc = SQLConnect(ExampleConHandle DBName SQL_NTS

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)ExampleprintError(ExampleConHandle SQL_NULL_HSTMT)

return(rc)

cout ltlt Successfully connected to ltlt DBName ltlt ltlt endlrc = SQLSetConnectAttr(ExampleConHandle SQL_ATTR_AUTOCOMMIT

(SQLPOINTER) SQL_AUTOCOMMIT_OFF SQL_IS_UINTEGER) Allocate An SQL Statement Handlerc = SQLAllocHandle(SQL_HANDLE_STMT ExampleConHandle

ampExampleStmtHandle)if (rc == SQL_SUCCESS)

Define A SELECT SQL Statement

strcpy((char ) SQLStmt select name job salary + ifnull(comm0) ascompensation )

ptr = strcat( (char ) SQLStmt from org o staff s )ptr = strcat( (char ) SQLStmt where odeptnumb = sdept)ptr = strcat( (char ) SQLStmt and deptname = )ptr = strcat( (char ) SQLStmt order by compensation desc)

Prepare The SQL Statementrc = SQLPrepare(ExampleStmtHandle SQLStmt SQL_NTS)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)ExampleprintError(ExampleConHandle ExampleStmtHandle)

54

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

return(rc)

Bind The Columns In The Result Data Set Returned To Application Variables

rc = SQLBindCol(ExampleStmtHandle 1 SQL_C_CHAR (SQLPOINTER)ExampleName sizeof(ExampleName) NULL)

rc = SQLBindCol(ExampleStmtHandle 2 SQL_C_CHAR (SQLPOINTER)ExampleJob sizeof(ExampleJob) NULL)

rc = SQLBindCol(ExampleStmtHandle 3 SQL_C_DOUBLE (SQLPOINTER)ampExampleComp sizeof(ExampleComp) NULL)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO) ExampleprintError(ExampleConHandle ExampleStmtHandle)

return(rc)

while (true)

for (int i = 0 i lt LOOPS i++)

rc=SQLBindParameter(ExampleStmtHandle1SQL_PARAM_INPUTSQL_C_CHARSQL_CHAR

150(SQLPOINTER) currentDepartment[i8]0NULL)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)

ExampleprintError(ExampleConHandle ExampleStmtHandle)return(rc)

rc = SQLExecute(ExampleStmtHandle)if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)

ExampleprintError(ExampleConHandle ExampleStmtHandle)return(rc)

cout ltlt endl ltlt Current Dept ltlt currentDepartment[i8] ltlt

endl Display The Results Of The SQL QueryExampleShowResults()if(rc = 0)break

if ( i500 == 0 ampamp i gt 0 )cout ltlt Loops ltlt i ltlt ltlt endl

cout ltlt AFTER ltlt LOOPS ltlt loops Press X to exit ltlt endlcin gtgt cif (c[0] == x || c[0] == X)

break

Free The SQL Statement Handleif (ExampleStmtHandle = NULL )

SQLFreeHandle(SQL_HANDLE_STMT ExampleStmtHandle) Disconnect From The Northwind Sample Databaserc = SQLDisconnect(ExampleConHandle)

Return To The Operating Systemreturn(rc)

55

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

of information In V5R3 the IBM Toolbox for Java (as well as the latest JTOpen) added a comprehensive detailed trace facility The following is the complete list of detailed trace parameters and their purpose

bull None or ldquordquo ndash This setting disables the detailed trace bull datastream - This category is used by Toolbox classes to log dataflow between the local host

and the remote system It is not intended for use by application classes bull diagnostic - This category is used to log object state information bull error - This category is used to log errors that cause an exception bull information - This category is used to track the flow of control through the code bull warning - This category is used to log errors that are recoverable bull conversion - This category is used by Toolbox classes to log character set conversions

between Unicode and native code pages bull proxy - This category is used by Toolbox classes to log data flow between the client and the

proxy server bull pcml - This category is used to determine how PCML interprets the data that is sent to and

from the server bull jdbc - This category is used to track JDBC calls throughout the program bull thread - This category is used to enable tracing of thread information This is useful when

debugging multi-threaded applications bull all - This category will enable all previous categories

The detailed trace can be enabled when using the DriverManagergetConnection() method for obtaining a connection to DB2 UDB for iSeries In this case the developer could add the toolbox trace property to the connection string This is illustrated in the following code sample

String dbUrl = jdbcas400pwd1toolbox trace=diagnostic con = DriverManagergetConnection(dbUrl dbUser dbPassword)

Note that currently the driverrsquos DataSource interfaces do not allow the developer to directly activate the detailed tracing However they could set the server from the command line at the time the java program is launched The example below shows how the detailed trace properties could be enabled at the command line

java -Dcomibmas400accessTracecategory=diagnostic TestJDBC

The -D switch indicates to the java interpreter that the information following it will be a system property

In case of a WebSphere application the trace property can be set through the admin console In the console select Application Servers-gt server1-gt Process Definition -gt Java Virtual Machine Figure 9 shows how to set the Generic JVM Arguments for an application server instance

18

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 9 Setting JVM arguments to enable detailed Toolbox tracing

Database Monitor

The database monitor is the ultimate tool available on DB2 UDB for iSeries to collect low-level SQL traces It is mainly used to pin down the SQL performance problems Refer to the lsquoUsing iSeries Database Monitor to Identify and Tune SQL Queriesrsquo white paper for a detailed discussion on how to collect and analyze the database monitor traces httpibmcomserversenablesiteeducationiborecordhtmldtmon

IBM DB2 JDBC Universal Driver DB2 JDBC Universal Driver is one of the new features delivered with DB2 UDB Version 8 DB2 JDBC Universal Driver has been designed to eliminate the dependency on DB2 CLI runtime modules as well as to enable direct Type 4 connectivity to DB2 UDB for iSeries and DB2 UDB for zOSreg

The pure-Java (Type 4) remote connectivity is based on the DRDA open distributed protocol for cross-platform access to DB2 DRDA defines the rules the protocols and the semantics for accessing distributed data Applications can access data in a distributed relational environment by using SQL statements The iSeries DRDA application server implementation is based on multiple connection-oriented server jobs running in the QSYSWRK subsystem A DRDA listener job (QRWTLSTN) listens for TCP connect requests on port 446 Once an application requester connects to the listener job the listener wakes up one of the QRWTSRVR prestart jobs and assigns it to a given client connection Any further communication occurs directly between the client application and the QRWTSRVR job These concepts are illustrated in Figure 10

19

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 10 Accessing DB2 UDB for iSeries with DB2 Universal Driver

The DB2 Universal Driver can be loaded in an AIX partition by installing one of the DB2 Connect for AIX products (see the Additional Information section for details) It is also a part of a DB2 Enterprise Server Edition for AIX install Specifically the developer needs three JAR files in a AIX partition to successfully connect to an iSeries server db2jccjar db2jcc_license_cisuzjar and db2jcc_license_cujar The iSeries license is contained in db2jcc_license_cisuzjar Note that this file is not a part of DB2 Client In other words a DB2 Connect license is required to use the driver in production environments The location of the JAR files needs to be added to the CLASSPATH environment variable For instance the following entry could be added to the AIX profile script

CLASSPATH=homedb2inst2sqllibjavadb2jccjarCLASSPATH=$CLASSPATHhomedb2inst2sqllibjavadb2jcc_license_cujarCLASSPATH=$CLASSPATHhomedb2inst2sqllibjavadb2jcc_license_cisuzjarexport CLASSPATH

Java Runtime 131 is a prerequisite

Additionally the developer should install the latest database group PTF (SF99503 for i5OS V5R3) on the iSeries server The Informational APAR ii13348 is keeping track of any fixes relevant to DRDA above and beyond the current database group PTF

Obtaining a Connection to DB2 UDB for iSeries When Type 4 connectivity is used the DB2 Universal Driver connects directly to the DB2 on iSeries through TCPIP Note that this is different from the legacy DB2 Type 2 JDBC driver that requires a DB2 node and remote database configurations on the client accessing iSeries The following code snippet illustrates how to use the DB2 JDBC Universal Driver to obtain a connection to DB2 UDB for iSeries

20

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

try ClassforName(comibmdb2jccDB2Driver) [1] catch(javalangClassNotFoundException e) Systemerrprint(ClassNotFoundException )Systemerrprintln(egetMessage())

try DriverManagergetConnection(jdbcdb2teraplex446TERAPLEX[2]

db2userdb2pwd) hellip catch(SQLException ex) Systemerrprintln(

SQLException + exgetMessage())

At [1] an instance of the DB2 JDBC Universal Driver is instantiated Then at [2] the driver is used to obtain a connection to the iSeries server Note the proper form of the database URL required by the driver

Considerations There are several advantages of DB2 JDBC Universal Driver bull Ease of cross-platform development mdash Consistent coding techniques and consistent error

codes and messages bull Ease of deployment mdash Pure Java (no runtime client required) and a single driver for accessing

DB2 on different platforms

The ease of use comes at a price though The iSeries JTOpen driver is optimized for accessing DB2 UDB for iSeries data and it uses native iSeries protocol to communicate with the back-end database server job This usually results in better performance and more-efficient system resources utilization For instance when using the DB2 JDBC Universal Driver to access an iSeries server the executeBatch method results in a single record insert There are also some restrictions when using DB2 Universal JDBC Driver with Type 4 connectivity

bull Support for distributed transactions (JTA) is not enabled bull Driver built-in connection pooling is not supported

Refer to Java application support in DB2 for more details on DB2 JDBC Universal Driver

21

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 Connect data access This section will explore the most important aspects of DB2 Connect ndash iSeries integration - including configuration tips and coding examples

DB2 Connect provides functionality for accessing data stored in DB2 UDB for iSeries as well as DB2 UDB for zOS and DB2 UDB for OS390reg DB2 Connect offers capabilities to access DB2 family members via several SQL interfaces gateway functions such as connection pooling and federated database functionality Many applications supporting the DB2 family of products leverage DB2 Connect as a key middleware component DB2 Connect is offered as separate AIX license products

Enterprise Edition Application Server Edition

In addition to DB2 Connect there are several other DB2 UDB Version 81 products that are supported on AIX

DB2 Universal Database Enterprise Server Edition DB2 Universal Database Workgroup Server Unlimited Edition DB2 Universal Database Workgroup Server Edition DB2 Universal Database Universal Developers Edition All Clients

The DB2 Connect Enterprise Edition functionality is also contained in DB2 Enterprise Server Edition for AIX

22

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 Connect in a nutshell In the scenario described in this paper the DB2 Connect functions contained in DB2 Enterprise Edition for AIX are utilized DB2 Connect Enterprise Edition provides support for both local and remote DB2 clients This is illustrated in Figure 11 Accessing DB2 UDB for iSeries with DB2 Connect

Figure 11 Accessing DB2 UDB for iSeries with DB2 Connect

DB2 Connect implements the Distributed Relational Database Architecturetrade (DRDAreg) to reduce the cost and complexity of accessing data stored in DB2 UDB for iSeries and other DRDA-compliant database servers DRDA defines the rules the protocols and the semantics for accessing distributed data Applications can access data in a distributed relational environment by using SQL statements In a distributed environment the system running the application and sending the SQL requests across the network is called the application requester (AR) A remote database server that executes SQL requests submitted by an application requester is known as the application server (AS) In the example shown in Figure 11 (above) DB2 Connect plays the role of an application requester while DB2 UDB for iSeries is an application server In this case DB2 Connect communicates with the iSeries database through TCPIP The iSeries DRDA application server implementation is based on multiple connection-oriented server jobs running in the QSYSWRK subsystem A DRDA listener job (QRWTLSTN) listens for TCP connect requests on port 446 Once an application requester connects to the listener job the listener wakes up one of the QRWTSRVR prestart jobs and assigns it to a given client connection Any further communication occurs directly between the client application and the QRWTSRVR job

DB2 Connect supports a wide range of programming interfaces that can be used by AIX applications to access the iSeries database Embedded SQL frac34 Both static and dynamic SQL frac34 Various programming languages (Java CC++ Cobol Fortran REXX)

DB2 Call Level Interface (DB2 CLI) ODBC JDBC frac34 DB2 JDBC Type 2 Driver frac34 DB2 JDBC Type 4 Driver (Universal JDBC Driver)

23

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Note that DB2 Connect supports access to DB2 UDB for iSeries through DB2 JDBC Universal driver However for performance and ease of maintenance reasons IBM recommends that Java applications running in AIX use native iSeries Toolbox JDBC driver See the JDBC Data Access section of this paper (above) for more details On the other hand DB2 Connect is a very efficient and robust connectivity option for AIX applications especially in the environments that are not directly supported by the native iSeries JDBC driver Here are several possible scenarios that would require DB2 Connect installed in a AIX partition

Embedded SQL interface is used to access DB2 CLI or ODBC interface is used to access DB2 A single SQL interface is needed to access multiple back end DB2 server Specific DB2 Connect functionality is needed such as distributed join or connection

pooling

Prerequisites One of the DB2 Connect products or DB2 Enterprise Server Edition for AIX V81 is needed Additionally DB2 Application Development Client is required in the AIX partition to compile DB2 applications

For maximum database server stability the developer should install the latest database group PTF (SF99503 for i5OS V5R3) on the iSeries server The Informational APAR ii13348 is keeping track of any fixes relevant to DRDA above and beyond the current database group PTF

DB2 Connect configuration The following example employs i5OS V5R3 and DB2 UDB Enterprise Server Edition for AIX Version 81 FixPak 6

Configuration steps in the iSeries partition The following process lists the necessary steps to be performed on the iSeries server 1) Verify that the TCPIP stack is working correctly It is assumed that the Virtual LAN is used to

communicate with the i5OS partition First obtain the IP address of the iSeries server or its hostname and ping the iSeries server from the AIX partition

2) Create a relational database (RDB) entry for the iSeries database in the i5OS partition If this has already been created it can be displayed by using the DSPRDBDIRE command Make sure that the RDB entry with a location of LOCAL exists on the iSeries server If it does not exist use the ADDRDBDIRE command to add the appropriate RDB entry For example the following command would add an RDB entry named TPLX For simplicity it is recommended that the TCPIP host name and RDB entry remain the same

ADDRDBDIRE RDB(TPLX) RMTLOCNAME(LOCAL)

3) Create a collection called NULLID This is necessary because the utilities shipped with DB2 Connect and DB2 UDB for AIX store their packages in the NULLID collection Since it does not exist by default in the iSeries server you must create it using the following command

CRTLIB LIB(NULLID)

4) Products that support DRDA automatically perform any necessary code page conversions at the receiving system For this to happen both systems need a translation table from their code page to the partner code page The default Coded Character Set Identifier (CCSID) on the iSeries server is 65535 Since DB2 Connect does not have a translation table for this code page the developer needs to change the individual user profiles to contain a CCSID that can be converted properly by DB2 Connect For US English this is 037 For other languages see DB2 Connect Personal Edition Quick Beginning GC09-2967 The following command changes the CCSID for an individual user profile to 037

24

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

CHGUSRPRF userid CCSID(037)

5) Verify that the default port 446 for DRDA service is being used To do this go to the Configure TCPIP menu (CFGTCP) select Configure Related Tables and then select Work with service table entries Verify that the DRDA service is set for port 446

6) The Distributed Data Management (DDM) job must be started for DRDA to work If you want the DDM job to be automatically started whenever TCPIP is started change the attributes of the DDM job using the CHGDDMTCPA command and set the Autostart server parameter to YES

7) If the system administrator chooses not to autostart the server issue the following command to start the DDM server job

STRTCPSVR SERVER(DDM)

8) Make sure that the user profiles that will be used to connect to the iSeries server exist on the server

25

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Configuration steps in the AIX partition The following steps are required for DB2 Connect to be configured in the AIX partition 1) Sign on to the AIX partition as the DB2 administrator 2) Launch Client Configuration Assistant (db2ca from the command prompt) It is assumed that

VNC or an X-Windows server are being used on the workstation so that the db2ca GUI can be properly rendered

3) From the Selected pull-down menu select the Add Database using Wizard option The Select how you want to setup a connection dialog appears Select Manually configure a connection to a database and click Next This is shown in Figure 12

Figure 12 Accessing DB2 UDB for iSeries with DB2 Connect

26

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

4) On the Select a communications protocol choose TCPIP and select The database physical resides on a host or OS400 system Then select the option Connect directly to the server as shown in Figure 13 Click Next

Figure 13 mdash Selecting communications protocol

27

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

5) On the TCPIP tab fill in the host name of the iSeries server The port number should be 446 This is shown in Figure 14 Click Next

Figure 14 mdash Specifying TCPIP communication parameters

28

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

6) On the Database tab fill in the Relational Database name Use the RDB entry name (specified in step 2) in the Configuration steps in the iSeries partition section as shown in Figure 15 Click Next

Figure 15 mdash Specifying the remote database

7) If you plan to use the ODBC applications select Register this database for ODBC as a system data source on the ODBC tab Click Next

29

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

8) On the Specify the node option dialog select OS400 from the Operating System pull-down menu This is shown in Figure 16 Click Finish

Figure 16 mdash Specifying the node options

30

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

9) The Test Connection dialog appears This allows the developer to verify that the connection works Select both CLI and JDBC check boxes You are also prompted for an iSeries user ID and password as shown in Figure 17

Figure 17 mdash Testing the connection

31

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

10) The successful connection to the database server is confirmed by the message box shown in Figure 18

Figure 18 mdash Test Connection results 11) At this time a newly configured database connection should appear in the main DB2

Configuration Assistant window It is recommended that the DB2 utilities are also bound to the iSeries database The bind process creates the necessary SQL packages on the remote database In the main Configuration Assistant window click the TPLX database entry and then select Selected-gtBindhellip

32

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

12) The Bind dialog appears Click Select All and then enter the connection information as shown in Figure 19 Click Bind The Results message box appears This allows the developer to monitor the progress of the binding process Watch for any error and warning messages

Figure 19 mdash Binding the DB2 utilities This concludes the DB2 Connect configuration steps

33

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Accessing DB2 UDB for iSeries from C embedded SQL

As mentioned earlier DB2 Connect allows developers to compile and run embedded SQL applications that access DB2 UDB for iSeries data This section covers implementation details for a C embedded SQL application called cursorsjsqc (see Appendix B for source code)

Prerequisites An embedded SQL application running in an AIX partition will use DB2 Connect services to access DB2 UDB for iSeries therefore the developer needs to make sure that all components listed in section Prerequisites on page 24 are installed The developer also needs to create a remote database connection as described in the DB2 Connect configuration section of this paper on page 24

Static SQL and SQL packages To successfully run against a DB2 UDB for iSeries database an embedded SQL application needs to be first precompiled and bound to the back-end database This process creates an SQL package on the target iSeries server The SQL package contains the access plan information for the SQL statements executed by the application The internal structure of the package as well as the method how its content is used by the SQL runtime to facilitate the access plan reuse is similar to the Extended Dynamic SQL support covered in detail in the Extended Dynamic SQL and Statement Caching section of this paper (on page 9) There are however important differences between the packages created by the extended dynamic SQL support and the packages created for embedded SQL DRDA client applications The extended dynamic SQL packages support dynamic SQL interfaces such as JDBC

that can submit ad hoc SQL statements at the run time The SQL runtime can prepare the dynamic statements and add them to the package On the other hand the DRDA packages are created at the precompile time and contain static SQL In order to add new statements to the package the application needs to be precompiled and rebound again

The extended dynamic SQL package can dynamically grow up to 500MB by allocating new space as required The DRDA packages since they are created at the precompile time have a fix size and do not grow over their life time

Simple embedded SQL application The application is based on a source code provided in the DB2 UDB samples directory typically to be found at homedb2inst1sqllibsamples The cursorsjsqc performs a join between STAFF and ORG tables located in DB2USER schema (library) on the TPLX database server (the source is provided at the end of this paper in Appendix B) The join statement retrieves the DEPTNAME column from ORG NAME column from STAFF and calculates the total compensation for an employee by adding SALARY and COMM columns in STAFF The results are sorted by department name and total compensation Here is the SELECT statement used by the application

SELECT deptname name salary + IFNULL(comm0) as compensationFROM org o staff sWHERE odeptnumb = sdeptORDER BY deptname compensation DESC

The application iterates through the selected records and prints out the data to the standard output device The sample DB2USER schema was created with the following SQL statements

db2 CONNECT TO tplx USER db2user USING mypassworddb2 CALL QSYSCREATE_SQL_SAMPLE(DB2USER)

34

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Make sure that the AIX partition is logged into with the DB2 admin user profile If the defaults were selected at the DB2 installation time this profile name is db2inst1 It is also assumed that DB2USER user exists on the iSeries server and that it has appropriate authority

There are several steps that are required to create an executable for the cursorsjsqc source code First the DB2 PRECOMPILE utility needs to be called The utility creates a bind file that is used to bind the required SQL package to the TPLX database It also converts embedded SQL statements into DB2 run-time API calls and produces a pure C source file that can be processed by an AIX C compiler

db2 CONNECT TO tplx USER db2user USING mypassworddb2 prep cursorsjsqc bindfile

Note that the connect statement is required only if the developer is not already connected to the database on an iSeries server Watch for any error or warning messages returned by the DB2 prep utility The prepare step should produce cursorsjbnd and cursorsjc files in the current directory Now the developer can invoke the bind utility to prepare the statements contained in the bind file and create the package on the target iSeries database server

db2 bind cursorsjbnd

It is assumed that Visual C++ 60 is installed and configured in the AIX partition Refer to the ldquoDeveloping and Porting C and C++ Applications on AIXrdquo redbook for more information on how to use the Visual C++ compiler httpibmcomredbooksabstractssg245674htmlOpen

Use the following commands to compile the C source generated by the precompile utility

xlc -I$INSTHOMEsqllibinclude ndashc cursorsjcxlc ndasho cursorsj cursorsjo -L$INSTHOMEsqlliblib ndashldb2

Run the program from the AIX prompt

cursorsj db2user mypassword

Distributed Join DB2 UDB Version 8 provides core federated server functionality A federated system consists of a DB2 UDB instance that operates as a federated server a database that acts as the federated database one or more data sources and clients (users and applications) that access the database and data sources Federated server permits objects stored in multiple databases to be accessed together in the same query For example a query can refer to a table that resides in DB2 UDB for iSeries and join it to a table stored in DB2 UDB for AIX Such a query would constitute so called distributed join The support for DB2 UDB for iSeries as a federated data source is provided by core federated server functionality directly implemented in DB2 UDB Enterprise Server Edition and DB2 UDB Connect Enterprise Edition All other DB2 UDB family members are also supported directly by core DB2 UDB federated server An additional software product DB2 Information Integratortrade is required to access non-DB2 UDB databases such as Oracle Sybase or Microsoftreg SQL Server Consult the following white papers for a detailed discussion on DB2 federated server support Heterogeneous data access for iSeries applications Version 2 httpibmcomserversenablesiteeducationiborecordhtmlhetdata Fundamentals of IBM DB2 Federated Server and Relational Connect httpwww7bsoftwareibmcomdmddlibrarytecharticle0206purnell0206purnellhtml

35

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Distributed Join Example In this section the steps that are required to configure DB2 UDB for iSeries as a federated data source will be illustrated Then the cursorsjsqc program will be ldquotweakedrdquo so that it executes a distributed join query that accesses data stored on an iSeries server and in the local DB2 UDB for AIX database It is assumed that the developer is familiar with the DB2 federated server concepts

Note Run the following commands from the Command Line Processor prompt Load the utility by executing the db2 command at the AIX prompt 1) First the local DB2 UDB for AIX instance needs to be enabled as a DB2 federated server

This is done by setting the database manager configuration parameter FEDERATED to YES

db2=gt update dbm cfg using FEDERATED YES

The database instance needs to be restarted for the change to take effect

NOTE A federated database is a regular database in a DB2 UDB instance that has the FEDERATED parameter enabled Therefore in this example the SAMPLE database that was created earlier is used as the federated database A new database can also be created using the CREATE DATABASE command

2) Connect to the federated database

db2=gt connect to sample

3) Use the CREATE WRAPPER statement to register a wrapper for the iSeries data source Wrappers are library routines that are used by the federated server to perform operations such as connecting to a data source and retrieving data from it The default wrapper name for DB2 UDB for iSeries is DRDA Here is the command to register the DRDA wrapper

db2=gt create wrapper drda

4) Use the CREATE SERVER statement to register a data source as a server within the federated database The server definition specifies the type and version of the data source and the wrapper used for communications with this data source For the DB2 UDB for iSeries data source the node and the database names are also needed The node and database name parameters have been configured for our TPLX database in the Configuration steps in the AIX partition section (on page 24) Use the following DB2 UDB command to lookup these parameter on the federated server

db2=gt list database directory

In this case the command produced the following output

Database alias = TPLX Database name = DCSE99E1 Node name = NDE9BF76 Database release level = a00 Comment = Directory entry type = Remote Authentication = SERVER Catalog database partition number = -1

36

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Note that the node name is set to NDE9BF76 The name was generated by the Configuration Administrator utility (db2ca)

Here is the command to register the TPLX database as a federated server

db2=gt create server tplx type db2400 version 530 wrapperdrda authorization db2user password mypassword options(nodeNDE9BF76 dbname TPLX)

The command is quite complex so make sure that the syntax is correct

5) Define the user mappings that instructs the federated server what user ID and password should be used when connecting to the iSeries data source

db2=gt create user mapping for user server tplxoptions(remote_authid db2user remote_password mypassword)

Specify the nickname for the iSeries table or view A nickname is an identifier that is used by the federated server to reference an object located at the data source The following command creates a nickname for the STAFF table located in the DB2USER schema on the TPLX database

db2=gt create nickname tplx_staff for tplxdb2userstaff

6) Test the distributed join query

db2=gt SELECT deptname name salary + COALESCE(comm0) ascompensation FROM org o tplx_staff s WHERE odeptnumb =sdept ORDER BY deptname compensation DESC

Note that the native iSeries function IFNULL has been substituted with an equivalent DB2 UDB function COALESCE COALESCE is also supported on iSeries servers For better portability IBM encourages the use of COALESCE rather than IFNULL Note also that the query runs on the federated server rather than on TPLX It accesses the ORG table in the local DB2 UDB for AIX SAMPLE database and the STAFF table that resides in TPLX The federated server performs the necessary distributed join

7) Modify the cursorsjsqc so that it executes a distributed join There are two source code modifications - Change the CONNECT TO statements Now the application needs to connect to the

federated database SAMPLE rather than to TPLX

EXEC SQL CONNECT TO SAMPLEEXEC SQL CONNECT TO SAMPLE USER userid USING passwd

- Modify the select statement so that it performs a distributed join Use the statement (shown in step 6) above Save the new source version as cursordjsqc

- Prepare bind and compile the distributed join version of the program as described in the Simple C embedded SQL application section (on page 34)

db2 prep cursordjsqc bindfiledb2 bind cursordjbndxlc -I$INSTHOMEsqllibinclude ndashc cursordjcxlc ndasho cursordj cursordjo -L$INSTHOMEsqlliblib ndashldb2

37

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

- Run the program from the AIX prompt

cursordj

Connection Pooling and Connection ConcentratorA modern Web-based application typically executes a large number of short-lived transactions Executing a transaction in this environment means establishing a database connection executing a few SQL statements and terminating this connection Creating connections to the database server is a very costly process To reduce the unnecessary workload DB2 Connect implements connection pooling and connection concentrator Connection pooling mechanism allows DB2 Connect to reuse an existing connection infrastructure for subsequent connection requests The connection concentrator is an advanced technology that allows DB2 Connect to serve a potentially very large number of clients with a limited number of database connections This is accomplished by decoupling clients from a particular database connection

Note that currently neither connection pooling nor connection concentrator support DB2 UDB for iSeries Therefore for performance reasons the author strongly recommends that the application server that obtains and drops connections very frequently implements its own database connection pooling mechanism that would assign an existing pooled database connection to a new AIX process or thread

TroubleshootingTroubleshooting a multi-tier application may be a bit tricky because the developer needs to deal with software components that reside in separate partitions The authorrsquos experience shows that two tools are particularly useful for pinning down the potential problem areas The joblog messages for a database server job usually provide enough details to isolate DB2

UDB for iSeries runtime issues The DRDA trace utility provides granular information about the data flow between the AIX

application and the iSeries server job

38

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Job Log MessagesAs mentioned earlier a DB2 client communicates with a corresponding iSeries server job This server job runs the SQL requests on behalf of the client More precisely when a DB2 client submits an SQL statement the statement is passed to a server job that in turn calls the DB2 runtime to execute the statement The results are then reformatted and marshaled to the client The iSeries DRDA server jobs are called QRWTSRVR and they run in the QUSRWRK subsystem At any given time there may be a large number of DRDA server jobs active on the system so the first step is to identify the job that serves the particular client connection The easiest method to accomplish this task is to run the following CL command from the i5OS prompt

WRKOBJLCK OBJ(DB2USER) OBJTYPE(USRPRF)

Here DB2USER is the user profile that is used to connect to the iSeries server Note that a QRWTSRVR job is assigned to a client after the connection has been established so the developer needs to set a breakpoint in the client application below the CONNECT TO statement

Once the Work with Object Locks appears key in 5 (Work with Job) next to the only QRWTSRVR job that should be listed This shows the Work with Job dialog Select option 10 to display the job log for the database server job Now the developer can search the job log for any error messages generated by the DB2 runtime

Sometimes it is also useful to include debug messages in the job log The debug messages are informational messages written to the job log about the implementation of a query They describe query implementation methods such as use of indexes join order ODP implementation (reusable versus non-reusable) and so on The easiest way to instruct the iSeries server to include the debug messages is to call the following stored procedure just after the connection to the iSeries server is established

EXEC SQL call qsysqcmdexc(STRDBGUPDPROD(YES)000000002000000)

A sample of the job log messages with debug messages enabled is shown below in Figure 20

Arrival sequence access was used for file STAFFAccess path suggestion for file STAFFQuery options used to build the OS400 query access plan Ending debug message for query ODP created Blocking used for queryCursor SQLCUR201 opened1 rows fetched from cursor SQLCUR201Row not found for SQLCUR201ODP deleted Cursor SQLCUR201 closedDESCRIBE of prepared statement STMT0201 completed

Figure 20 mdash Joblog with debug messages enabled

So the job log offers fairly detailed information on how the AIX client requests were implemented by the DB2 runtime

39

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 DRDA trace utilityThe DB2 DRDA trace utility (db2drdat) provides detailed information about the data streams exchanged between DB2 Connect and target database server The output file produced by the utility contains send and receive communications buffers TCPIP error messages and SQL Communications Area (SQLCA) information Please refer to lsquoDB2 Connect Userrsquos Guidersquo manual for in-depth discussion of the DRDA trace utility

Accessing DB2 UDB for iSeries from CLI DB2 Call Level Interface (CLI ) is based on the Microsoft Open Database Connectivity (ODBC) specification and the ISO CLI standard The DB2 CLI interface gained popularity among DB2 application providers because the developer can build an ODBC application by simply linking the application with libdb2 library on a UNIX server In other words the developer directly utilizes the DB2 ODBC driver services without a need for an ODBC driver manager Additionally in contrast to embedded SQL the developer does not need to precompile or bind DB2 CLI applications because they use packages provided with DB2 UDB The developer simply compiles and links the application

Prerequisites A DB2 CLI application running in an AIX partition will use DB2 Connect services to access DB2 UDB for iSeries therefore make sure that all components listed in Prerequisites section of this paper on page 24 are installed The developer also needs to create a remote database connection as described in the DB2 Connect configuration section of this paper on page 24

Dynamic SQL and Access Plan Caching A DB2 CLI client application uses the dynamic SQL interface and does not have the capability to utilize the extended dynamic SQL support Therefore it runs lsquopurersquo dynamic SQL statements That does not mean however that the process of parsing validating and optimizing will be repeated for every execution of a given dynamic SQL statement

The DB2 UDB for iSeries database implements an internal object called System-Wide SQL Statement Cache (SWSC) The SWSC can improve the performance of programs using dynamic SQL statements by caching the access plans in a system-wide cache When a dynamic SQL statement is submitted the SQL runtime searches the SWSC to see if this statement has been previously executed If so then DB2 retrieves and reuses the key information associated with the cached statement and thereby the processing time and the resources utilization can be significantly reduced

Simple DB2 CLI C++ ApplicationThis section covers DB2 CLI implementation details for a sample C++ program called testclicpp (the source is provided at the end of this paper in Appendix C) To compile the source with Visual C++ complier use the following command in the AIX partition

xlC ndashI$INSTHOMEsqllibinclude ndashc testclicppxlC ndasho testcli testclio ndashL$INSTHOMEsqlliblib ndashldb2

The application performs a join between STAFF and ORG tables located in DB2USER schema (library) The join statement retrieves the DEPTNAME column from ORG NAME and JOB columns from STAFF and calculates the total compensation for an employee by adding SALARY and COMM columns in STAFF The results are sorted by total compensation The selection criterion is based on the current value of the department name parameter Here is the SELECT statement used by testcli

40

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

select name job salary + coalesce(comm0) as compensationfrom org o staff swhere odeptnumb = sdeptand deptname = order by compensation desc

Figure 21 shows the software components involved in the execution of this sample application

Figure 21 How a DB2 CLI client accesses DB2 UDB on an iSeries server

Although the testcli application is fairly simple it covers some important aspects of efficient CLI programming for DB2 UDB for iSeries

Reusable Open Data Paths (ODPs)An Open Data Path (ODP) definition is an internal i5OS object that is created when certain SQL statements (such as OPEN INSERT UPDATE and DELETE) are executed for the first time in a given job (or connection) The ODP can be thought of as a runtime implementation of an access plan The access plan created at the optimization time provides a recipe or in other words a sequence of steps necessary to execute the statement The ODP on the other hand provides the executable code for all requested IO operations The process of creating new ODP objects is fairly CPU- and IO-intensive so whenever possible the iSeries DB2 runtime tries to reuse existing ODPs For instance a SQLCloseCursor() API call may close the SQL cursor but leave the ODP available to be used the next time the cursor is opened This can significantly reduce the processing and response time in running SQL statements A reusable OPD usually requires 10 to 20 times less CPU resources than a newly created ODP Therefore it is important that the applications employ programming techniques that allow the DB2 runtime to reuse ODPs

With dynamic interfaces such as CLI full opens are avoided by using a prepare once execute many programming paradigm It means that when an SQL statement is going to be executed more than once you should prepare the statement just once and then reuse the prepared

41

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

statements for consecutive executions Although DB2 UDB does try to convert literals to parameter markers so that similar statements can be reused it is a better programming practice to explicitly implement parameter markers That way the chances for reusable ODPs are quite significantly improved The code snippet in Figure 22 illustrates how to implement the prepare once execute many programming technique

Define A SELECT SQL Statementstrcpy((char ) SQLStmt select name job salary + ifnull(comm0) ascompensation )ptr = strcat( (char ) SQLStmt from org o staff s )ptr = strcat( (char ) SQLStmt where odeptnumb = sdept)ptr = strcat( (char ) SQLStmt and deptname = )ptr = strcat( (char ) SQLStmt order by compensation desc) [1]

Prepare The SQL Statementrc = SQLPrepare(ExampleStmtHandle SQLStmt SQL_NTS) [2]

Bind The Columns In The Result Data Set Returned To Application Variablesrc = SQLBindCol(ExampleStmtHandle 1 SQL_C_CHAR (SQLPOINTER)

ExampleName sizeof(ExampleName) NULL)rc = SQLBindCol(ExampleStmtHandle 2 SQL_C_CHAR (SQLPOINTER)

ExampleJob sizeof(ExampleJob) NULL)rc = SQLBindCol(ExampleStmtHandle 3 SQL_C_DOUBLE (SQLPOINTER)

ampExampleComp sizeof(ExampleComp) NULL)

for (int i = 0 i lt LOOPS i++)rc=SQLBindParameter(ExampleStmtHandle

1SQL_PARAM_INPUTSQL_C_CHARSQL_CHAR10(SQLPOINTER) currentDepartment[i8]0NULL) [3]

rc = SQLExecute(ExampleStmtHandle) [4]cout ltlt endl ltlt Current Dept ltlt currentDepartment[i8] ltlt endl Display The Results Of The SQL QueryExampleShowResults()

Figure 22 Use the prepare once execute many programming technique

The error-handling code has been removed for clarity At [1] the statement text is assigned to a variable Note that a parameter marker is used in the WHERE clause The statement is then prepared just once at [2] The current value of the parameter is bound to the prepared statement at [3] The prepared statement is executed at [4] Steps [3] and [4] are repeatedly executed in a for loop

Techniques to Further Improve DB2 CLI Performance Thus far this paper has discussed the techniques used by a sample application to tune the CLI performance However depending on the application architecture other methods of improving CLI performance may be considered

Connection PoolingCurrently the CLI application connecting through DB2 Connect to DB2 UDB for iSeries does not take advantage of the connection pooling mechanism implemented by DB2 Connect Therefore for performance reasons the author strongly recommends that the application server that obtains and drops connections very frequently implements its own database connection pooling mechanism that would assign an existing pooled database connection to a new AIX process or thread

42

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Blocking

For queries which result in returning large data blocks from the iSeries server (usually 32K of data and above) ensure that the database manager configuration parameter RQRIOBLK is set to 32767 This can be done using the Command Line Processor (CLP) as follows

db2 update database manager configuration using RQRIOBLK 32767

TroubleshootingThe experience of the author shows that two tools are particularly useful for pinning down the potential problem areas bull Joblog messages for a database server job usually provides enough details to isolate DB2

runtime issues bull CLI trace utility provides granular information about the data flow between the AIX application

and the database server job

Job Log MessagesThe process of finding and analyzing the job log for a DB2 CLI connection is identical to the process outlined for an embedded SQL application in the Job Log Message section of this paper on page 39

CLI Trace The DB2 CLIODBCJDBC trace utility provides very detailed information about the data streams exchanged between DB2 Connect and target database server Refer to the DB2 Information Center for more information on how to set up and analyze the CLI traces httppublibboulderibmcominfocenterdb2v8luwindexjsptopic=comibmdb2udbdocadc000 7959htm

43

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Trademarks

IBM eServer iSeries AIX AIX 5L i5OS WebSphere DB2 DB2 Universal Database DB2 Connect OS400 zOS OS390 Distributed Relational Database Architecture DRDA and DB2 Information Integration are trademarks or registered trademarks of International Business Machines Corporation in the United States and other countries

Java and all Java-based trademarks are trademarks of Sun Microsystems Inc in the United States other countries or both

Linux is a registered trademark of Linus Torvalds in the United States other countries or both

UNIX is a registered trademark of The Open Group in the United States and other countries

Microsoft and Windows are registered trademarks of Microsoft Corporation in the United States andor other countries

All other registered trademarks and trademarks are properties of their respective owners

IBM makes no commitment to make available any products referred to herein

References in this publication to IBM products or services do not imply that IBM intends to make them available in every country in which IBM operates

Additional Information ITSO offers a Redbook that can be helpful to those who want to learn more about i5OS AIX integration

bull AIX Integration with I5OS on the IBM eServer iSeries Server (SG24-6551)

Jarek Miszczyk is the Senior Software Engineer IBM eServer Solutions Enablement IBM Rochester

[Portions of this white paper reprinted with permission from MC Mag Online published by MC Press LLP httpwwwmcpressonlinecom]

Acknowledgments The author would like to thank the following people for their advice contributions and support on this paper

Bob Bittner IBM Rochester Jon Rush IBM Rochester Prasad Vallurupalli IBM Rochester Neil Willis IBM Rochester

44

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix A Source Listing of TestJDBCjava

package comibmiseriespwdimport javasqlimport javaxnamingimport javautilHashtableimport javautilimport javaxsqlimport comibmas400access

public class TestJDBC public static void main(javalangString[] args)

throws Exception

int numOfLoops = 5000int outerNumOfLoops = 5boolean firstExec = trueConnection conStatement sPreparedStatement psPreparedStatement pstmtdelCallableStatement cstmPreparedStatement pstmtHashtable env = new Hashtable()

envput(ContextINITIAL_CONTEXT_FACTORYcomsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env)Systemoutprintln(Deploying connection pooling data source)deployDataSource() Do the work with connection pooling onlyAS400JDBCConnectionPoolDataSource tkcpds =

(AS400JDBCConnectionPoolDataSource)ctxlookup(jdbcToolkitDataSource) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPool pool = new AS400JDBCConnectionPool(tkcpds) Adds 1 connection to the pool that can be used by theapplication (creates the physical database connections based onthe data source)poolfill(1)Systemoutprintln(nStart timing Toolkit connection pooling)long startTime = SystemcurrentTimeMillis()

for (int i = 0 i lt outerNumOfLoops i++) con = poolgetConnection()consetAutoCommit(false) deleteif ( i == 0)

long startDelete = SystemcurrentTimeMillis()cstm = cstm = conprepareCall(

CALL qsysqcmdexc(CLRPFM FILE(DB2USERCOFFEES) + 000000002800000))

cstmexecuteUpdate()cstmclose()long endDelete = SystemcurrentTimeMillis()Systemoutprintln(Delete all records +

(endDelete - startDelete) + ms elapsed)

45

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

String sqlinstrlong startInsert = SystemcurrentTimeMillis() insert

pstmt =conprepareStatement(INSERT INTO COFFEES VALUES( ))for (int j = 0 j lt numOfLoops j++) pstmtsetString(1 Kona_ + IntegertoString(i))pstmtsetInt(2 150)pstmtsetFloat(3 999f)pstmtsetInt(4 0)pstmtsetInt(5 0)pstmtaddBatch()int [] updateCounts = pstmtexecuteBatch()concommit()pstmtclose()long endInsert = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for + numOfLoops + inserts

+ (endInsert - startInsert)) selectlong startSelect = SystemcurrentTimeMillis()ps = conprepareStatement(SELECT FROM COFFEES)ResultSet rs = psexecuteQuery()rsnext()rsclose()concommit()psclose()long endSelect = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for select +

(endSelect - startSelect))consetAutoCommit(true)conclose()long endTime = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for + outerNumOfLoops +

loops + (endTime - startTime))Systemexit(0)

private static void deployDataSource()throws ExceptionString serverName = teraplex String databaseName = TERAPLEX String userName = db2user String password = db2pwd

Establish a JNDI context and bind the connection pool data sourceHashtable env = new Hashtable()envput(ContextINITIAL_CONTEXT_FACTORY

comsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPoolDataSource tkcpds = new

AS400JDBCConnectionPoolDataSource()tkcpdssetServerName(serverName) tkcpdssetDatabaseName(databaseName) tkcpdssetUser(userName) tkcpdssetPassword(password) tkcpdssetDescription(Toolkit Connection Pooling DataSource)tkcpdssetSavePasswordWhenSerialized(true)tkcpdssetExtendedDynamic(true)

46

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

tkcpdssetPackage(JDBCDS)tkcpdssetPackageCache(true)tkcpdssetPackageCriteria(select)enable the following properties as requiredcpdssetTrace(true)tkcpdssetServerTraceCategories( AS400JDBCDataSourceSERVER_TRACE_DEBUG_SERVER_JOB)

ctxrebind(jdbcToolkitDataSource tkcpds)

47

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix B mdash Source Listing of cursorsjsqc

Source File Name = cursorsjsqc Licensed Materials - Property of IBM (C) COPYRIGHT International Business Machines Corp 1995 2000 2004 All Rights Reserved US Government Users Restricted Rights - Use duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp PURPOSE This sample program demonstrates the use of a CURSOR The CURSOR is processed using static SQL EXTERNAL DEPENDENCIES - Ensure existence of database for precompile purposes - Precompile with the SQL precompiler (PREP in DB2) - Bind to a database (BIND in DB2) - Compile and link with the IBM Cset++ compiler (AIX and OS2) or the Microsoft Visual C++ compiler (Windows) or the compiler supported on your platform For more information about these samples see the README file For more information on programming in C see the - Programming in C and C++ section of the Application Development Guide For more information on building C applications see the - Building C Applications section of the Application Building Guide For more information on the SQL language see the SQL Reference

include ltstdiohgt include ltstdlibhgt include ltstringhgtinclude ltsqlhgtinclude ltsqlenvhgtinclude ltsqldahgtinclude ltsqlcahgt

int SqlInfoPrint( char struct sqlca int char )void TransRollback( void)

define EMB_SQL_CHECK( MSG_STR ) rc = SqlInfoPrint( MSG_STR ampsqlca __LINE__ __FILE__) if ( rc = 0 ) TransRollback( )

return 1

EXEC SQL INCLUDE SQLCA

int main(int argc char argv[])

EXEC SQL BEGIN DECLARE SECTIONchar dname[15]

48

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

char pname[10]double compchar userid[9]char passwd[19]

EXEC SQL END DECLARE SECTION

int rc = 0printf( Sample C program CURSORSJ n )if (argc == 1)

EXEC SQL CONNECT TO TPLXEMB_SQL_CHECK(CONNECT TO TPLX)

else if (argc == 3)

strcpy (userid argv[1])strcpy (passwd argv[2])EXEC SQL CONNECT TO TPLX USER userid USING passwdEMB_SQL_CHECK(CONNECT TO TPLX)

else

printf (nUSAGE cursor [userid passwd]nn)return 1

endif

EXEC SQL DECLARE c1 CURSOR FORselect deptname name salary + ifnull(comm0) as compensationfrom org o staff swhere odeptnumb = sdeptorder by deptname compensation desc

EXEC SQL OPEN c1EMB_SQL_CHECK(OPEN CURSOR)

printf(DEPARTMENT NAME COMPENSn)printf(-----------------------------------n)do

EXEC SQL FETCH c1 INTO dname pname compif (SQLCODE = 0) breakprintf( -1515s -1010s 72fn dname pname comp )

while ( 1 )

EXEC SQL CLOSE c1EMB_SQL_CHECK(CLOSE CURSOR)

EXEC SQL CONNECT RESETEMB_SQL_CHECK(CONNECT RESET)

exit(0)

end of program CURSORSJSQC

int SqlInfoPrint( char appMsgstruct sqlca pSqlcaint linechar file )

int rc = 0char sqlInfo[1024]char sqlInfoToken[1024]char sqlstateMsg[1024]char errorMsg[1024]

if (pSqlca-gtsqlcode = 0 ampamp pSqlca-gtsqlcode = 100)

49

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

strcpy(sqlInfo )if( pSqlca-gtsqlcode lt 0) sprintf( sqlInfoToken n---- error report ----n)

strcat( sqlInfo sqlInfoToken)else sprintf( sqlInfoToken n---- warning report ----n)

strcat( sqlInfo sqlInfoToken) endif

sprintf( sqlInfoToken app message = sn appMsg)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken line = dn line)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken file = sn file)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken SQLCODE = ldn pSqlca-gtsqlcode)strcat( sqlInfo sqlInfoToken)

get error message rc = sqlaintp( errorMsg 1024 80 pSqlca) return code is the length of the errorMsg string if( rc gt 0) sprintf( sqlInfoToken sn errorMsg)

strcat( sqlInfo sqlInfoToken)

get SQLSTATE message rc = sqlogstt( sqlstateMsg 1024 80 pSqlca-gtsqlstate)if (rc == 0) sprintf( sqlInfoToken sn sqlstateMsg)

strcat( sqlInfo sqlInfoToken)

if( pSqlca-gtsqlcode lt 0) sprintf( sqlInfoToken --- end error report ---n)

strcat( sqlInfo sqlInfoToken)printf(s sqlInfo)return 1

else sprintf( sqlInfoToken --- end warning report ---n)

strcat( sqlInfo sqlInfoToken)printf(s sqlInfo)return 0

endif endif

return 0

void TransRollback( ) struct sqlca sqlca

int rc = 0 rollback the transaction printf( nRolling back the transaction n)

EXEC SQL ROLLBACKrc = SqlInfoPrint( ROLLBACK ampsqlca __LINE__ __FILE__)if( rc == 0) printf( The transaction was rolled backn)

50

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

51

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix C mdash Source Listing of testclicpp

Include The Appropriate Header Filesinclude ltsqlclihgtinclude ltsqlcli1hgtinclude ltsqlutilhgtinclude ltsqlenvhgtinclude ltstdiohgt include ltiostreamgt include ltlocalehgt include ltstringhgtdefine SQL_SQLSTATE_SIZE 5define LOOPS 8

using namespace std

Define The CLI_Class Classclass CLI_Class

Attributespublic

SQLHANDLE EnvHandleSQLHANDLE ConHandleSQLHANDLE StmtHandleSQLRETURN rcSQLCHAR Job[6]SQLCHAR Name[10]SQLDOUBLE Comp

Operationspublic

CLI_Class()~CLI_Class()SQLRETURN ShowResults()

Constructor Destructor

SQLRETURN printError( SQLHDBC SQLHSTMT)

Define The Class ConstructorCLI_ClassCLI_Class()

setlocale( LC_ALL )

Initialize The Return Code Variablerc = SQL_SUCCESS

Allocate An Environment Handlerc = SQLAllocHandle(SQL_HANDLE_ENV SQL_NULL_HANDLE ampEnvHandle)

Allocate A Connection Handleif (rc == SQL_SUCCESS)

rc = SQLAllocHandle(SQL_HANDLE_DBC EnvHandle ampConHandle)

Define The Class DestructorCLI_Class~CLI_Class()

Free The Connection Handleif (ConHandle = NULL)

SQLFreeHandle(SQL_HANDLE_DBC ConHandle)

Free The Environment Handle

52

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

if (EnvHandle = NULL)SQLFreeHandle(SQL_HANDLE_ENV EnvHandle)

Define The ShowResults() Member FunctionSQLRETURN CLI_ClassShowResults(void)

While There Are Records In The Result Data Set Generated Retrieve And Display Themcout ltlt Name Job Compensation ltlt endlcout ltlt --------- ------ ------------ ltlt endlcoutsetf(iosleft)coutprecision(2)coutsetf(iosfixed)while (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)

rc = SQLFetch(StmtHandle)if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)

coutwidth(15)cout ltlt Name

coutwidth(10)cout ltlt Job

coutwidth(7)cout ltlt Comp ltltendl

if(rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO ampamp rc = SQL_NO_DATA)printError(ConHandle StmtHandle)

else

rc = 0SQLCloseCursor(StmtHandle)

Return The ODBC API Return Code To The Calling Functionreturn(rc)

SQLRETURN CLI_ClassprintError (SQLHDBC hdbc

SQLHSTMT hstmt)

SQLCHAR buffer[SQL_MAX_MESSAGE_LENGTH + 1]SQLCHAR sqlstate[SQL_SQLSTATE_SIZE + 1]SQLINTEGER sqlcodeSQLSMALLINT lengthSQLRETURN rcwhile ((rc = SQLError(SQL_NULL_HENV hdbc hstmt

sqlstateampsqlcodebufferSQL_MAX_MESSAGE_LENGTH + 1amplength)) == SQL_SUCCESS || rc ==

SQL_SUCCESS_WITH_INFO)

cout ltlt SQLSTATE ltlt sqlstate ltlt endlcout ltlt SQLCODE ltlt sqlcode ltlt endlcout ltlt Error msg ltlt buffer ltlt endl

53

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

cout ltlt----------------------------- ltlt endl ltlt endl

return(SQL_ERROR)

----------------------------------------------------------------- The Main Function -----------------------------------------------------------------int main()

Declare The Local Memory Variables

(SQLCHAR ) db2user SQL_NTS (SQLCHAR ) test26t SQL_NTS)

SQLRETURNSQLCHARSQLCHARSQLCHARchar

SQLCHAR

rc = SQL_SUCCESSDBName[10] = TPLXSQLStmt[255]c[10]ptrcurrentDepartment[8][15] = Head Office

New England Mid Atlantic South Atlantic Great Lakes PlainsPacificMountain

Create An Instance Of The CLI_Class ClassCLI_Class Example

Connect To iSeries Database if (ExampleConHandle = NULL)

rc = SQLConnect(ExampleConHandle DBName SQL_NTS

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)ExampleprintError(ExampleConHandle SQL_NULL_HSTMT)

return(rc)

cout ltlt Successfully connected to ltlt DBName ltlt ltlt endlrc = SQLSetConnectAttr(ExampleConHandle SQL_ATTR_AUTOCOMMIT

(SQLPOINTER) SQL_AUTOCOMMIT_OFF SQL_IS_UINTEGER) Allocate An SQL Statement Handlerc = SQLAllocHandle(SQL_HANDLE_STMT ExampleConHandle

ampExampleStmtHandle)if (rc == SQL_SUCCESS)

Define A SELECT SQL Statement

strcpy((char ) SQLStmt select name job salary + ifnull(comm0) ascompensation )

ptr = strcat( (char ) SQLStmt from org o staff s )ptr = strcat( (char ) SQLStmt where odeptnumb = sdept)ptr = strcat( (char ) SQLStmt and deptname = )ptr = strcat( (char ) SQLStmt order by compensation desc)

Prepare The SQL Statementrc = SQLPrepare(ExampleStmtHandle SQLStmt SQL_NTS)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)ExampleprintError(ExampleConHandle ExampleStmtHandle)

54

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

return(rc)

Bind The Columns In The Result Data Set Returned To Application Variables

rc = SQLBindCol(ExampleStmtHandle 1 SQL_C_CHAR (SQLPOINTER)ExampleName sizeof(ExampleName) NULL)

rc = SQLBindCol(ExampleStmtHandle 2 SQL_C_CHAR (SQLPOINTER)ExampleJob sizeof(ExampleJob) NULL)

rc = SQLBindCol(ExampleStmtHandle 3 SQL_C_DOUBLE (SQLPOINTER)ampExampleComp sizeof(ExampleComp) NULL)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO) ExampleprintError(ExampleConHandle ExampleStmtHandle)

return(rc)

while (true)

for (int i = 0 i lt LOOPS i++)

rc=SQLBindParameter(ExampleStmtHandle1SQL_PARAM_INPUTSQL_C_CHARSQL_CHAR

150(SQLPOINTER) currentDepartment[i8]0NULL)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)

ExampleprintError(ExampleConHandle ExampleStmtHandle)return(rc)

rc = SQLExecute(ExampleStmtHandle)if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)

ExampleprintError(ExampleConHandle ExampleStmtHandle)return(rc)

cout ltlt endl ltlt Current Dept ltlt currentDepartment[i8] ltlt

endl Display The Results Of The SQL QueryExampleShowResults()if(rc = 0)break

if ( i500 == 0 ampamp i gt 0 )cout ltlt Loops ltlt i ltlt ltlt endl

cout ltlt AFTER ltlt LOOPS ltlt loops Press X to exit ltlt endlcin gtgt cif (c[0] == x || c[0] == X)

break

Free The SQL Statement Handleif (ExampleStmtHandle = NULL )

SQLFreeHandle(SQL_HANDLE_STMT ExampleStmtHandle) Disconnect From The Northwind Sample Databaserc = SQLDisconnect(ExampleConHandle)

Return To The Operating Systemreturn(rc)

55

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 9 Setting JVM arguments to enable detailed Toolbox tracing

Database Monitor

The database monitor is the ultimate tool available on DB2 UDB for iSeries to collect low-level SQL traces It is mainly used to pin down the SQL performance problems Refer to the lsquoUsing iSeries Database Monitor to Identify and Tune SQL Queriesrsquo white paper for a detailed discussion on how to collect and analyze the database monitor traces httpibmcomserversenablesiteeducationiborecordhtmldtmon

IBM DB2 JDBC Universal Driver DB2 JDBC Universal Driver is one of the new features delivered with DB2 UDB Version 8 DB2 JDBC Universal Driver has been designed to eliminate the dependency on DB2 CLI runtime modules as well as to enable direct Type 4 connectivity to DB2 UDB for iSeries and DB2 UDB for zOSreg

The pure-Java (Type 4) remote connectivity is based on the DRDA open distributed protocol for cross-platform access to DB2 DRDA defines the rules the protocols and the semantics for accessing distributed data Applications can access data in a distributed relational environment by using SQL statements The iSeries DRDA application server implementation is based on multiple connection-oriented server jobs running in the QSYSWRK subsystem A DRDA listener job (QRWTLSTN) listens for TCP connect requests on port 446 Once an application requester connects to the listener job the listener wakes up one of the QRWTSRVR prestart jobs and assigns it to a given client connection Any further communication occurs directly between the client application and the QRWTSRVR job These concepts are illustrated in Figure 10

19

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 10 Accessing DB2 UDB for iSeries with DB2 Universal Driver

The DB2 Universal Driver can be loaded in an AIX partition by installing one of the DB2 Connect for AIX products (see the Additional Information section for details) It is also a part of a DB2 Enterprise Server Edition for AIX install Specifically the developer needs three JAR files in a AIX partition to successfully connect to an iSeries server db2jccjar db2jcc_license_cisuzjar and db2jcc_license_cujar The iSeries license is contained in db2jcc_license_cisuzjar Note that this file is not a part of DB2 Client In other words a DB2 Connect license is required to use the driver in production environments The location of the JAR files needs to be added to the CLASSPATH environment variable For instance the following entry could be added to the AIX profile script

CLASSPATH=homedb2inst2sqllibjavadb2jccjarCLASSPATH=$CLASSPATHhomedb2inst2sqllibjavadb2jcc_license_cujarCLASSPATH=$CLASSPATHhomedb2inst2sqllibjavadb2jcc_license_cisuzjarexport CLASSPATH

Java Runtime 131 is a prerequisite

Additionally the developer should install the latest database group PTF (SF99503 for i5OS V5R3) on the iSeries server The Informational APAR ii13348 is keeping track of any fixes relevant to DRDA above and beyond the current database group PTF

Obtaining a Connection to DB2 UDB for iSeries When Type 4 connectivity is used the DB2 Universal Driver connects directly to the DB2 on iSeries through TCPIP Note that this is different from the legacy DB2 Type 2 JDBC driver that requires a DB2 node and remote database configurations on the client accessing iSeries The following code snippet illustrates how to use the DB2 JDBC Universal Driver to obtain a connection to DB2 UDB for iSeries

20

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

try ClassforName(comibmdb2jccDB2Driver) [1] catch(javalangClassNotFoundException e) Systemerrprint(ClassNotFoundException )Systemerrprintln(egetMessage())

try DriverManagergetConnection(jdbcdb2teraplex446TERAPLEX[2]

db2userdb2pwd) hellip catch(SQLException ex) Systemerrprintln(

SQLException + exgetMessage())

At [1] an instance of the DB2 JDBC Universal Driver is instantiated Then at [2] the driver is used to obtain a connection to the iSeries server Note the proper form of the database URL required by the driver

Considerations There are several advantages of DB2 JDBC Universal Driver bull Ease of cross-platform development mdash Consistent coding techniques and consistent error

codes and messages bull Ease of deployment mdash Pure Java (no runtime client required) and a single driver for accessing

DB2 on different platforms

The ease of use comes at a price though The iSeries JTOpen driver is optimized for accessing DB2 UDB for iSeries data and it uses native iSeries protocol to communicate with the back-end database server job This usually results in better performance and more-efficient system resources utilization For instance when using the DB2 JDBC Universal Driver to access an iSeries server the executeBatch method results in a single record insert There are also some restrictions when using DB2 Universal JDBC Driver with Type 4 connectivity

bull Support for distributed transactions (JTA) is not enabled bull Driver built-in connection pooling is not supported

Refer to Java application support in DB2 for more details on DB2 JDBC Universal Driver

21

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 Connect data access This section will explore the most important aspects of DB2 Connect ndash iSeries integration - including configuration tips and coding examples

DB2 Connect provides functionality for accessing data stored in DB2 UDB for iSeries as well as DB2 UDB for zOS and DB2 UDB for OS390reg DB2 Connect offers capabilities to access DB2 family members via several SQL interfaces gateway functions such as connection pooling and federated database functionality Many applications supporting the DB2 family of products leverage DB2 Connect as a key middleware component DB2 Connect is offered as separate AIX license products

Enterprise Edition Application Server Edition

In addition to DB2 Connect there are several other DB2 UDB Version 81 products that are supported on AIX

DB2 Universal Database Enterprise Server Edition DB2 Universal Database Workgroup Server Unlimited Edition DB2 Universal Database Workgroup Server Edition DB2 Universal Database Universal Developers Edition All Clients

The DB2 Connect Enterprise Edition functionality is also contained in DB2 Enterprise Server Edition for AIX

22

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 Connect in a nutshell In the scenario described in this paper the DB2 Connect functions contained in DB2 Enterprise Edition for AIX are utilized DB2 Connect Enterprise Edition provides support for both local and remote DB2 clients This is illustrated in Figure 11 Accessing DB2 UDB for iSeries with DB2 Connect

Figure 11 Accessing DB2 UDB for iSeries with DB2 Connect

DB2 Connect implements the Distributed Relational Database Architecturetrade (DRDAreg) to reduce the cost and complexity of accessing data stored in DB2 UDB for iSeries and other DRDA-compliant database servers DRDA defines the rules the protocols and the semantics for accessing distributed data Applications can access data in a distributed relational environment by using SQL statements In a distributed environment the system running the application and sending the SQL requests across the network is called the application requester (AR) A remote database server that executes SQL requests submitted by an application requester is known as the application server (AS) In the example shown in Figure 11 (above) DB2 Connect plays the role of an application requester while DB2 UDB for iSeries is an application server In this case DB2 Connect communicates with the iSeries database through TCPIP The iSeries DRDA application server implementation is based on multiple connection-oriented server jobs running in the QSYSWRK subsystem A DRDA listener job (QRWTLSTN) listens for TCP connect requests on port 446 Once an application requester connects to the listener job the listener wakes up one of the QRWTSRVR prestart jobs and assigns it to a given client connection Any further communication occurs directly between the client application and the QRWTSRVR job

DB2 Connect supports a wide range of programming interfaces that can be used by AIX applications to access the iSeries database Embedded SQL frac34 Both static and dynamic SQL frac34 Various programming languages (Java CC++ Cobol Fortran REXX)

DB2 Call Level Interface (DB2 CLI) ODBC JDBC frac34 DB2 JDBC Type 2 Driver frac34 DB2 JDBC Type 4 Driver (Universal JDBC Driver)

23

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Note that DB2 Connect supports access to DB2 UDB for iSeries through DB2 JDBC Universal driver However for performance and ease of maintenance reasons IBM recommends that Java applications running in AIX use native iSeries Toolbox JDBC driver See the JDBC Data Access section of this paper (above) for more details On the other hand DB2 Connect is a very efficient and robust connectivity option for AIX applications especially in the environments that are not directly supported by the native iSeries JDBC driver Here are several possible scenarios that would require DB2 Connect installed in a AIX partition

Embedded SQL interface is used to access DB2 CLI or ODBC interface is used to access DB2 A single SQL interface is needed to access multiple back end DB2 server Specific DB2 Connect functionality is needed such as distributed join or connection

pooling

Prerequisites One of the DB2 Connect products or DB2 Enterprise Server Edition for AIX V81 is needed Additionally DB2 Application Development Client is required in the AIX partition to compile DB2 applications

For maximum database server stability the developer should install the latest database group PTF (SF99503 for i5OS V5R3) on the iSeries server The Informational APAR ii13348 is keeping track of any fixes relevant to DRDA above and beyond the current database group PTF

DB2 Connect configuration The following example employs i5OS V5R3 and DB2 UDB Enterprise Server Edition for AIX Version 81 FixPak 6

Configuration steps in the iSeries partition The following process lists the necessary steps to be performed on the iSeries server 1) Verify that the TCPIP stack is working correctly It is assumed that the Virtual LAN is used to

communicate with the i5OS partition First obtain the IP address of the iSeries server or its hostname and ping the iSeries server from the AIX partition

2) Create a relational database (RDB) entry for the iSeries database in the i5OS partition If this has already been created it can be displayed by using the DSPRDBDIRE command Make sure that the RDB entry with a location of LOCAL exists on the iSeries server If it does not exist use the ADDRDBDIRE command to add the appropriate RDB entry For example the following command would add an RDB entry named TPLX For simplicity it is recommended that the TCPIP host name and RDB entry remain the same

ADDRDBDIRE RDB(TPLX) RMTLOCNAME(LOCAL)

3) Create a collection called NULLID This is necessary because the utilities shipped with DB2 Connect and DB2 UDB for AIX store their packages in the NULLID collection Since it does not exist by default in the iSeries server you must create it using the following command

CRTLIB LIB(NULLID)

4) Products that support DRDA automatically perform any necessary code page conversions at the receiving system For this to happen both systems need a translation table from their code page to the partner code page The default Coded Character Set Identifier (CCSID) on the iSeries server is 65535 Since DB2 Connect does not have a translation table for this code page the developer needs to change the individual user profiles to contain a CCSID that can be converted properly by DB2 Connect For US English this is 037 For other languages see DB2 Connect Personal Edition Quick Beginning GC09-2967 The following command changes the CCSID for an individual user profile to 037

24

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

CHGUSRPRF userid CCSID(037)

5) Verify that the default port 446 for DRDA service is being used To do this go to the Configure TCPIP menu (CFGTCP) select Configure Related Tables and then select Work with service table entries Verify that the DRDA service is set for port 446

6) The Distributed Data Management (DDM) job must be started for DRDA to work If you want the DDM job to be automatically started whenever TCPIP is started change the attributes of the DDM job using the CHGDDMTCPA command and set the Autostart server parameter to YES

7) If the system administrator chooses not to autostart the server issue the following command to start the DDM server job

STRTCPSVR SERVER(DDM)

8) Make sure that the user profiles that will be used to connect to the iSeries server exist on the server

25

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Configuration steps in the AIX partition The following steps are required for DB2 Connect to be configured in the AIX partition 1) Sign on to the AIX partition as the DB2 administrator 2) Launch Client Configuration Assistant (db2ca from the command prompt) It is assumed that

VNC or an X-Windows server are being used on the workstation so that the db2ca GUI can be properly rendered

3) From the Selected pull-down menu select the Add Database using Wizard option The Select how you want to setup a connection dialog appears Select Manually configure a connection to a database and click Next This is shown in Figure 12

Figure 12 Accessing DB2 UDB for iSeries with DB2 Connect

26

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

4) On the Select a communications protocol choose TCPIP and select The database physical resides on a host or OS400 system Then select the option Connect directly to the server as shown in Figure 13 Click Next

Figure 13 mdash Selecting communications protocol

27

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

5) On the TCPIP tab fill in the host name of the iSeries server The port number should be 446 This is shown in Figure 14 Click Next

Figure 14 mdash Specifying TCPIP communication parameters

28

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

6) On the Database tab fill in the Relational Database name Use the RDB entry name (specified in step 2) in the Configuration steps in the iSeries partition section as shown in Figure 15 Click Next

Figure 15 mdash Specifying the remote database

7) If you plan to use the ODBC applications select Register this database for ODBC as a system data source on the ODBC tab Click Next

29

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

8) On the Specify the node option dialog select OS400 from the Operating System pull-down menu This is shown in Figure 16 Click Finish

Figure 16 mdash Specifying the node options

30

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

9) The Test Connection dialog appears This allows the developer to verify that the connection works Select both CLI and JDBC check boxes You are also prompted for an iSeries user ID and password as shown in Figure 17

Figure 17 mdash Testing the connection

31

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

10) The successful connection to the database server is confirmed by the message box shown in Figure 18

Figure 18 mdash Test Connection results 11) At this time a newly configured database connection should appear in the main DB2

Configuration Assistant window It is recommended that the DB2 utilities are also bound to the iSeries database The bind process creates the necessary SQL packages on the remote database In the main Configuration Assistant window click the TPLX database entry and then select Selected-gtBindhellip

32

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

12) The Bind dialog appears Click Select All and then enter the connection information as shown in Figure 19 Click Bind The Results message box appears This allows the developer to monitor the progress of the binding process Watch for any error and warning messages

Figure 19 mdash Binding the DB2 utilities This concludes the DB2 Connect configuration steps

33

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Accessing DB2 UDB for iSeries from C embedded SQL

As mentioned earlier DB2 Connect allows developers to compile and run embedded SQL applications that access DB2 UDB for iSeries data This section covers implementation details for a C embedded SQL application called cursorsjsqc (see Appendix B for source code)

Prerequisites An embedded SQL application running in an AIX partition will use DB2 Connect services to access DB2 UDB for iSeries therefore the developer needs to make sure that all components listed in section Prerequisites on page 24 are installed The developer also needs to create a remote database connection as described in the DB2 Connect configuration section of this paper on page 24

Static SQL and SQL packages To successfully run against a DB2 UDB for iSeries database an embedded SQL application needs to be first precompiled and bound to the back-end database This process creates an SQL package on the target iSeries server The SQL package contains the access plan information for the SQL statements executed by the application The internal structure of the package as well as the method how its content is used by the SQL runtime to facilitate the access plan reuse is similar to the Extended Dynamic SQL support covered in detail in the Extended Dynamic SQL and Statement Caching section of this paper (on page 9) There are however important differences between the packages created by the extended dynamic SQL support and the packages created for embedded SQL DRDA client applications The extended dynamic SQL packages support dynamic SQL interfaces such as JDBC

that can submit ad hoc SQL statements at the run time The SQL runtime can prepare the dynamic statements and add them to the package On the other hand the DRDA packages are created at the precompile time and contain static SQL In order to add new statements to the package the application needs to be precompiled and rebound again

The extended dynamic SQL package can dynamically grow up to 500MB by allocating new space as required The DRDA packages since they are created at the precompile time have a fix size and do not grow over their life time

Simple embedded SQL application The application is based on a source code provided in the DB2 UDB samples directory typically to be found at homedb2inst1sqllibsamples The cursorsjsqc performs a join between STAFF and ORG tables located in DB2USER schema (library) on the TPLX database server (the source is provided at the end of this paper in Appendix B) The join statement retrieves the DEPTNAME column from ORG NAME column from STAFF and calculates the total compensation for an employee by adding SALARY and COMM columns in STAFF The results are sorted by department name and total compensation Here is the SELECT statement used by the application

SELECT deptname name salary + IFNULL(comm0) as compensationFROM org o staff sWHERE odeptnumb = sdeptORDER BY deptname compensation DESC

The application iterates through the selected records and prints out the data to the standard output device The sample DB2USER schema was created with the following SQL statements

db2 CONNECT TO tplx USER db2user USING mypassworddb2 CALL QSYSCREATE_SQL_SAMPLE(DB2USER)

34

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Make sure that the AIX partition is logged into with the DB2 admin user profile If the defaults were selected at the DB2 installation time this profile name is db2inst1 It is also assumed that DB2USER user exists on the iSeries server and that it has appropriate authority

There are several steps that are required to create an executable for the cursorsjsqc source code First the DB2 PRECOMPILE utility needs to be called The utility creates a bind file that is used to bind the required SQL package to the TPLX database It also converts embedded SQL statements into DB2 run-time API calls and produces a pure C source file that can be processed by an AIX C compiler

db2 CONNECT TO tplx USER db2user USING mypassworddb2 prep cursorsjsqc bindfile

Note that the connect statement is required only if the developer is not already connected to the database on an iSeries server Watch for any error or warning messages returned by the DB2 prep utility The prepare step should produce cursorsjbnd and cursorsjc files in the current directory Now the developer can invoke the bind utility to prepare the statements contained in the bind file and create the package on the target iSeries database server

db2 bind cursorsjbnd

It is assumed that Visual C++ 60 is installed and configured in the AIX partition Refer to the ldquoDeveloping and Porting C and C++ Applications on AIXrdquo redbook for more information on how to use the Visual C++ compiler httpibmcomredbooksabstractssg245674htmlOpen

Use the following commands to compile the C source generated by the precompile utility

xlc -I$INSTHOMEsqllibinclude ndashc cursorsjcxlc ndasho cursorsj cursorsjo -L$INSTHOMEsqlliblib ndashldb2

Run the program from the AIX prompt

cursorsj db2user mypassword

Distributed Join DB2 UDB Version 8 provides core federated server functionality A federated system consists of a DB2 UDB instance that operates as a federated server a database that acts as the federated database one or more data sources and clients (users and applications) that access the database and data sources Federated server permits objects stored in multiple databases to be accessed together in the same query For example a query can refer to a table that resides in DB2 UDB for iSeries and join it to a table stored in DB2 UDB for AIX Such a query would constitute so called distributed join The support for DB2 UDB for iSeries as a federated data source is provided by core federated server functionality directly implemented in DB2 UDB Enterprise Server Edition and DB2 UDB Connect Enterprise Edition All other DB2 UDB family members are also supported directly by core DB2 UDB federated server An additional software product DB2 Information Integratortrade is required to access non-DB2 UDB databases such as Oracle Sybase or Microsoftreg SQL Server Consult the following white papers for a detailed discussion on DB2 federated server support Heterogeneous data access for iSeries applications Version 2 httpibmcomserversenablesiteeducationiborecordhtmlhetdata Fundamentals of IBM DB2 Federated Server and Relational Connect httpwww7bsoftwareibmcomdmddlibrarytecharticle0206purnell0206purnellhtml

35

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Distributed Join Example In this section the steps that are required to configure DB2 UDB for iSeries as a federated data source will be illustrated Then the cursorsjsqc program will be ldquotweakedrdquo so that it executes a distributed join query that accesses data stored on an iSeries server and in the local DB2 UDB for AIX database It is assumed that the developer is familiar with the DB2 federated server concepts

Note Run the following commands from the Command Line Processor prompt Load the utility by executing the db2 command at the AIX prompt 1) First the local DB2 UDB for AIX instance needs to be enabled as a DB2 federated server

This is done by setting the database manager configuration parameter FEDERATED to YES

db2=gt update dbm cfg using FEDERATED YES

The database instance needs to be restarted for the change to take effect

NOTE A federated database is a regular database in a DB2 UDB instance that has the FEDERATED parameter enabled Therefore in this example the SAMPLE database that was created earlier is used as the federated database A new database can also be created using the CREATE DATABASE command

2) Connect to the federated database

db2=gt connect to sample

3) Use the CREATE WRAPPER statement to register a wrapper for the iSeries data source Wrappers are library routines that are used by the federated server to perform operations such as connecting to a data source and retrieving data from it The default wrapper name for DB2 UDB for iSeries is DRDA Here is the command to register the DRDA wrapper

db2=gt create wrapper drda

4) Use the CREATE SERVER statement to register a data source as a server within the federated database The server definition specifies the type and version of the data source and the wrapper used for communications with this data source For the DB2 UDB for iSeries data source the node and the database names are also needed The node and database name parameters have been configured for our TPLX database in the Configuration steps in the AIX partition section (on page 24) Use the following DB2 UDB command to lookup these parameter on the federated server

db2=gt list database directory

In this case the command produced the following output

Database alias = TPLX Database name = DCSE99E1 Node name = NDE9BF76 Database release level = a00 Comment = Directory entry type = Remote Authentication = SERVER Catalog database partition number = -1

36

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Note that the node name is set to NDE9BF76 The name was generated by the Configuration Administrator utility (db2ca)

Here is the command to register the TPLX database as a federated server

db2=gt create server tplx type db2400 version 530 wrapperdrda authorization db2user password mypassword options(nodeNDE9BF76 dbname TPLX)

The command is quite complex so make sure that the syntax is correct

5) Define the user mappings that instructs the federated server what user ID and password should be used when connecting to the iSeries data source

db2=gt create user mapping for user server tplxoptions(remote_authid db2user remote_password mypassword)

Specify the nickname for the iSeries table or view A nickname is an identifier that is used by the federated server to reference an object located at the data source The following command creates a nickname for the STAFF table located in the DB2USER schema on the TPLX database

db2=gt create nickname tplx_staff for tplxdb2userstaff

6) Test the distributed join query

db2=gt SELECT deptname name salary + COALESCE(comm0) ascompensation FROM org o tplx_staff s WHERE odeptnumb =sdept ORDER BY deptname compensation DESC

Note that the native iSeries function IFNULL has been substituted with an equivalent DB2 UDB function COALESCE COALESCE is also supported on iSeries servers For better portability IBM encourages the use of COALESCE rather than IFNULL Note also that the query runs on the federated server rather than on TPLX It accesses the ORG table in the local DB2 UDB for AIX SAMPLE database and the STAFF table that resides in TPLX The federated server performs the necessary distributed join

7) Modify the cursorsjsqc so that it executes a distributed join There are two source code modifications - Change the CONNECT TO statements Now the application needs to connect to the

federated database SAMPLE rather than to TPLX

EXEC SQL CONNECT TO SAMPLEEXEC SQL CONNECT TO SAMPLE USER userid USING passwd

- Modify the select statement so that it performs a distributed join Use the statement (shown in step 6) above Save the new source version as cursordjsqc

- Prepare bind and compile the distributed join version of the program as described in the Simple C embedded SQL application section (on page 34)

db2 prep cursordjsqc bindfiledb2 bind cursordjbndxlc -I$INSTHOMEsqllibinclude ndashc cursordjcxlc ndasho cursordj cursordjo -L$INSTHOMEsqlliblib ndashldb2

37

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

- Run the program from the AIX prompt

cursordj

Connection Pooling and Connection ConcentratorA modern Web-based application typically executes a large number of short-lived transactions Executing a transaction in this environment means establishing a database connection executing a few SQL statements and terminating this connection Creating connections to the database server is a very costly process To reduce the unnecessary workload DB2 Connect implements connection pooling and connection concentrator Connection pooling mechanism allows DB2 Connect to reuse an existing connection infrastructure for subsequent connection requests The connection concentrator is an advanced technology that allows DB2 Connect to serve a potentially very large number of clients with a limited number of database connections This is accomplished by decoupling clients from a particular database connection

Note that currently neither connection pooling nor connection concentrator support DB2 UDB for iSeries Therefore for performance reasons the author strongly recommends that the application server that obtains and drops connections very frequently implements its own database connection pooling mechanism that would assign an existing pooled database connection to a new AIX process or thread

TroubleshootingTroubleshooting a multi-tier application may be a bit tricky because the developer needs to deal with software components that reside in separate partitions The authorrsquos experience shows that two tools are particularly useful for pinning down the potential problem areas The joblog messages for a database server job usually provide enough details to isolate DB2

UDB for iSeries runtime issues The DRDA trace utility provides granular information about the data flow between the AIX

application and the iSeries server job

38

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Job Log MessagesAs mentioned earlier a DB2 client communicates with a corresponding iSeries server job This server job runs the SQL requests on behalf of the client More precisely when a DB2 client submits an SQL statement the statement is passed to a server job that in turn calls the DB2 runtime to execute the statement The results are then reformatted and marshaled to the client The iSeries DRDA server jobs are called QRWTSRVR and they run in the QUSRWRK subsystem At any given time there may be a large number of DRDA server jobs active on the system so the first step is to identify the job that serves the particular client connection The easiest method to accomplish this task is to run the following CL command from the i5OS prompt

WRKOBJLCK OBJ(DB2USER) OBJTYPE(USRPRF)

Here DB2USER is the user profile that is used to connect to the iSeries server Note that a QRWTSRVR job is assigned to a client after the connection has been established so the developer needs to set a breakpoint in the client application below the CONNECT TO statement

Once the Work with Object Locks appears key in 5 (Work with Job) next to the only QRWTSRVR job that should be listed This shows the Work with Job dialog Select option 10 to display the job log for the database server job Now the developer can search the job log for any error messages generated by the DB2 runtime

Sometimes it is also useful to include debug messages in the job log The debug messages are informational messages written to the job log about the implementation of a query They describe query implementation methods such as use of indexes join order ODP implementation (reusable versus non-reusable) and so on The easiest way to instruct the iSeries server to include the debug messages is to call the following stored procedure just after the connection to the iSeries server is established

EXEC SQL call qsysqcmdexc(STRDBGUPDPROD(YES)000000002000000)

A sample of the job log messages with debug messages enabled is shown below in Figure 20

Arrival sequence access was used for file STAFFAccess path suggestion for file STAFFQuery options used to build the OS400 query access plan Ending debug message for query ODP created Blocking used for queryCursor SQLCUR201 opened1 rows fetched from cursor SQLCUR201Row not found for SQLCUR201ODP deleted Cursor SQLCUR201 closedDESCRIBE of prepared statement STMT0201 completed

Figure 20 mdash Joblog with debug messages enabled

So the job log offers fairly detailed information on how the AIX client requests were implemented by the DB2 runtime

39

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 DRDA trace utilityThe DB2 DRDA trace utility (db2drdat) provides detailed information about the data streams exchanged between DB2 Connect and target database server The output file produced by the utility contains send and receive communications buffers TCPIP error messages and SQL Communications Area (SQLCA) information Please refer to lsquoDB2 Connect Userrsquos Guidersquo manual for in-depth discussion of the DRDA trace utility

Accessing DB2 UDB for iSeries from CLI DB2 Call Level Interface (CLI ) is based on the Microsoft Open Database Connectivity (ODBC) specification and the ISO CLI standard The DB2 CLI interface gained popularity among DB2 application providers because the developer can build an ODBC application by simply linking the application with libdb2 library on a UNIX server In other words the developer directly utilizes the DB2 ODBC driver services without a need for an ODBC driver manager Additionally in contrast to embedded SQL the developer does not need to precompile or bind DB2 CLI applications because they use packages provided with DB2 UDB The developer simply compiles and links the application

Prerequisites A DB2 CLI application running in an AIX partition will use DB2 Connect services to access DB2 UDB for iSeries therefore make sure that all components listed in Prerequisites section of this paper on page 24 are installed The developer also needs to create a remote database connection as described in the DB2 Connect configuration section of this paper on page 24

Dynamic SQL and Access Plan Caching A DB2 CLI client application uses the dynamic SQL interface and does not have the capability to utilize the extended dynamic SQL support Therefore it runs lsquopurersquo dynamic SQL statements That does not mean however that the process of parsing validating and optimizing will be repeated for every execution of a given dynamic SQL statement

The DB2 UDB for iSeries database implements an internal object called System-Wide SQL Statement Cache (SWSC) The SWSC can improve the performance of programs using dynamic SQL statements by caching the access plans in a system-wide cache When a dynamic SQL statement is submitted the SQL runtime searches the SWSC to see if this statement has been previously executed If so then DB2 retrieves and reuses the key information associated with the cached statement and thereby the processing time and the resources utilization can be significantly reduced

Simple DB2 CLI C++ ApplicationThis section covers DB2 CLI implementation details for a sample C++ program called testclicpp (the source is provided at the end of this paper in Appendix C) To compile the source with Visual C++ complier use the following command in the AIX partition

xlC ndashI$INSTHOMEsqllibinclude ndashc testclicppxlC ndasho testcli testclio ndashL$INSTHOMEsqlliblib ndashldb2

The application performs a join between STAFF and ORG tables located in DB2USER schema (library) The join statement retrieves the DEPTNAME column from ORG NAME and JOB columns from STAFF and calculates the total compensation for an employee by adding SALARY and COMM columns in STAFF The results are sorted by total compensation The selection criterion is based on the current value of the department name parameter Here is the SELECT statement used by testcli

40

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

select name job salary + coalesce(comm0) as compensationfrom org o staff swhere odeptnumb = sdeptand deptname = order by compensation desc

Figure 21 shows the software components involved in the execution of this sample application

Figure 21 How a DB2 CLI client accesses DB2 UDB on an iSeries server

Although the testcli application is fairly simple it covers some important aspects of efficient CLI programming for DB2 UDB for iSeries

Reusable Open Data Paths (ODPs)An Open Data Path (ODP) definition is an internal i5OS object that is created when certain SQL statements (such as OPEN INSERT UPDATE and DELETE) are executed for the first time in a given job (or connection) The ODP can be thought of as a runtime implementation of an access plan The access plan created at the optimization time provides a recipe or in other words a sequence of steps necessary to execute the statement The ODP on the other hand provides the executable code for all requested IO operations The process of creating new ODP objects is fairly CPU- and IO-intensive so whenever possible the iSeries DB2 runtime tries to reuse existing ODPs For instance a SQLCloseCursor() API call may close the SQL cursor but leave the ODP available to be used the next time the cursor is opened This can significantly reduce the processing and response time in running SQL statements A reusable OPD usually requires 10 to 20 times less CPU resources than a newly created ODP Therefore it is important that the applications employ programming techniques that allow the DB2 runtime to reuse ODPs

With dynamic interfaces such as CLI full opens are avoided by using a prepare once execute many programming paradigm It means that when an SQL statement is going to be executed more than once you should prepare the statement just once and then reuse the prepared

41

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

statements for consecutive executions Although DB2 UDB does try to convert literals to parameter markers so that similar statements can be reused it is a better programming practice to explicitly implement parameter markers That way the chances for reusable ODPs are quite significantly improved The code snippet in Figure 22 illustrates how to implement the prepare once execute many programming technique

Define A SELECT SQL Statementstrcpy((char ) SQLStmt select name job salary + ifnull(comm0) ascompensation )ptr = strcat( (char ) SQLStmt from org o staff s )ptr = strcat( (char ) SQLStmt where odeptnumb = sdept)ptr = strcat( (char ) SQLStmt and deptname = )ptr = strcat( (char ) SQLStmt order by compensation desc) [1]

Prepare The SQL Statementrc = SQLPrepare(ExampleStmtHandle SQLStmt SQL_NTS) [2]

Bind The Columns In The Result Data Set Returned To Application Variablesrc = SQLBindCol(ExampleStmtHandle 1 SQL_C_CHAR (SQLPOINTER)

ExampleName sizeof(ExampleName) NULL)rc = SQLBindCol(ExampleStmtHandle 2 SQL_C_CHAR (SQLPOINTER)

ExampleJob sizeof(ExampleJob) NULL)rc = SQLBindCol(ExampleStmtHandle 3 SQL_C_DOUBLE (SQLPOINTER)

ampExampleComp sizeof(ExampleComp) NULL)

for (int i = 0 i lt LOOPS i++)rc=SQLBindParameter(ExampleStmtHandle

1SQL_PARAM_INPUTSQL_C_CHARSQL_CHAR10(SQLPOINTER) currentDepartment[i8]0NULL) [3]

rc = SQLExecute(ExampleStmtHandle) [4]cout ltlt endl ltlt Current Dept ltlt currentDepartment[i8] ltlt endl Display The Results Of The SQL QueryExampleShowResults()

Figure 22 Use the prepare once execute many programming technique

The error-handling code has been removed for clarity At [1] the statement text is assigned to a variable Note that a parameter marker is used in the WHERE clause The statement is then prepared just once at [2] The current value of the parameter is bound to the prepared statement at [3] The prepared statement is executed at [4] Steps [3] and [4] are repeatedly executed in a for loop

Techniques to Further Improve DB2 CLI Performance Thus far this paper has discussed the techniques used by a sample application to tune the CLI performance However depending on the application architecture other methods of improving CLI performance may be considered

Connection PoolingCurrently the CLI application connecting through DB2 Connect to DB2 UDB for iSeries does not take advantage of the connection pooling mechanism implemented by DB2 Connect Therefore for performance reasons the author strongly recommends that the application server that obtains and drops connections very frequently implements its own database connection pooling mechanism that would assign an existing pooled database connection to a new AIX process or thread

42

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Blocking

For queries which result in returning large data blocks from the iSeries server (usually 32K of data and above) ensure that the database manager configuration parameter RQRIOBLK is set to 32767 This can be done using the Command Line Processor (CLP) as follows

db2 update database manager configuration using RQRIOBLK 32767

TroubleshootingThe experience of the author shows that two tools are particularly useful for pinning down the potential problem areas bull Joblog messages for a database server job usually provides enough details to isolate DB2

runtime issues bull CLI trace utility provides granular information about the data flow between the AIX application

and the database server job

Job Log MessagesThe process of finding and analyzing the job log for a DB2 CLI connection is identical to the process outlined for an embedded SQL application in the Job Log Message section of this paper on page 39

CLI Trace The DB2 CLIODBCJDBC trace utility provides very detailed information about the data streams exchanged between DB2 Connect and target database server Refer to the DB2 Information Center for more information on how to set up and analyze the CLI traces httppublibboulderibmcominfocenterdb2v8luwindexjsptopic=comibmdb2udbdocadc000 7959htm

43

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Trademarks

IBM eServer iSeries AIX AIX 5L i5OS WebSphere DB2 DB2 Universal Database DB2 Connect OS400 zOS OS390 Distributed Relational Database Architecture DRDA and DB2 Information Integration are trademarks or registered trademarks of International Business Machines Corporation in the United States and other countries

Java and all Java-based trademarks are trademarks of Sun Microsystems Inc in the United States other countries or both

Linux is a registered trademark of Linus Torvalds in the United States other countries or both

UNIX is a registered trademark of The Open Group in the United States and other countries

Microsoft and Windows are registered trademarks of Microsoft Corporation in the United States andor other countries

All other registered trademarks and trademarks are properties of their respective owners

IBM makes no commitment to make available any products referred to herein

References in this publication to IBM products or services do not imply that IBM intends to make them available in every country in which IBM operates

Additional Information ITSO offers a Redbook that can be helpful to those who want to learn more about i5OS AIX integration

bull AIX Integration with I5OS on the IBM eServer iSeries Server (SG24-6551)

Jarek Miszczyk is the Senior Software Engineer IBM eServer Solutions Enablement IBM Rochester

[Portions of this white paper reprinted with permission from MC Mag Online published by MC Press LLP httpwwwmcpressonlinecom]

Acknowledgments The author would like to thank the following people for their advice contributions and support on this paper

Bob Bittner IBM Rochester Jon Rush IBM Rochester Prasad Vallurupalli IBM Rochester Neil Willis IBM Rochester

44

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix A Source Listing of TestJDBCjava

package comibmiseriespwdimport javasqlimport javaxnamingimport javautilHashtableimport javautilimport javaxsqlimport comibmas400access

public class TestJDBC public static void main(javalangString[] args)

throws Exception

int numOfLoops = 5000int outerNumOfLoops = 5boolean firstExec = trueConnection conStatement sPreparedStatement psPreparedStatement pstmtdelCallableStatement cstmPreparedStatement pstmtHashtable env = new Hashtable()

envput(ContextINITIAL_CONTEXT_FACTORYcomsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env)Systemoutprintln(Deploying connection pooling data source)deployDataSource() Do the work with connection pooling onlyAS400JDBCConnectionPoolDataSource tkcpds =

(AS400JDBCConnectionPoolDataSource)ctxlookup(jdbcToolkitDataSource) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPool pool = new AS400JDBCConnectionPool(tkcpds) Adds 1 connection to the pool that can be used by theapplication (creates the physical database connections based onthe data source)poolfill(1)Systemoutprintln(nStart timing Toolkit connection pooling)long startTime = SystemcurrentTimeMillis()

for (int i = 0 i lt outerNumOfLoops i++) con = poolgetConnection()consetAutoCommit(false) deleteif ( i == 0)

long startDelete = SystemcurrentTimeMillis()cstm = cstm = conprepareCall(

CALL qsysqcmdexc(CLRPFM FILE(DB2USERCOFFEES) + 000000002800000))

cstmexecuteUpdate()cstmclose()long endDelete = SystemcurrentTimeMillis()Systemoutprintln(Delete all records +

(endDelete - startDelete) + ms elapsed)

45

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

String sqlinstrlong startInsert = SystemcurrentTimeMillis() insert

pstmt =conprepareStatement(INSERT INTO COFFEES VALUES( ))for (int j = 0 j lt numOfLoops j++) pstmtsetString(1 Kona_ + IntegertoString(i))pstmtsetInt(2 150)pstmtsetFloat(3 999f)pstmtsetInt(4 0)pstmtsetInt(5 0)pstmtaddBatch()int [] updateCounts = pstmtexecuteBatch()concommit()pstmtclose()long endInsert = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for + numOfLoops + inserts

+ (endInsert - startInsert)) selectlong startSelect = SystemcurrentTimeMillis()ps = conprepareStatement(SELECT FROM COFFEES)ResultSet rs = psexecuteQuery()rsnext()rsclose()concommit()psclose()long endSelect = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for select +

(endSelect - startSelect))consetAutoCommit(true)conclose()long endTime = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for + outerNumOfLoops +

loops + (endTime - startTime))Systemexit(0)

private static void deployDataSource()throws ExceptionString serverName = teraplex String databaseName = TERAPLEX String userName = db2user String password = db2pwd

Establish a JNDI context and bind the connection pool data sourceHashtable env = new Hashtable()envput(ContextINITIAL_CONTEXT_FACTORY

comsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPoolDataSource tkcpds = new

AS400JDBCConnectionPoolDataSource()tkcpdssetServerName(serverName) tkcpdssetDatabaseName(databaseName) tkcpdssetUser(userName) tkcpdssetPassword(password) tkcpdssetDescription(Toolkit Connection Pooling DataSource)tkcpdssetSavePasswordWhenSerialized(true)tkcpdssetExtendedDynamic(true)

46

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

tkcpdssetPackage(JDBCDS)tkcpdssetPackageCache(true)tkcpdssetPackageCriteria(select)enable the following properties as requiredcpdssetTrace(true)tkcpdssetServerTraceCategories( AS400JDBCDataSourceSERVER_TRACE_DEBUG_SERVER_JOB)

ctxrebind(jdbcToolkitDataSource tkcpds)

47

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix B mdash Source Listing of cursorsjsqc

Source File Name = cursorsjsqc Licensed Materials - Property of IBM (C) COPYRIGHT International Business Machines Corp 1995 2000 2004 All Rights Reserved US Government Users Restricted Rights - Use duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp PURPOSE This sample program demonstrates the use of a CURSOR The CURSOR is processed using static SQL EXTERNAL DEPENDENCIES - Ensure existence of database for precompile purposes - Precompile with the SQL precompiler (PREP in DB2) - Bind to a database (BIND in DB2) - Compile and link with the IBM Cset++ compiler (AIX and OS2) or the Microsoft Visual C++ compiler (Windows) or the compiler supported on your platform For more information about these samples see the README file For more information on programming in C see the - Programming in C and C++ section of the Application Development Guide For more information on building C applications see the - Building C Applications section of the Application Building Guide For more information on the SQL language see the SQL Reference

include ltstdiohgt include ltstdlibhgt include ltstringhgtinclude ltsqlhgtinclude ltsqlenvhgtinclude ltsqldahgtinclude ltsqlcahgt

int SqlInfoPrint( char struct sqlca int char )void TransRollback( void)

define EMB_SQL_CHECK( MSG_STR ) rc = SqlInfoPrint( MSG_STR ampsqlca __LINE__ __FILE__) if ( rc = 0 ) TransRollback( )

return 1

EXEC SQL INCLUDE SQLCA

int main(int argc char argv[])

EXEC SQL BEGIN DECLARE SECTIONchar dname[15]

48

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

char pname[10]double compchar userid[9]char passwd[19]

EXEC SQL END DECLARE SECTION

int rc = 0printf( Sample C program CURSORSJ n )if (argc == 1)

EXEC SQL CONNECT TO TPLXEMB_SQL_CHECK(CONNECT TO TPLX)

else if (argc == 3)

strcpy (userid argv[1])strcpy (passwd argv[2])EXEC SQL CONNECT TO TPLX USER userid USING passwdEMB_SQL_CHECK(CONNECT TO TPLX)

else

printf (nUSAGE cursor [userid passwd]nn)return 1

endif

EXEC SQL DECLARE c1 CURSOR FORselect deptname name salary + ifnull(comm0) as compensationfrom org o staff swhere odeptnumb = sdeptorder by deptname compensation desc

EXEC SQL OPEN c1EMB_SQL_CHECK(OPEN CURSOR)

printf(DEPARTMENT NAME COMPENSn)printf(-----------------------------------n)do

EXEC SQL FETCH c1 INTO dname pname compif (SQLCODE = 0) breakprintf( -1515s -1010s 72fn dname pname comp )

while ( 1 )

EXEC SQL CLOSE c1EMB_SQL_CHECK(CLOSE CURSOR)

EXEC SQL CONNECT RESETEMB_SQL_CHECK(CONNECT RESET)

exit(0)

end of program CURSORSJSQC

int SqlInfoPrint( char appMsgstruct sqlca pSqlcaint linechar file )

int rc = 0char sqlInfo[1024]char sqlInfoToken[1024]char sqlstateMsg[1024]char errorMsg[1024]

if (pSqlca-gtsqlcode = 0 ampamp pSqlca-gtsqlcode = 100)

49

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

strcpy(sqlInfo )if( pSqlca-gtsqlcode lt 0) sprintf( sqlInfoToken n---- error report ----n)

strcat( sqlInfo sqlInfoToken)else sprintf( sqlInfoToken n---- warning report ----n)

strcat( sqlInfo sqlInfoToken) endif

sprintf( sqlInfoToken app message = sn appMsg)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken line = dn line)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken file = sn file)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken SQLCODE = ldn pSqlca-gtsqlcode)strcat( sqlInfo sqlInfoToken)

get error message rc = sqlaintp( errorMsg 1024 80 pSqlca) return code is the length of the errorMsg string if( rc gt 0) sprintf( sqlInfoToken sn errorMsg)

strcat( sqlInfo sqlInfoToken)

get SQLSTATE message rc = sqlogstt( sqlstateMsg 1024 80 pSqlca-gtsqlstate)if (rc == 0) sprintf( sqlInfoToken sn sqlstateMsg)

strcat( sqlInfo sqlInfoToken)

if( pSqlca-gtsqlcode lt 0) sprintf( sqlInfoToken --- end error report ---n)

strcat( sqlInfo sqlInfoToken)printf(s sqlInfo)return 1

else sprintf( sqlInfoToken --- end warning report ---n)

strcat( sqlInfo sqlInfoToken)printf(s sqlInfo)return 0

endif endif

return 0

void TransRollback( ) struct sqlca sqlca

int rc = 0 rollback the transaction printf( nRolling back the transaction n)

EXEC SQL ROLLBACKrc = SqlInfoPrint( ROLLBACK ampsqlca __LINE__ __FILE__)if( rc == 0) printf( The transaction was rolled backn)

50

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

51

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix C mdash Source Listing of testclicpp

Include The Appropriate Header Filesinclude ltsqlclihgtinclude ltsqlcli1hgtinclude ltsqlutilhgtinclude ltsqlenvhgtinclude ltstdiohgt include ltiostreamgt include ltlocalehgt include ltstringhgtdefine SQL_SQLSTATE_SIZE 5define LOOPS 8

using namespace std

Define The CLI_Class Classclass CLI_Class

Attributespublic

SQLHANDLE EnvHandleSQLHANDLE ConHandleSQLHANDLE StmtHandleSQLRETURN rcSQLCHAR Job[6]SQLCHAR Name[10]SQLDOUBLE Comp

Operationspublic

CLI_Class()~CLI_Class()SQLRETURN ShowResults()

Constructor Destructor

SQLRETURN printError( SQLHDBC SQLHSTMT)

Define The Class ConstructorCLI_ClassCLI_Class()

setlocale( LC_ALL )

Initialize The Return Code Variablerc = SQL_SUCCESS

Allocate An Environment Handlerc = SQLAllocHandle(SQL_HANDLE_ENV SQL_NULL_HANDLE ampEnvHandle)

Allocate A Connection Handleif (rc == SQL_SUCCESS)

rc = SQLAllocHandle(SQL_HANDLE_DBC EnvHandle ampConHandle)

Define The Class DestructorCLI_Class~CLI_Class()

Free The Connection Handleif (ConHandle = NULL)

SQLFreeHandle(SQL_HANDLE_DBC ConHandle)

Free The Environment Handle

52

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

if (EnvHandle = NULL)SQLFreeHandle(SQL_HANDLE_ENV EnvHandle)

Define The ShowResults() Member FunctionSQLRETURN CLI_ClassShowResults(void)

While There Are Records In The Result Data Set Generated Retrieve And Display Themcout ltlt Name Job Compensation ltlt endlcout ltlt --------- ------ ------------ ltlt endlcoutsetf(iosleft)coutprecision(2)coutsetf(iosfixed)while (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)

rc = SQLFetch(StmtHandle)if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)

coutwidth(15)cout ltlt Name

coutwidth(10)cout ltlt Job

coutwidth(7)cout ltlt Comp ltltendl

if(rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO ampamp rc = SQL_NO_DATA)printError(ConHandle StmtHandle)

else

rc = 0SQLCloseCursor(StmtHandle)

Return The ODBC API Return Code To The Calling Functionreturn(rc)

SQLRETURN CLI_ClassprintError (SQLHDBC hdbc

SQLHSTMT hstmt)

SQLCHAR buffer[SQL_MAX_MESSAGE_LENGTH + 1]SQLCHAR sqlstate[SQL_SQLSTATE_SIZE + 1]SQLINTEGER sqlcodeSQLSMALLINT lengthSQLRETURN rcwhile ((rc = SQLError(SQL_NULL_HENV hdbc hstmt

sqlstateampsqlcodebufferSQL_MAX_MESSAGE_LENGTH + 1amplength)) == SQL_SUCCESS || rc ==

SQL_SUCCESS_WITH_INFO)

cout ltlt SQLSTATE ltlt sqlstate ltlt endlcout ltlt SQLCODE ltlt sqlcode ltlt endlcout ltlt Error msg ltlt buffer ltlt endl

53

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

cout ltlt----------------------------- ltlt endl ltlt endl

return(SQL_ERROR)

----------------------------------------------------------------- The Main Function -----------------------------------------------------------------int main()

Declare The Local Memory Variables

(SQLCHAR ) db2user SQL_NTS (SQLCHAR ) test26t SQL_NTS)

SQLRETURNSQLCHARSQLCHARSQLCHARchar

SQLCHAR

rc = SQL_SUCCESSDBName[10] = TPLXSQLStmt[255]c[10]ptrcurrentDepartment[8][15] = Head Office

New England Mid Atlantic South Atlantic Great Lakes PlainsPacificMountain

Create An Instance Of The CLI_Class ClassCLI_Class Example

Connect To iSeries Database if (ExampleConHandle = NULL)

rc = SQLConnect(ExampleConHandle DBName SQL_NTS

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)ExampleprintError(ExampleConHandle SQL_NULL_HSTMT)

return(rc)

cout ltlt Successfully connected to ltlt DBName ltlt ltlt endlrc = SQLSetConnectAttr(ExampleConHandle SQL_ATTR_AUTOCOMMIT

(SQLPOINTER) SQL_AUTOCOMMIT_OFF SQL_IS_UINTEGER) Allocate An SQL Statement Handlerc = SQLAllocHandle(SQL_HANDLE_STMT ExampleConHandle

ampExampleStmtHandle)if (rc == SQL_SUCCESS)

Define A SELECT SQL Statement

strcpy((char ) SQLStmt select name job salary + ifnull(comm0) ascompensation )

ptr = strcat( (char ) SQLStmt from org o staff s )ptr = strcat( (char ) SQLStmt where odeptnumb = sdept)ptr = strcat( (char ) SQLStmt and deptname = )ptr = strcat( (char ) SQLStmt order by compensation desc)

Prepare The SQL Statementrc = SQLPrepare(ExampleStmtHandle SQLStmt SQL_NTS)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)ExampleprintError(ExampleConHandle ExampleStmtHandle)

54

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

return(rc)

Bind The Columns In The Result Data Set Returned To Application Variables

rc = SQLBindCol(ExampleStmtHandle 1 SQL_C_CHAR (SQLPOINTER)ExampleName sizeof(ExampleName) NULL)

rc = SQLBindCol(ExampleStmtHandle 2 SQL_C_CHAR (SQLPOINTER)ExampleJob sizeof(ExampleJob) NULL)

rc = SQLBindCol(ExampleStmtHandle 3 SQL_C_DOUBLE (SQLPOINTER)ampExampleComp sizeof(ExampleComp) NULL)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO) ExampleprintError(ExampleConHandle ExampleStmtHandle)

return(rc)

while (true)

for (int i = 0 i lt LOOPS i++)

rc=SQLBindParameter(ExampleStmtHandle1SQL_PARAM_INPUTSQL_C_CHARSQL_CHAR

150(SQLPOINTER) currentDepartment[i8]0NULL)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)

ExampleprintError(ExampleConHandle ExampleStmtHandle)return(rc)

rc = SQLExecute(ExampleStmtHandle)if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)

ExampleprintError(ExampleConHandle ExampleStmtHandle)return(rc)

cout ltlt endl ltlt Current Dept ltlt currentDepartment[i8] ltlt

endl Display The Results Of The SQL QueryExampleShowResults()if(rc = 0)break

if ( i500 == 0 ampamp i gt 0 )cout ltlt Loops ltlt i ltlt ltlt endl

cout ltlt AFTER ltlt LOOPS ltlt loops Press X to exit ltlt endlcin gtgt cif (c[0] == x || c[0] == X)

break

Free The SQL Statement Handleif (ExampleStmtHandle = NULL )

SQLFreeHandle(SQL_HANDLE_STMT ExampleStmtHandle) Disconnect From The Northwind Sample Databaserc = SQLDisconnect(ExampleConHandle)

Return To The Operating Systemreturn(rc)

55

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Figure 10 Accessing DB2 UDB for iSeries with DB2 Universal Driver

The DB2 Universal Driver can be loaded in an AIX partition by installing one of the DB2 Connect for AIX products (see the Additional Information section for details) It is also a part of a DB2 Enterprise Server Edition for AIX install Specifically the developer needs three JAR files in a AIX partition to successfully connect to an iSeries server db2jccjar db2jcc_license_cisuzjar and db2jcc_license_cujar The iSeries license is contained in db2jcc_license_cisuzjar Note that this file is not a part of DB2 Client In other words a DB2 Connect license is required to use the driver in production environments The location of the JAR files needs to be added to the CLASSPATH environment variable For instance the following entry could be added to the AIX profile script

CLASSPATH=homedb2inst2sqllibjavadb2jccjarCLASSPATH=$CLASSPATHhomedb2inst2sqllibjavadb2jcc_license_cujarCLASSPATH=$CLASSPATHhomedb2inst2sqllibjavadb2jcc_license_cisuzjarexport CLASSPATH

Java Runtime 131 is a prerequisite

Additionally the developer should install the latest database group PTF (SF99503 for i5OS V5R3) on the iSeries server The Informational APAR ii13348 is keeping track of any fixes relevant to DRDA above and beyond the current database group PTF

Obtaining a Connection to DB2 UDB for iSeries When Type 4 connectivity is used the DB2 Universal Driver connects directly to the DB2 on iSeries through TCPIP Note that this is different from the legacy DB2 Type 2 JDBC driver that requires a DB2 node and remote database configurations on the client accessing iSeries The following code snippet illustrates how to use the DB2 JDBC Universal Driver to obtain a connection to DB2 UDB for iSeries

20

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

try ClassforName(comibmdb2jccDB2Driver) [1] catch(javalangClassNotFoundException e) Systemerrprint(ClassNotFoundException )Systemerrprintln(egetMessage())

try DriverManagergetConnection(jdbcdb2teraplex446TERAPLEX[2]

db2userdb2pwd) hellip catch(SQLException ex) Systemerrprintln(

SQLException + exgetMessage())

At [1] an instance of the DB2 JDBC Universal Driver is instantiated Then at [2] the driver is used to obtain a connection to the iSeries server Note the proper form of the database URL required by the driver

Considerations There are several advantages of DB2 JDBC Universal Driver bull Ease of cross-platform development mdash Consistent coding techniques and consistent error

codes and messages bull Ease of deployment mdash Pure Java (no runtime client required) and a single driver for accessing

DB2 on different platforms

The ease of use comes at a price though The iSeries JTOpen driver is optimized for accessing DB2 UDB for iSeries data and it uses native iSeries protocol to communicate with the back-end database server job This usually results in better performance and more-efficient system resources utilization For instance when using the DB2 JDBC Universal Driver to access an iSeries server the executeBatch method results in a single record insert There are also some restrictions when using DB2 Universal JDBC Driver with Type 4 connectivity

bull Support for distributed transactions (JTA) is not enabled bull Driver built-in connection pooling is not supported

Refer to Java application support in DB2 for more details on DB2 JDBC Universal Driver

21

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 Connect data access This section will explore the most important aspects of DB2 Connect ndash iSeries integration - including configuration tips and coding examples

DB2 Connect provides functionality for accessing data stored in DB2 UDB for iSeries as well as DB2 UDB for zOS and DB2 UDB for OS390reg DB2 Connect offers capabilities to access DB2 family members via several SQL interfaces gateway functions such as connection pooling and federated database functionality Many applications supporting the DB2 family of products leverage DB2 Connect as a key middleware component DB2 Connect is offered as separate AIX license products

Enterprise Edition Application Server Edition

In addition to DB2 Connect there are several other DB2 UDB Version 81 products that are supported on AIX

DB2 Universal Database Enterprise Server Edition DB2 Universal Database Workgroup Server Unlimited Edition DB2 Universal Database Workgroup Server Edition DB2 Universal Database Universal Developers Edition All Clients

The DB2 Connect Enterprise Edition functionality is also contained in DB2 Enterprise Server Edition for AIX

22

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 Connect in a nutshell In the scenario described in this paper the DB2 Connect functions contained in DB2 Enterprise Edition for AIX are utilized DB2 Connect Enterprise Edition provides support for both local and remote DB2 clients This is illustrated in Figure 11 Accessing DB2 UDB for iSeries with DB2 Connect

Figure 11 Accessing DB2 UDB for iSeries with DB2 Connect

DB2 Connect implements the Distributed Relational Database Architecturetrade (DRDAreg) to reduce the cost and complexity of accessing data stored in DB2 UDB for iSeries and other DRDA-compliant database servers DRDA defines the rules the protocols and the semantics for accessing distributed data Applications can access data in a distributed relational environment by using SQL statements In a distributed environment the system running the application and sending the SQL requests across the network is called the application requester (AR) A remote database server that executes SQL requests submitted by an application requester is known as the application server (AS) In the example shown in Figure 11 (above) DB2 Connect plays the role of an application requester while DB2 UDB for iSeries is an application server In this case DB2 Connect communicates with the iSeries database through TCPIP The iSeries DRDA application server implementation is based on multiple connection-oriented server jobs running in the QSYSWRK subsystem A DRDA listener job (QRWTLSTN) listens for TCP connect requests on port 446 Once an application requester connects to the listener job the listener wakes up one of the QRWTSRVR prestart jobs and assigns it to a given client connection Any further communication occurs directly between the client application and the QRWTSRVR job

DB2 Connect supports a wide range of programming interfaces that can be used by AIX applications to access the iSeries database Embedded SQL frac34 Both static and dynamic SQL frac34 Various programming languages (Java CC++ Cobol Fortran REXX)

DB2 Call Level Interface (DB2 CLI) ODBC JDBC frac34 DB2 JDBC Type 2 Driver frac34 DB2 JDBC Type 4 Driver (Universal JDBC Driver)

23

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Note that DB2 Connect supports access to DB2 UDB for iSeries through DB2 JDBC Universal driver However for performance and ease of maintenance reasons IBM recommends that Java applications running in AIX use native iSeries Toolbox JDBC driver See the JDBC Data Access section of this paper (above) for more details On the other hand DB2 Connect is a very efficient and robust connectivity option for AIX applications especially in the environments that are not directly supported by the native iSeries JDBC driver Here are several possible scenarios that would require DB2 Connect installed in a AIX partition

Embedded SQL interface is used to access DB2 CLI or ODBC interface is used to access DB2 A single SQL interface is needed to access multiple back end DB2 server Specific DB2 Connect functionality is needed such as distributed join or connection

pooling

Prerequisites One of the DB2 Connect products or DB2 Enterprise Server Edition for AIX V81 is needed Additionally DB2 Application Development Client is required in the AIX partition to compile DB2 applications

For maximum database server stability the developer should install the latest database group PTF (SF99503 for i5OS V5R3) on the iSeries server The Informational APAR ii13348 is keeping track of any fixes relevant to DRDA above and beyond the current database group PTF

DB2 Connect configuration The following example employs i5OS V5R3 and DB2 UDB Enterprise Server Edition for AIX Version 81 FixPak 6

Configuration steps in the iSeries partition The following process lists the necessary steps to be performed on the iSeries server 1) Verify that the TCPIP stack is working correctly It is assumed that the Virtual LAN is used to

communicate with the i5OS partition First obtain the IP address of the iSeries server or its hostname and ping the iSeries server from the AIX partition

2) Create a relational database (RDB) entry for the iSeries database in the i5OS partition If this has already been created it can be displayed by using the DSPRDBDIRE command Make sure that the RDB entry with a location of LOCAL exists on the iSeries server If it does not exist use the ADDRDBDIRE command to add the appropriate RDB entry For example the following command would add an RDB entry named TPLX For simplicity it is recommended that the TCPIP host name and RDB entry remain the same

ADDRDBDIRE RDB(TPLX) RMTLOCNAME(LOCAL)

3) Create a collection called NULLID This is necessary because the utilities shipped with DB2 Connect and DB2 UDB for AIX store their packages in the NULLID collection Since it does not exist by default in the iSeries server you must create it using the following command

CRTLIB LIB(NULLID)

4) Products that support DRDA automatically perform any necessary code page conversions at the receiving system For this to happen both systems need a translation table from their code page to the partner code page The default Coded Character Set Identifier (CCSID) on the iSeries server is 65535 Since DB2 Connect does not have a translation table for this code page the developer needs to change the individual user profiles to contain a CCSID that can be converted properly by DB2 Connect For US English this is 037 For other languages see DB2 Connect Personal Edition Quick Beginning GC09-2967 The following command changes the CCSID for an individual user profile to 037

24

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

CHGUSRPRF userid CCSID(037)

5) Verify that the default port 446 for DRDA service is being used To do this go to the Configure TCPIP menu (CFGTCP) select Configure Related Tables and then select Work with service table entries Verify that the DRDA service is set for port 446

6) The Distributed Data Management (DDM) job must be started for DRDA to work If you want the DDM job to be automatically started whenever TCPIP is started change the attributes of the DDM job using the CHGDDMTCPA command and set the Autostart server parameter to YES

7) If the system administrator chooses not to autostart the server issue the following command to start the DDM server job

STRTCPSVR SERVER(DDM)

8) Make sure that the user profiles that will be used to connect to the iSeries server exist on the server

25

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Configuration steps in the AIX partition The following steps are required for DB2 Connect to be configured in the AIX partition 1) Sign on to the AIX partition as the DB2 administrator 2) Launch Client Configuration Assistant (db2ca from the command prompt) It is assumed that

VNC or an X-Windows server are being used on the workstation so that the db2ca GUI can be properly rendered

3) From the Selected pull-down menu select the Add Database using Wizard option The Select how you want to setup a connection dialog appears Select Manually configure a connection to a database and click Next This is shown in Figure 12

Figure 12 Accessing DB2 UDB for iSeries with DB2 Connect

26

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

4) On the Select a communications protocol choose TCPIP and select The database physical resides on a host or OS400 system Then select the option Connect directly to the server as shown in Figure 13 Click Next

Figure 13 mdash Selecting communications protocol

27

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

5) On the TCPIP tab fill in the host name of the iSeries server The port number should be 446 This is shown in Figure 14 Click Next

Figure 14 mdash Specifying TCPIP communication parameters

28

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

6) On the Database tab fill in the Relational Database name Use the RDB entry name (specified in step 2) in the Configuration steps in the iSeries partition section as shown in Figure 15 Click Next

Figure 15 mdash Specifying the remote database

7) If you plan to use the ODBC applications select Register this database for ODBC as a system data source on the ODBC tab Click Next

29

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

8) On the Specify the node option dialog select OS400 from the Operating System pull-down menu This is shown in Figure 16 Click Finish

Figure 16 mdash Specifying the node options

30

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

9) The Test Connection dialog appears This allows the developer to verify that the connection works Select both CLI and JDBC check boxes You are also prompted for an iSeries user ID and password as shown in Figure 17

Figure 17 mdash Testing the connection

31

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

10) The successful connection to the database server is confirmed by the message box shown in Figure 18

Figure 18 mdash Test Connection results 11) At this time a newly configured database connection should appear in the main DB2

Configuration Assistant window It is recommended that the DB2 utilities are also bound to the iSeries database The bind process creates the necessary SQL packages on the remote database In the main Configuration Assistant window click the TPLX database entry and then select Selected-gtBindhellip

32

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

12) The Bind dialog appears Click Select All and then enter the connection information as shown in Figure 19 Click Bind The Results message box appears This allows the developer to monitor the progress of the binding process Watch for any error and warning messages

Figure 19 mdash Binding the DB2 utilities This concludes the DB2 Connect configuration steps

33

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Accessing DB2 UDB for iSeries from C embedded SQL

As mentioned earlier DB2 Connect allows developers to compile and run embedded SQL applications that access DB2 UDB for iSeries data This section covers implementation details for a C embedded SQL application called cursorsjsqc (see Appendix B for source code)

Prerequisites An embedded SQL application running in an AIX partition will use DB2 Connect services to access DB2 UDB for iSeries therefore the developer needs to make sure that all components listed in section Prerequisites on page 24 are installed The developer also needs to create a remote database connection as described in the DB2 Connect configuration section of this paper on page 24

Static SQL and SQL packages To successfully run against a DB2 UDB for iSeries database an embedded SQL application needs to be first precompiled and bound to the back-end database This process creates an SQL package on the target iSeries server The SQL package contains the access plan information for the SQL statements executed by the application The internal structure of the package as well as the method how its content is used by the SQL runtime to facilitate the access plan reuse is similar to the Extended Dynamic SQL support covered in detail in the Extended Dynamic SQL and Statement Caching section of this paper (on page 9) There are however important differences between the packages created by the extended dynamic SQL support and the packages created for embedded SQL DRDA client applications The extended dynamic SQL packages support dynamic SQL interfaces such as JDBC

that can submit ad hoc SQL statements at the run time The SQL runtime can prepare the dynamic statements and add them to the package On the other hand the DRDA packages are created at the precompile time and contain static SQL In order to add new statements to the package the application needs to be precompiled and rebound again

The extended dynamic SQL package can dynamically grow up to 500MB by allocating new space as required The DRDA packages since they are created at the precompile time have a fix size and do not grow over their life time

Simple embedded SQL application The application is based on a source code provided in the DB2 UDB samples directory typically to be found at homedb2inst1sqllibsamples The cursorsjsqc performs a join between STAFF and ORG tables located in DB2USER schema (library) on the TPLX database server (the source is provided at the end of this paper in Appendix B) The join statement retrieves the DEPTNAME column from ORG NAME column from STAFF and calculates the total compensation for an employee by adding SALARY and COMM columns in STAFF The results are sorted by department name and total compensation Here is the SELECT statement used by the application

SELECT deptname name salary + IFNULL(comm0) as compensationFROM org o staff sWHERE odeptnumb = sdeptORDER BY deptname compensation DESC

The application iterates through the selected records and prints out the data to the standard output device The sample DB2USER schema was created with the following SQL statements

db2 CONNECT TO tplx USER db2user USING mypassworddb2 CALL QSYSCREATE_SQL_SAMPLE(DB2USER)

34

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Make sure that the AIX partition is logged into with the DB2 admin user profile If the defaults were selected at the DB2 installation time this profile name is db2inst1 It is also assumed that DB2USER user exists on the iSeries server and that it has appropriate authority

There are several steps that are required to create an executable for the cursorsjsqc source code First the DB2 PRECOMPILE utility needs to be called The utility creates a bind file that is used to bind the required SQL package to the TPLX database It also converts embedded SQL statements into DB2 run-time API calls and produces a pure C source file that can be processed by an AIX C compiler

db2 CONNECT TO tplx USER db2user USING mypassworddb2 prep cursorsjsqc bindfile

Note that the connect statement is required only if the developer is not already connected to the database on an iSeries server Watch for any error or warning messages returned by the DB2 prep utility The prepare step should produce cursorsjbnd and cursorsjc files in the current directory Now the developer can invoke the bind utility to prepare the statements contained in the bind file and create the package on the target iSeries database server

db2 bind cursorsjbnd

It is assumed that Visual C++ 60 is installed and configured in the AIX partition Refer to the ldquoDeveloping and Porting C and C++ Applications on AIXrdquo redbook for more information on how to use the Visual C++ compiler httpibmcomredbooksabstractssg245674htmlOpen

Use the following commands to compile the C source generated by the precompile utility

xlc -I$INSTHOMEsqllibinclude ndashc cursorsjcxlc ndasho cursorsj cursorsjo -L$INSTHOMEsqlliblib ndashldb2

Run the program from the AIX prompt

cursorsj db2user mypassword

Distributed Join DB2 UDB Version 8 provides core federated server functionality A federated system consists of a DB2 UDB instance that operates as a federated server a database that acts as the federated database one or more data sources and clients (users and applications) that access the database and data sources Federated server permits objects stored in multiple databases to be accessed together in the same query For example a query can refer to a table that resides in DB2 UDB for iSeries and join it to a table stored in DB2 UDB for AIX Such a query would constitute so called distributed join The support for DB2 UDB for iSeries as a federated data source is provided by core federated server functionality directly implemented in DB2 UDB Enterprise Server Edition and DB2 UDB Connect Enterprise Edition All other DB2 UDB family members are also supported directly by core DB2 UDB federated server An additional software product DB2 Information Integratortrade is required to access non-DB2 UDB databases such as Oracle Sybase or Microsoftreg SQL Server Consult the following white papers for a detailed discussion on DB2 federated server support Heterogeneous data access for iSeries applications Version 2 httpibmcomserversenablesiteeducationiborecordhtmlhetdata Fundamentals of IBM DB2 Federated Server and Relational Connect httpwww7bsoftwareibmcomdmddlibrarytecharticle0206purnell0206purnellhtml

35

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Distributed Join Example In this section the steps that are required to configure DB2 UDB for iSeries as a federated data source will be illustrated Then the cursorsjsqc program will be ldquotweakedrdquo so that it executes a distributed join query that accesses data stored on an iSeries server and in the local DB2 UDB for AIX database It is assumed that the developer is familiar with the DB2 federated server concepts

Note Run the following commands from the Command Line Processor prompt Load the utility by executing the db2 command at the AIX prompt 1) First the local DB2 UDB for AIX instance needs to be enabled as a DB2 federated server

This is done by setting the database manager configuration parameter FEDERATED to YES

db2=gt update dbm cfg using FEDERATED YES

The database instance needs to be restarted for the change to take effect

NOTE A federated database is a regular database in a DB2 UDB instance that has the FEDERATED parameter enabled Therefore in this example the SAMPLE database that was created earlier is used as the federated database A new database can also be created using the CREATE DATABASE command

2) Connect to the federated database

db2=gt connect to sample

3) Use the CREATE WRAPPER statement to register a wrapper for the iSeries data source Wrappers are library routines that are used by the federated server to perform operations such as connecting to a data source and retrieving data from it The default wrapper name for DB2 UDB for iSeries is DRDA Here is the command to register the DRDA wrapper

db2=gt create wrapper drda

4) Use the CREATE SERVER statement to register a data source as a server within the federated database The server definition specifies the type and version of the data source and the wrapper used for communications with this data source For the DB2 UDB for iSeries data source the node and the database names are also needed The node and database name parameters have been configured for our TPLX database in the Configuration steps in the AIX partition section (on page 24) Use the following DB2 UDB command to lookup these parameter on the federated server

db2=gt list database directory

In this case the command produced the following output

Database alias = TPLX Database name = DCSE99E1 Node name = NDE9BF76 Database release level = a00 Comment = Directory entry type = Remote Authentication = SERVER Catalog database partition number = -1

36

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Note that the node name is set to NDE9BF76 The name was generated by the Configuration Administrator utility (db2ca)

Here is the command to register the TPLX database as a federated server

db2=gt create server tplx type db2400 version 530 wrapperdrda authorization db2user password mypassword options(nodeNDE9BF76 dbname TPLX)

The command is quite complex so make sure that the syntax is correct

5) Define the user mappings that instructs the federated server what user ID and password should be used when connecting to the iSeries data source

db2=gt create user mapping for user server tplxoptions(remote_authid db2user remote_password mypassword)

Specify the nickname for the iSeries table or view A nickname is an identifier that is used by the federated server to reference an object located at the data source The following command creates a nickname for the STAFF table located in the DB2USER schema on the TPLX database

db2=gt create nickname tplx_staff for tplxdb2userstaff

6) Test the distributed join query

db2=gt SELECT deptname name salary + COALESCE(comm0) ascompensation FROM org o tplx_staff s WHERE odeptnumb =sdept ORDER BY deptname compensation DESC

Note that the native iSeries function IFNULL has been substituted with an equivalent DB2 UDB function COALESCE COALESCE is also supported on iSeries servers For better portability IBM encourages the use of COALESCE rather than IFNULL Note also that the query runs on the federated server rather than on TPLX It accesses the ORG table in the local DB2 UDB for AIX SAMPLE database and the STAFF table that resides in TPLX The federated server performs the necessary distributed join

7) Modify the cursorsjsqc so that it executes a distributed join There are two source code modifications - Change the CONNECT TO statements Now the application needs to connect to the

federated database SAMPLE rather than to TPLX

EXEC SQL CONNECT TO SAMPLEEXEC SQL CONNECT TO SAMPLE USER userid USING passwd

- Modify the select statement so that it performs a distributed join Use the statement (shown in step 6) above Save the new source version as cursordjsqc

- Prepare bind and compile the distributed join version of the program as described in the Simple C embedded SQL application section (on page 34)

db2 prep cursordjsqc bindfiledb2 bind cursordjbndxlc -I$INSTHOMEsqllibinclude ndashc cursordjcxlc ndasho cursordj cursordjo -L$INSTHOMEsqlliblib ndashldb2

37

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

- Run the program from the AIX prompt

cursordj

Connection Pooling and Connection ConcentratorA modern Web-based application typically executes a large number of short-lived transactions Executing a transaction in this environment means establishing a database connection executing a few SQL statements and terminating this connection Creating connections to the database server is a very costly process To reduce the unnecessary workload DB2 Connect implements connection pooling and connection concentrator Connection pooling mechanism allows DB2 Connect to reuse an existing connection infrastructure for subsequent connection requests The connection concentrator is an advanced technology that allows DB2 Connect to serve a potentially very large number of clients with a limited number of database connections This is accomplished by decoupling clients from a particular database connection

Note that currently neither connection pooling nor connection concentrator support DB2 UDB for iSeries Therefore for performance reasons the author strongly recommends that the application server that obtains and drops connections very frequently implements its own database connection pooling mechanism that would assign an existing pooled database connection to a new AIX process or thread

TroubleshootingTroubleshooting a multi-tier application may be a bit tricky because the developer needs to deal with software components that reside in separate partitions The authorrsquos experience shows that two tools are particularly useful for pinning down the potential problem areas The joblog messages for a database server job usually provide enough details to isolate DB2

UDB for iSeries runtime issues The DRDA trace utility provides granular information about the data flow between the AIX

application and the iSeries server job

38

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Job Log MessagesAs mentioned earlier a DB2 client communicates with a corresponding iSeries server job This server job runs the SQL requests on behalf of the client More precisely when a DB2 client submits an SQL statement the statement is passed to a server job that in turn calls the DB2 runtime to execute the statement The results are then reformatted and marshaled to the client The iSeries DRDA server jobs are called QRWTSRVR and they run in the QUSRWRK subsystem At any given time there may be a large number of DRDA server jobs active on the system so the first step is to identify the job that serves the particular client connection The easiest method to accomplish this task is to run the following CL command from the i5OS prompt

WRKOBJLCK OBJ(DB2USER) OBJTYPE(USRPRF)

Here DB2USER is the user profile that is used to connect to the iSeries server Note that a QRWTSRVR job is assigned to a client after the connection has been established so the developer needs to set a breakpoint in the client application below the CONNECT TO statement

Once the Work with Object Locks appears key in 5 (Work with Job) next to the only QRWTSRVR job that should be listed This shows the Work with Job dialog Select option 10 to display the job log for the database server job Now the developer can search the job log for any error messages generated by the DB2 runtime

Sometimes it is also useful to include debug messages in the job log The debug messages are informational messages written to the job log about the implementation of a query They describe query implementation methods such as use of indexes join order ODP implementation (reusable versus non-reusable) and so on The easiest way to instruct the iSeries server to include the debug messages is to call the following stored procedure just after the connection to the iSeries server is established

EXEC SQL call qsysqcmdexc(STRDBGUPDPROD(YES)000000002000000)

A sample of the job log messages with debug messages enabled is shown below in Figure 20

Arrival sequence access was used for file STAFFAccess path suggestion for file STAFFQuery options used to build the OS400 query access plan Ending debug message for query ODP created Blocking used for queryCursor SQLCUR201 opened1 rows fetched from cursor SQLCUR201Row not found for SQLCUR201ODP deleted Cursor SQLCUR201 closedDESCRIBE of prepared statement STMT0201 completed

Figure 20 mdash Joblog with debug messages enabled

So the job log offers fairly detailed information on how the AIX client requests were implemented by the DB2 runtime

39

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 DRDA trace utilityThe DB2 DRDA trace utility (db2drdat) provides detailed information about the data streams exchanged between DB2 Connect and target database server The output file produced by the utility contains send and receive communications buffers TCPIP error messages and SQL Communications Area (SQLCA) information Please refer to lsquoDB2 Connect Userrsquos Guidersquo manual for in-depth discussion of the DRDA trace utility

Accessing DB2 UDB for iSeries from CLI DB2 Call Level Interface (CLI ) is based on the Microsoft Open Database Connectivity (ODBC) specification and the ISO CLI standard The DB2 CLI interface gained popularity among DB2 application providers because the developer can build an ODBC application by simply linking the application with libdb2 library on a UNIX server In other words the developer directly utilizes the DB2 ODBC driver services without a need for an ODBC driver manager Additionally in contrast to embedded SQL the developer does not need to precompile or bind DB2 CLI applications because they use packages provided with DB2 UDB The developer simply compiles and links the application

Prerequisites A DB2 CLI application running in an AIX partition will use DB2 Connect services to access DB2 UDB for iSeries therefore make sure that all components listed in Prerequisites section of this paper on page 24 are installed The developer also needs to create a remote database connection as described in the DB2 Connect configuration section of this paper on page 24

Dynamic SQL and Access Plan Caching A DB2 CLI client application uses the dynamic SQL interface and does not have the capability to utilize the extended dynamic SQL support Therefore it runs lsquopurersquo dynamic SQL statements That does not mean however that the process of parsing validating and optimizing will be repeated for every execution of a given dynamic SQL statement

The DB2 UDB for iSeries database implements an internal object called System-Wide SQL Statement Cache (SWSC) The SWSC can improve the performance of programs using dynamic SQL statements by caching the access plans in a system-wide cache When a dynamic SQL statement is submitted the SQL runtime searches the SWSC to see if this statement has been previously executed If so then DB2 retrieves and reuses the key information associated with the cached statement and thereby the processing time and the resources utilization can be significantly reduced

Simple DB2 CLI C++ ApplicationThis section covers DB2 CLI implementation details for a sample C++ program called testclicpp (the source is provided at the end of this paper in Appendix C) To compile the source with Visual C++ complier use the following command in the AIX partition

xlC ndashI$INSTHOMEsqllibinclude ndashc testclicppxlC ndasho testcli testclio ndashL$INSTHOMEsqlliblib ndashldb2

The application performs a join between STAFF and ORG tables located in DB2USER schema (library) The join statement retrieves the DEPTNAME column from ORG NAME and JOB columns from STAFF and calculates the total compensation for an employee by adding SALARY and COMM columns in STAFF The results are sorted by total compensation The selection criterion is based on the current value of the department name parameter Here is the SELECT statement used by testcli

40

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

select name job salary + coalesce(comm0) as compensationfrom org o staff swhere odeptnumb = sdeptand deptname = order by compensation desc

Figure 21 shows the software components involved in the execution of this sample application

Figure 21 How a DB2 CLI client accesses DB2 UDB on an iSeries server

Although the testcli application is fairly simple it covers some important aspects of efficient CLI programming for DB2 UDB for iSeries

Reusable Open Data Paths (ODPs)An Open Data Path (ODP) definition is an internal i5OS object that is created when certain SQL statements (such as OPEN INSERT UPDATE and DELETE) are executed for the first time in a given job (or connection) The ODP can be thought of as a runtime implementation of an access plan The access plan created at the optimization time provides a recipe or in other words a sequence of steps necessary to execute the statement The ODP on the other hand provides the executable code for all requested IO operations The process of creating new ODP objects is fairly CPU- and IO-intensive so whenever possible the iSeries DB2 runtime tries to reuse existing ODPs For instance a SQLCloseCursor() API call may close the SQL cursor but leave the ODP available to be used the next time the cursor is opened This can significantly reduce the processing and response time in running SQL statements A reusable OPD usually requires 10 to 20 times less CPU resources than a newly created ODP Therefore it is important that the applications employ programming techniques that allow the DB2 runtime to reuse ODPs

With dynamic interfaces such as CLI full opens are avoided by using a prepare once execute many programming paradigm It means that when an SQL statement is going to be executed more than once you should prepare the statement just once and then reuse the prepared

41

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

statements for consecutive executions Although DB2 UDB does try to convert literals to parameter markers so that similar statements can be reused it is a better programming practice to explicitly implement parameter markers That way the chances for reusable ODPs are quite significantly improved The code snippet in Figure 22 illustrates how to implement the prepare once execute many programming technique

Define A SELECT SQL Statementstrcpy((char ) SQLStmt select name job salary + ifnull(comm0) ascompensation )ptr = strcat( (char ) SQLStmt from org o staff s )ptr = strcat( (char ) SQLStmt where odeptnumb = sdept)ptr = strcat( (char ) SQLStmt and deptname = )ptr = strcat( (char ) SQLStmt order by compensation desc) [1]

Prepare The SQL Statementrc = SQLPrepare(ExampleStmtHandle SQLStmt SQL_NTS) [2]

Bind The Columns In The Result Data Set Returned To Application Variablesrc = SQLBindCol(ExampleStmtHandle 1 SQL_C_CHAR (SQLPOINTER)

ExampleName sizeof(ExampleName) NULL)rc = SQLBindCol(ExampleStmtHandle 2 SQL_C_CHAR (SQLPOINTER)

ExampleJob sizeof(ExampleJob) NULL)rc = SQLBindCol(ExampleStmtHandle 3 SQL_C_DOUBLE (SQLPOINTER)

ampExampleComp sizeof(ExampleComp) NULL)

for (int i = 0 i lt LOOPS i++)rc=SQLBindParameter(ExampleStmtHandle

1SQL_PARAM_INPUTSQL_C_CHARSQL_CHAR10(SQLPOINTER) currentDepartment[i8]0NULL) [3]

rc = SQLExecute(ExampleStmtHandle) [4]cout ltlt endl ltlt Current Dept ltlt currentDepartment[i8] ltlt endl Display The Results Of The SQL QueryExampleShowResults()

Figure 22 Use the prepare once execute many programming technique

The error-handling code has been removed for clarity At [1] the statement text is assigned to a variable Note that a parameter marker is used in the WHERE clause The statement is then prepared just once at [2] The current value of the parameter is bound to the prepared statement at [3] The prepared statement is executed at [4] Steps [3] and [4] are repeatedly executed in a for loop

Techniques to Further Improve DB2 CLI Performance Thus far this paper has discussed the techniques used by a sample application to tune the CLI performance However depending on the application architecture other methods of improving CLI performance may be considered

Connection PoolingCurrently the CLI application connecting through DB2 Connect to DB2 UDB for iSeries does not take advantage of the connection pooling mechanism implemented by DB2 Connect Therefore for performance reasons the author strongly recommends that the application server that obtains and drops connections very frequently implements its own database connection pooling mechanism that would assign an existing pooled database connection to a new AIX process or thread

42

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Blocking

For queries which result in returning large data blocks from the iSeries server (usually 32K of data and above) ensure that the database manager configuration parameter RQRIOBLK is set to 32767 This can be done using the Command Line Processor (CLP) as follows

db2 update database manager configuration using RQRIOBLK 32767

TroubleshootingThe experience of the author shows that two tools are particularly useful for pinning down the potential problem areas bull Joblog messages for a database server job usually provides enough details to isolate DB2

runtime issues bull CLI trace utility provides granular information about the data flow between the AIX application

and the database server job

Job Log MessagesThe process of finding and analyzing the job log for a DB2 CLI connection is identical to the process outlined for an embedded SQL application in the Job Log Message section of this paper on page 39

CLI Trace The DB2 CLIODBCJDBC trace utility provides very detailed information about the data streams exchanged between DB2 Connect and target database server Refer to the DB2 Information Center for more information on how to set up and analyze the CLI traces httppublibboulderibmcominfocenterdb2v8luwindexjsptopic=comibmdb2udbdocadc000 7959htm

43

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Trademarks

IBM eServer iSeries AIX AIX 5L i5OS WebSphere DB2 DB2 Universal Database DB2 Connect OS400 zOS OS390 Distributed Relational Database Architecture DRDA and DB2 Information Integration are trademarks or registered trademarks of International Business Machines Corporation in the United States and other countries

Java and all Java-based trademarks are trademarks of Sun Microsystems Inc in the United States other countries or both

Linux is a registered trademark of Linus Torvalds in the United States other countries or both

UNIX is a registered trademark of The Open Group in the United States and other countries

Microsoft and Windows are registered trademarks of Microsoft Corporation in the United States andor other countries

All other registered trademarks and trademarks are properties of their respective owners

IBM makes no commitment to make available any products referred to herein

References in this publication to IBM products or services do not imply that IBM intends to make them available in every country in which IBM operates

Additional Information ITSO offers a Redbook that can be helpful to those who want to learn more about i5OS AIX integration

bull AIX Integration with I5OS on the IBM eServer iSeries Server (SG24-6551)

Jarek Miszczyk is the Senior Software Engineer IBM eServer Solutions Enablement IBM Rochester

[Portions of this white paper reprinted with permission from MC Mag Online published by MC Press LLP httpwwwmcpressonlinecom]

Acknowledgments The author would like to thank the following people for their advice contributions and support on this paper

Bob Bittner IBM Rochester Jon Rush IBM Rochester Prasad Vallurupalli IBM Rochester Neil Willis IBM Rochester

44

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix A Source Listing of TestJDBCjava

package comibmiseriespwdimport javasqlimport javaxnamingimport javautilHashtableimport javautilimport javaxsqlimport comibmas400access

public class TestJDBC public static void main(javalangString[] args)

throws Exception

int numOfLoops = 5000int outerNumOfLoops = 5boolean firstExec = trueConnection conStatement sPreparedStatement psPreparedStatement pstmtdelCallableStatement cstmPreparedStatement pstmtHashtable env = new Hashtable()

envput(ContextINITIAL_CONTEXT_FACTORYcomsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env)Systemoutprintln(Deploying connection pooling data source)deployDataSource() Do the work with connection pooling onlyAS400JDBCConnectionPoolDataSource tkcpds =

(AS400JDBCConnectionPoolDataSource)ctxlookup(jdbcToolkitDataSource) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPool pool = new AS400JDBCConnectionPool(tkcpds) Adds 1 connection to the pool that can be used by theapplication (creates the physical database connections based onthe data source)poolfill(1)Systemoutprintln(nStart timing Toolkit connection pooling)long startTime = SystemcurrentTimeMillis()

for (int i = 0 i lt outerNumOfLoops i++) con = poolgetConnection()consetAutoCommit(false) deleteif ( i == 0)

long startDelete = SystemcurrentTimeMillis()cstm = cstm = conprepareCall(

CALL qsysqcmdexc(CLRPFM FILE(DB2USERCOFFEES) + 000000002800000))

cstmexecuteUpdate()cstmclose()long endDelete = SystemcurrentTimeMillis()Systemoutprintln(Delete all records +

(endDelete - startDelete) + ms elapsed)

45

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

String sqlinstrlong startInsert = SystemcurrentTimeMillis() insert

pstmt =conprepareStatement(INSERT INTO COFFEES VALUES( ))for (int j = 0 j lt numOfLoops j++) pstmtsetString(1 Kona_ + IntegertoString(i))pstmtsetInt(2 150)pstmtsetFloat(3 999f)pstmtsetInt(4 0)pstmtsetInt(5 0)pstmtaddBatch()int [] updateCounts = pstmtexecuteBatch()concommit()pstmtclose()long endInsert = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for + numOfLoops + inserts

+ (endInsert - startInsert)) selectlong startSelect = SystemcurrentTimeMillis()ps = conprepareStatement(SELECT FROM COFFEES)ResultSet rs = psexecuteQuery()rsnext()rsclose()concommit()psclose()long endSelect = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for select +

(endSelect - startSelect))consetAutoCommit(true)conclose()long endTime = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for + outerNumOfLoops +

loops + (endTime - startTime))Systemexit(0)

private static void deployDataSource()throws ExceptionString serverName = teraplex String databaseName = TERAPLEX String userName = db2user String password = db2pwd

Establish a JNDI context and bind the connection pool data sourceHashtable env = new Hashtable()envput(ContextINITIAL_CONTEXT_FACTORY

comsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPoolDataSource tkcpds = new

AS400JDBCConnectionPoolDataSource()tkcpdssetServerName(serverName) tkcpdssetDatabaseName(databaseName) tkcpdssetUser(userName) tkcpdssetPassword(password) tkcpdssetDescription(Toolkit Connection Pooling DataSource)tkcpdssetSavePasswordWhenSerialized(true)tkcpdssetExtendedDynamic(true)

46

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

tkcpdssetPackage(JDBCDS)tkcpdssetPackageCache(true)tkcpdssetPackageCriteria(select)enable the following properties as requiredcpdssetTrace(true)tkcpdssetServerTraceCategories( AS400JDBCDataSourceSERVER_TRACE_DEBUG_SERVER_JOB)

ctxrebind(jdbcToolkitDataSource tkcpds)

47

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix B mdash Source Listing of cursorsjsqc

Source File Name = cursorsjsqc Licensed Materials - Property of IBM (C) COPYRIGHT International Business Machines Corp 1995 2000 2004 All Rights Reserved US Government Users Restricted Rights - Use duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp PURPOSE This sample program demonstrates the use of a CURSOR The CURSOR is processed using static SQL EXTERNAL DEPENDENCIES - Ensure existence of database for precompile purposes - Precompile with the SQL precompiler (PREP in DB2) - Bind to a database (BIND in DB2) - Compile and link with the IBM Cset++ compiler (AIX and OS2) or the Microsoft Visual C++ compiler (Windows) or the compiler supported on your platform For more information about these samples see the README file For more information on programming in C see the - Programming in C and C++ section of the Application Development Guide For more information on building C applications see the - Building C Applications section of the Application Building Guide For more information on the SQL language see the SQL Reference

include ltstdiohgt include ltstdlibhgt include ltstringhgtinclude ltsqlhgtinclude ltsqlenvhgtinclude ltsqldahgtinclude ltsqlcahgt

int SqlInfoPrint( char struct sqlca int char )void TransRollback( void)

define EMB_SQL_CHECK( MSG_STR ) rc = SqlInfoPrint( MSG_STR ampsqlca __LINE__ __FILE__) if ( rc = 0 ) TransRollback( )

return 1

EXEC SQL INCLUDE SQLCA

int main(int argc char argv[])

EXEC SQL BEGIN DECLARE SECTIONchar dname[15]

48

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

char pname[10]double compchar userid[9]char passwd[19]

EXEC SQL END DECLARE SECTION

int rc = 0printf( Sample C program CURSORSJ n )if (argc == 1)

EXEC SQL CONNECT TO TPLXEMB_SQL_CHECK(CONNECT TO TPLX)

else if (argc == 3)

strcpy (userid argv[1])strcpy (passwd argv[2])EXEC SQL CONNECT TO TPLX USER userid USING passwdEMB_SQL_CHECK(CONNECT TO TPLX)

else

printf (nUSAGE cursor [userid passwd]nn)return 1

endif

EXEC SQL DECLARE c1 CURSOR FORselect deptname name salary + ifnull(comm0) as compensationfrom org o staff swhere odeptnumb = sdeptorder by deptname compensation desc

EXEC SQL OPEN c1EMB_SQL_CHECK(OPEN CURSOR)

printf(DEPARTMENT NAME COMPENSn)printf(-----------------------------------n)do

EXEC SQL FETCH c1 INTO dname pname compif (SQLCODE = 0) breakprintf( -1515s -1010s 72fn dname pname comp )

while ( 1 )

EXEC SQL CLOSE c1EMB_SQL_CHECK(CLOSE CURSOR)

EXEC SQL CONNECT RESETEMB_SQL_CHECK(CONNECT RESET)

exit(0)

end of program CURSORSJSQC

int SqlInfoPrint( char appMsgstruct sqlca pSqlcaint linechar file )

int rc = 0char sqlInfo[1024]char sqlInfoToken[1024]char sqlstateMsg[1024]char errorMsg[1024]

if (pSqlca-gtsqlcode = 0 ampamp pSqlca-gtsqlcode = 100)

49

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

strcpy(sqlInfo )if( pSqlca-gtsqlcode lt 0) sprintf( sqlInfoToken n---- error report ----n)

strcat( sqlInfo sqlInfoToken)else sprintf( sqlInfoToken n---- warning report ----n)

strcat( sqlInfo sqlInfoToken) endif

sprintf( sqlInfoToken app message = sn appMsg)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken line = dn line)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken file = sn file)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken SQLCODE = ldn pSqlca-gtsqlcode)strcat( sqlInfo sqlInfoToken)

get error message rc = sqlaintp( errorMsg 1024 80 pSqlca) return code is the length of the errorMsg string if( rc gt 0) sprintf( sqlInfoToken sn errorMsg)

strcat( sqlInfo sqlInfoToken)

get SQLSTATE message rc = sqlogstt( sqlstateMsg 1024 80 pSqlca-gtsqlstate)if (rc == 0) sprintf( sqlInfoToken sn sqlstateMsg)

strcat( sqlInfo sqlInfoToken)

if( pSqlca-gtsqlcode lt 0) sprintf( sqlInfoToken --- end error report ---n)

strcat( sqlInfo sqlInfoToken)printf(s sqlInfo)return 1

else sprintf( sqlInfoToken --- end warning report ---n)

strcat( sqlInfo sqlInfoToken)printf(s sqlInfo)return 0

endif endif

return 0

void TransRollback( ) struct sqlca sqlca

int rc = 0 rollback the transaction printf( nRolling back the transaction n)

EXEC SQL ROLLBACKrc = SqlInfoPrint( ROLLBACK ampsqlca __LINE__ __FILE__)if( rc == 0) printf( The transaction was rolled backn)

50

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

51

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix C mdash Source Listing of testclicpp

Include The Appropriate Header Filesinclude ltsqlclihgtinclude ltsqlcli1hgtinclude ltsqlutilhgtinclude ltsqlenvhgtinclude ltstdiohgt include ltiostreamgt include ltlocalehgt include ltstringhgtdefine SQL_SQLSTATE_SIZE 5define LOOPS 8

using namespace std

Define The CLI_Class Classclass CLI_Class

Attributespublic

SQLHANDLE EnvHandleSQLHANDLE ConHandleSQLHANDLE StmtHandleSQLRETURN rcSQLCHAR Job[6]SQLCHAR Name[10]SQLDOUBLE Comp

Operationspublic

CLI_Class()~CLI_Class()SQLRETURN ShowResults()

Constructor Destructor

SQLRETURN printError( SQLHDBC SQLHSTMT)

Define The Class ConstructorCLI_ClassCLI_Class()

setlocale( LC_ALL )

Initialize The Return Code Variablerc = SQL_SUCCESS

Allocate An Environment Handlerc = SQLAllocHandle(SQL_HANDLE_ENV SQL_NULL_HANDLE ampEnvHandle)

Allocate A Connection Handleif (rc == SQL_SUCCESS)

rc = SQLAllocHandle(SQL_HANDLE_DBC EnvHandle ampConHandle)

Define The Class DestructorCLI_Class~CLI_Class()

Free The Connection Handleif (ConHandle = NULL)

SQLFreeHandle(SQL_HANDLE_DBC ConHandle)

Free The Environment Handle

52

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

if (EnvHandle = NULL)SQLFreeHandle(SQL_HANDLE_ENV EnvHandle)

Define The ShowResults() Member FunctionSQLRETURN CLI_ClassShowResults(void)

While There Are Records In The Result Data Set Generated Retrieve And Display Themcout ltlt Name Job Compensation ltlt endlcout ltlt --------- ------ ------------ ltlt endlcoutsetf(iosleft)coutprecision(2)coutsetf(iosfixed)while (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)

rc = SQLFetch(StmtHandle)if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)

coutwidth(15)cout ltlt Name

coutwidth(10)cout ltlt Job

coutwidth(7)cout ltlt Comp ltltendl

if(rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO ampamp rc = SQL_NO_DATA)printError(ConHandle StmtHandle)

else

rc = 0SQLCloseCursor(StmtHandle)

Return The ODBC API Return Code To The Calling Functionreturn(rc)

SQLRETURN CLI_ClassprintError (SQLHDBC hdbc

SQLHSTMT hstmt)

SQLCHAR buffer[SQL_MAX_MESSAGE_LENGTH + 1]SQLCHAR sqlstate[SQL_SQLSTATE_SIZE + 1]SQLINTEGER sqlcodeSQLSMALLINT lengthSQLRETURN rcwhile ((rc = SQLError(SQL_NULL_HENV hdbc hstmt

sqlstateampsqlcodebufferSQL_MAX_MESSAGE_LENGTH + 1amplength)) == SQL_SUCCESS || rc ==

SQL_SUCCESS_WITH_INFO)

cout ltlt SQLSTATE ltlt sqlstate ltlt endlcout ltlt SQLCODE ltlt sqlcode ltlt endlcout ltlt Error msg ltlt buffer ltlt endl

53

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

cout ltlt----------------------------- ltlt endl ltlt endl

return(SQL_ERROR)

----------------------------------------------------------------- The Main Function -----------------------------------------------------------------int main()

Declare The Local Memory Variables

(SQLCHAR ) db2user SQL_NTS (SQLCHAR ) test26t SQL_NTS)

SQLRETURNSQLCHARSQLCHARSQLCHARchar

SQLCHAR

rc = SQL_SUCCESSDBName[10] = TPLXSQLStmt[255]c[10]ptrcurrentDepartment[8][15] = Head Office

New England Mid Atlantic South Atlantic Great Lakes PlainsPacificMountain

Create An Instance Of The CLI_Class ClassCLI_Class Example

Connect To iSeries Database if (ExampleConHandle = NULL)

rc = SQLConnect(ExampleConHandle DBName SQL_NTS

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)ExampleprintError(ExampleConHandle SQL_NULL_HSTMT)

return(rc)

cout ltlt Successfully connected to ltlt DBName ltlt ltlt endlrc = SQLSetConnectAttr(ExampleConHandle SQL_ATTR_AUTOCOMMIT

(SQLPOINTER) SQL_AUTOCOMMIT_OFF SQL_IS_UINTEGER) Allocate An SQL Statement Handlerc = SQLAllocHandle(SQL_HANDLE_STMT ExampleConHandle

ampExampleStmtHandle)if (rc == SQL_SUCCESS)

Define A SELECT SQL Statement

strcpy((char ) SQLStmt select name job salary + ifnull(comm0) ascompensation )

ptr = strcat( (char ) SQLStmt from org o staff s )ptr = strcat( (char ) SQLStmt where odeptnumb = sdept)ptr = strcat( (char ) SQLStmt and deptname = )ptr = strcat( (char ) SQLStmt order by compensation desc)

Prepare The SQL Statementrc = SQLPrepare(ExampleStmtHandle SQLStmt SQL_NTS)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)ExampleprintError(ExampleConHandle ExampleStmtHandle)

54

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

return(rc)

Bind The Columns In The Result Data Set Returned To Application Variables

rc = SQLBindCol(ExampleStmtHandle 1 SQL_C_CHAR (SQLPOINTER)ExampleName sizeof(ExampleName) NULL)

rc = SQLBindCol(ExampleStmtHandle 2 SQL_C_CHAR (SQLPOINTER)ExampleJob sizeof(ExampleJob) NULL)

rc = SQLBindCol(ExampleStmtHandle 3 SQL_C_DOUBLE (SQLPOINTER)ampExampleComp sizeof(ExampleComp) NULL)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO) ExampleprintError(ExampleConHandle ExampleStmtHandle)

return(rc)

while (true)

for (int i = 0 i lt LOOPS i++)

rc=SQLBindParameter(ExampleStmtHandle1SQL_PARAM_INPUTSQL_C_CHARSQL_CHAR

150(SQLPOINTER) currentDepartment[i8]0NULL)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)

ExampleprintError(ExampleConHandle ExampleStmtHandle)return(rc)

rc = SQLExecute(ExampleStmtHandle)if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)

ExampleprintError(ExampleConHandle ExampleStmtHandle)return(rc)

cout ltlt endl ltlt Current Dept ltlt currentDepartment[i8] ltlt

endl Display The Results Of The SQL QueryExampleShowResults()if(rc = 0)break

if ( i500 == 0 ampamp i gt 0 )cout ltlt Loops ltlt i ltlt ltlt endl

cout ltlt AFTER ltlt LOOPS ltlt loops Press X to exit ltlt endlcin gtgt cif (c[0] == x || c[0] == X)

break

Free The SQL Statement Handleif (ExampleStmtHandle = NULL )

SQLFreeHandle(SQL_HANDLE_STMT ExampleStmtHandle) Disconnect From The Northwind Sample Databaserc = SQLDisconnect(ExampleConHandle)

Return To The Operating Systemreturn(rc)

55

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

try ClassforName(comibmdb2jccDB2Driver) [1] catch(javalangClassNotFoundException e) Systemerrprint(ClassNotFoundException )Systemerrprintln(egetMessage())

try DriverManagergetConnection(jdbcdb2teraplex446TERAPLEX[2]

db2userdb2pwd) hellip catch(SQLException ex) Systemerrprintln(

SQLException + exgetMessage())

At [1] an instance of the DB2 JDBC Universal Driver is instantiated Then at [2] the driver is used to obtain a connection to the iSeries server Note the proper form of the database URL required by the driver

Considerations There are several advantages of DB2 JDBC Universal Driver bull Ease of cross-platform development mdash Consistent coding techniques and consistent error

codes and messages bull Ease of deployment mdash Pure Java (no runtime client required) and a single driver for accessing

DB2 on different platforms

The ease of use comes at a price though The iSeries JTOpen driver is optimized for accessing DB2 UDB for iSeries data and it uses native iSeries protocol to communicate with the back-end database server job This usually results in better performance and more-efficient system resources utilization For instance when using the DB2 JDBC Universal Driver to access an iSeries server the executeBatch method results in a single record insert There are also some restrictions when using DB2 Universal JDBC Driver with Type 4 connectivity

bull Support for distributed transactions (JTA) is not enabled bull Driver built-in connection pooling is not supported

Refer to Java application support in DB2 for more details on DB2 JDBC Universal Driver

21

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 Connect data access This section will explore the most important aspects of DB2 Connect ndash iSeries integration - including configuration tips and coding examples

DB2 Connect provides functionality for accessing data stored in DB2 UDB for iSeries as well as DB2 UDB for zOS and DB2 UDB for OS390reg DB2 Connect offers capabilities to access DB2 family members via several SQL interfaces gateway functions such as connection pooling and federated database functionality Many applications supporting the DB2 family of products leverage DB2 Connect as a key middleware component DB2 Connect is offered as separate AIX license products

Enterprise Edition Application Server Edition

In addition to DB2 Connect there are several other DB2 UDB Version 81 products that are supported on AIX

DB2 Universal Database Enterprise Server Edition DB2 Universal Database Workgroup Server Unlimited Edition DB2 Universal Database Workgroup Server Edition DB2 Universal Database Universal Developers Edition All Clients

The DB2 Connect Enterprise Edition functionality is also contained in DB2 Enterprise Server Edition for AIX

22

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 Connect in a nutshell In the scenario described in this paper the DB2 Connect functions contained in DB2 Enterprise Edition for AIX are utilized DB2 Connect Enterprise Edition provides support for both local and remote DB2 clients This is illustrated in Figure 11 Accessing DB2 UDB for iSeries with DB2 Connect

Figure 11 Accessing DB2 UDB for iSeries with DB2 Connect

DB2 Connect implements the Distributed Relational Database Architecturetrade (DRDAreg) to reduce the cost and complexity of accessing data stored in DB2 UDB for iSeries and other DRDA-compliant database servers DRDA defines the rules the protocols and the semantics for accessing distributed data Applications can access data in a distributed relational environment by using SQL statements In a distributed environment the system running the application and sending the SQL requests across the network is called the application requester (AR) A remote database server that executes SQL requests submitted by an application requester is known as the application server (AS) In the example shown in Figure 11 (above) DB2 Connect plays the role of an application requester while DB2 UDB for iSeries is an application server In this case DB2 Connect communicates with the iSeries database through TCPIP The iSeries DRDA application server implementation is based on multiple connection-oriented server jobs running in the QSYSWRK subsystem A DRDA listener job (QRWTLSTN) listens for TCP connect requests on port 446 Once an application requester connects to the listener job the listener wakes up one of the QRWTSRVR prestart jobs and assigns it to a given client connection Any further communication occurs directly between the client application and the QRWTSRVR job

DB2 Connect supports a wide range of programming interfaces that can be used by AIX applications to access the iSeries database Embedded SQL frac34 Both static and dynamic SQL frac34 Various programming languages (Java CC++ Cobol Fortran REXX)

DB2 Call Level Interface (DB2 CLI) ODBC JDBC frac34 DB2 JDBC Type 2 Driver frac34 DB2 JDBC Type 4 Driver (Universal JDBC Driver)

23

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Note that DB2 Connect supports access to DB2 UDB for iSeries through DB2 JDBC Universal driver However for performance and ease of maintenance reasons IBM recommends that Java applications running in AIX use native iSeries Toolbox JDBC driver See the JDBC Data Access section of this paper (above) for more details On the other hand DB2 Connect is a very efficient and robust connectivity option for AIX applications especially in the environments that are not directly supported by the native iSeries JDBC driver Here are several possible scenarios that would require DB2 Connect installed in a AIX partition

Embedded SQL interface is used to access DB2 CLI or ODBC interface is used to access DB2 A single SQL interface is needed to access multiple back end DB2 server Specific DB2 Connect functionality is needed such as distributed join or connection

pooling

Prerequisites One of the DB2 Connect products or DB2 Enterprise Server Edition for AIX V81 is needed Additionally DB2 Application Development Client is required in the AIX partition to compile DB2 applications

For maximum database server stability the developer should install the latest database group PTF (SF99503 for i5OS V5R3) on the iSeries server The Informational APAR ii13348 is keeping track of any fixes relevant to DRDA above and beyond the current database group PTF

DB2 Connect configuration The following example employs i5OS V5R3 and DB2 UDB Enterprise Server Edition for AIX Version 81 FixPak 6

Configuration steps in the iSeries partition The following process lists the necessary steps to be performed on the iSeries server 1) Verify that the TCPIP stack is working correctly It is assumed that the Virtual LAN is used to

communicate with the i5OS partition First obtain the IP address of the iSeries server or its hostname and ping the iSeries server from the AIX partition

2) Create a relational database (RDB) entry for the iSeries database in the i5OS partition If this has already been created it can be displayed by using the DSPRDBDIRE command Make sure that the RDB entry with a location of LOCAL exists on the iSeries server If it does not exist use the ADDRDBDIRE command to add the appropriate RDB entry For example the following command would add an RDB entry named TPLX For simplicity it is recommended that the TCPIP host name and RDB entry remain the same

ADDRDBDIRE RDB(TPLX) RMTLOCNAME(LOCAL)

3) Create a collection called NULLID This is necessary because the utilities shipped with DB2 Connect and DB2 UDB for AIX store their packages in the NULLID collection Since it does not exist by default in the iSeries server you must create it using the following command

CRTLIB LIB(NULLID)

4) Products that support DRDA automatically perform any necessary code page conversions at the receiving system For this to happen both systems need a translation table from their code page to the partner code page The default Coded Character Set Identifier (CCSID) on the iSeries server is 65535 Since DB2 Connect does not have a translation table for this code page the developer needs to change the individual user profiles to contain a CCSID that can be converted properly by DB2 Connect For US English this is 037 For other languages see DB2 Connect Personal Edition Quick Beginning GC09-2967 The following command changes the CCSID for an individual user profile to 037

24

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

CHGUSRPRF userid CCSID(037)

5) Verify that the default port 446 for DRDA service is being used To do this go to the Configure TCPIP menu (CFGTCP) select Configure Related Tables and then select Work with service table entries Verify that the DRDA service is set for port 446

6) The Distributed Data Management (DDM) job must be started for DRDA to work If you want the DDM job to be automatically started whenever TCPIP is started change the attributes of the DDM job using the CHGDDMTCPA command and set the Autostart server parameter to YES

7) If the system administrator chooses not to autostart the server issue the following command to start the DDM server job

STRTCPSVR SERVER(DDM)

8) Make sure that the user profiles that will be used to connect to the iSeries server exist on the server

25

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Configuration steps in the AIX partition The following steps are required for DB2 Connect to be configured in the AIX partition 1) Sign on to the AIX partition as the DB2 administrator 2) Launch Client Configuration Assistant (db2ca from the command prompt) It is assumed that

VNC or an X-Windows server are being used on the workstation so that the db2ca GUI can be properly rendered

3) From the Selected pull-down menu select the Add Database using Wizard option The Select how you want to setup a connection dialog appears Select Manually configure a connection to a database and click Next This is shown in Figure 12

Figure 12 Accessing DB2 UDB for iSeries with DB2 Connect

26

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

4) On the Select a communications protocol choose TCPIP and select The database physical resides on a host or OS400 system Then select the option Connect directly to the server as shown in Figure 13 Click Next

Figure 13 mdash Selecting communications protocol

27

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

5) On the TCPIP tab fill in the host name of the iSeries server The port number should be 446 This is shown in Figure 14 Click Next

Figure 14 mdash Specifying TCPIP communication parameters

28

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

6) On the Database tab fill in the Relational Database name Use the RDB entry name (specified in step 2) in the Configuration steps in the iSeries partition section as shown in Figure 15 Click Next

Figure 15 mdash Specifying the remote database

7) If you plan to use the ODBC applications select Register this database for ODBC as a system data source on the ODBC tab Click Next

29

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

8) On the Specify the node option dialog select OS400 from the Operating System pull-down menu This is shown in Figure 16 Click Finish

Figure 16 mdash Specifying the node options

30

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

9) The Test Connection dialog appears This allows the developer to verify that the connection works Select both CLI and JDBC check boxes You are also prompted for an iSeries user ID and password as shown in Figure 17

Figure 17 mdash Testing the connection

31

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

10) The successful connection to the database server is confirmed by the message box shown in Figure 18

Figure 18 mdash Test Connection results 11) At this time a newly configured database connection should appear in the main DB2

Configuration Assistant window It is recommended that the DB2 utilities are also bound to the iSeries database The bind process creates the necessary SQL packages on the remote database In the main Configuration Assistant window click the TPLX database entry and then select Selected-gtBindhellip

32

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

12) The Bind dialog appears Click Select All and then enter the connection information as shown in Figure 19 Click Bind The Results message box appears This allows the developer to monitor the progress of the binding process Watch for any error and warning messages

Figure 19 mdash Binding the DB2 utilities This concludes the DB2 Connect configuration steps

33

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Accessing DB2 UDB for iSeries from C embedded SQL

As mentioned earlier DB2 Connect allows developers to compile and run embedded SQL applications that access DB2 UDB for iSeries data This section covers implementation details for a C embedded SQL application called cursorsjsqc (see Appendix B for source code)

Prerequisites An embedded SQL application running in an AIX partition will use DB2 Connect services to access DB2 UDB for iSeries therefore the developer needs to make sure that all components listed in section Prerequisites on page 24 are installed The developer also needs to create a remote database connection as described in the DB2 Connect configuration section of this paper on page 24

Static SQL and SQL packages To successfully run against a DB2 UDB for iSeries database an embedded SQL application needs to be first precompiled and bound to the back-end database This process creates an SQL package on the target iSeries server The SQL package contains the access plan information for the SQL statements executed by the application The internal structure of the package as well as the method how its content is used by the SQL runtime to facilitate the access plan reuse is similar to the Extended Dynamic SQL support covered in detail in the Extended Dynamic SQL and Statement Caching section of this paper (on page 9) There are however important differences between the packages created by the extended dynamic SQL support and the packages created for embedded SQL DRDA client applications The extended dynamic SQL packages support dynamic SQL interfaces such as JDBC

that can submit ad hoc SQL statements at the run time The SQL runtime can prepare the dynamic statements and add them to the package On the other hand the DRDA packages are created at the precompile time and contain static SQL In order to add new statements to the package the application needs to be precompiled and rebound again

The extended dynamic SQL package can dynamically grow up to 500MB by allocating new space as required The DRDA packages since they are created at the precompile time have a fix size and do not grow over their life time

Simple embedded SQL application The application is based on a source code provided in the DB2 UDB samples directory typically to be found at homedb2inst1sqllibsamples The cursorsjsqc performs a join between STAFF and ORG tables located in DB2USER schema (library) on the TPLX database server (the source is provided at the end of this paper in Appendix B) The join statement retrieves the DEPTNAME column from ORG NAME column from STAFF and calculates the total compensation for an employee by adding SALARY and COMM columns in STAFF The results are sorted by department name and total compensation Here is the SELECT statement used by the application

SELECT deptname name salary + IFNULL(comm0) as compensationFROM org o staff sWHERE odeptnumb = sdeptORDER BY deptname compensation DESC

The application iterates through the selected records and prints out the data to the standard output device The sample DB2USER schema was created with the following SQL statements

db2 CONNECT TO tplx USER db2user USING mypassworddb2 CALL QSYSCREATE_SQL_SAMPLE(DB2USER)

34

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Make sure that the AIX partition is logged into with the DB2 admin user profile If the defaults were selected at the DB2 installation time this profile name is db2inst1 It is also assumed that DB2USER user exists on the iSeries server and that it has appropriate authority

There are several steps that are required to create an executable for the cursorsjsqc source code First the DB2 PRECOMPILE utility needs to be called The utility creates a bind file that is used to bind the required SQL package to the TPLX database It also converts embedded SQL statements into DB2 run-time API calls and produces a pure C source file that can be processed by an AIX C compiler

db2 CONNECT TO tplx USER db2user USING mypassworddb2 prep cursorsjsqc bindfile

Note that the connect statement is required only if the developer is not already connected to the database on an iSeries server Watch for any error or warning messages returned by the DB2 prep utility The prepare step should produce cursorsjbnd and cursorsjc files in the current directory Now the developer can invoke the bind utility to prepare the statements contained in the bind file and create the package on the target iSeries database server

db2 bind cursorsjbnd

It is assumed that Visual C++ 60 is installed and configured in the AIX partition Refer to the ldquoDeveloping and Porting C and C++ Applications on AIXrdquo redbook for more information on how to use the Visual C++ compiler httpibmcomredbooksabstractssg245674htmlOpen

Use the following commands to compile the C source generated by the precompile utility

xlc -I$INSTHOMEsqllibinclude ndashc cursorsjcxlc ndasho cursorsj cursorsjo -L$INSTHOMEsqlliblib ndashldb2

Run the program from the AIX prompt

cursorsj db2user mypassword

Distributed Join DB2 UDB Version 8 provides core federated server functionality A federated system consists of a DB2 UDB instance that operates as a federated server a database that acts as the federated database one or more data sources and clients (users and applications) that access the database and data sources Federated server permits objects stored in multiple databases to be accessed together in the same query For example a query can refer to a table that resides in DB2 UDB for iSeries and join it to a table stored in DB2 UDB for AIX Such a query would constitute so called distributed join The support for DB2 UDB for iSeries as a federated data source is provided by core federated server functionality directly implemented in DB2 UDB Enterprise Server Edition and DB2 UDB Connect Enterprise Edition All other DB2 UDB family members are also supported directly by core DB2 UDB federated server An additional software product DB2 Information Integratortrade is required to access non-DB2 UDB databases such as Oracle Sybase or Microsoftreg SQL Server Consult the following white papers for a detailed discussion on DB2 federated server support Heterogeneous data access for iSeries applications Version 2 httpibmcomserversenablesiteeducationiborecordhtmlhetdata Fundamentals of IBM DB2 Federated Server and Relational Connect httpwww7bsoftwareibmcomdmddlibrarytecharticle0206purnell0206purnellhtml

35

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Distributed Join Example In this section the steps that are required to configure DB2 UDB for iSeries as a federated data source will be illustrated Then the cursorsjsqc program will be ldquotweakedrdquo so that it executes a distributed join query that accesses data stored on an iSeries server and in the local DB2 UDB for AIX database It is assumed that the developer is familiar with the DB2 federated server concepts

Note Run the following commands from the Command Line Processor prompt Load the utility by executing the db2 command at the AIX prompt 1) First the local DB2 UDB for AIX instance needs to be enabled as a DB2 federated server

This is done by setting the database manager configuration parameter FEDERATED to YES

db2=gt update dbm cfg using FEDERATED YES

The database instance needs to be restarted for the change to take effect

NOTE A federated database is a regular database in a DB2 UDB instance that has the FEDERATED parameter enabled Therefore in this example the SAMPLE database that was created earlier is used as the federated database A new database can also be created using the CREATE DATABASE command

2) Connect to the federated database

db2=gt connect to sample

3) Use the CREATE WRAPPER statement to register a wrapper for the iSeries data source Wrappers are library routines that are used by the federated server to perform operations such as connecting to a data source and retrieving data from it The default wrapper name for DB2 UDB for iSeries is DRDA Here is the command to register the DRDA wrapper

db2=gt create wrapper drda

4) Use the CREATE SERVER statement to register a data source as a server within the federated database The server definition specifies the type and version of the data source and the wrapper used for communications with this data source For the DB2 UDB for iSeries data source the node and the database names are also needed The node and database name parameters have been configured for our TPLX database in the Configuration steps in the AIX partition section (on page 24) Use the following DB2 UDB command to lookup these parameter on the federated server

db2=gt list database directory

In this case the command produced the following output

Database alias = TPLX Database name = DCSE99E1 Node name = NDE9BF76 Database release level = a00 Comment = Directory entry type = Remote Authentication = SERVER Catalog database partition number = -1

36

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Note that the node name is set to NDE9BF76 The name was generated by the Configuration Administrator utility (db2ca)

Here is the command to register the TPLX database as a federated server

db2=gt create server tplx type db2400 version 530 wrapperdrda authorization db2user password mypassword options(nodeNDE9BF76 dbname TPLX)

The command is quite complex so make sure that the syntax is correct

5) Define the user mappings that instructs the federated server what user ID and password should be used when connecting to the iSeries data source

db2=gt create user mapping for user server tplxoptions(remote_authid db2user remote_password mypassword)

Specify the nickname for the iSeries table or view A nickname is an identifier that is used by the federated server to reference an object located at the data source The following command creates a nickname for the STAFF table located in the DB2USER schema on the TPLX database

db2=gt create nickname tplx_staff for tplxdb2userstaff

6) Test the distributed join query

db2=gt SELECT deptname name salary + COALESCE(comm0) ascompensation FROM org o tplx_staff s WHERE odeptnumb =sdept ORDER BY deptname compensation DESC

Note that the native iSeries function IFNULL has been substituted with an equivalent DB2 UDB function COALESCE COALESCE is also supported on iSeries servers For better portability IBM encourages the use of COALESCE rather than IFNULL Note also that the query runs on the federated server rather than on TPLX It accesses the ORG table in the local DB2 UDB for AIX SAMPLE database and the STAFF table that resides in TPLX The federated server performs the necessary distributed join

7) Modify the cursorsjsqc so that it executes a distributed join There are two source code modifications - Change the CONNECT TO statements Now the application needs to connect to the

federated database SAMPLE rather than to TPLX

EXEC SQL CONNECT TO SAMPLEEXEC SQL CONNECT TO SAMPLE USER userid USING passwd

- Modify the select statement so that it performs a distributed join Use the statement (shown in step 6) above Save the new source version as cursordjsqc

- Prepare bind and compile the distributed join version of the program as described in the Simple C embedded SQL application section (on page 34)

db2 prep cursordjsqc bindfiledb2 bind cursordjbndxlc -I$INSTHOMEsqllibinclude ndashc cursordjcxlc ndasho cursordj cursordjo -L$INSTHOMEsqlliblib ndashldb2

37

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

- Run the program from the AIX prompt

cursordj

Connection Pooling and Connection ConcentratorA modern Web-based application typically executes a large number of short-lived transactions Executing a transaction in this environment means establishing a database connection executing a few SQL statements and terminating this connection Creating connections to the database server is a very costly process To reduce the unnecessary workload DB2 Connect implements connection pooling and connection concentrator Connection pooling mechanism allows DB2 Connect to reuse an existing connection infrastructure for subsequent connection requests The connection concentrator is an advanced technology that allows DB2 Connect to serve a potentially very large number of clients with a limited number of database connections This is accomplished by decoupling clients from a particular database connection

Note that currently neither connection pooling nor connection concentrator support DB2 UDB for iSeries Therefore for performance reasons the author strongly recommends that the application server that obtains and drops connections very frequently implements its own database connection pooling mechanism that would assign an existing pooled database connection to a new AIX process or thread

TroubleshootingTroubleshooting a multi-tier application may be a bit tricky because the developer needs to deal with software components that reside in separate partitions The authorrsquos experience shows that two tools are particularly useful for pinning down the potential problem areas The joblog messages for a database server job usually provide enough details to isolate DB2

UDB for iSeries runtime issues The DRDA trace utility provides granular information about the data flow between the AIX

application and the iSeries server job

38

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Job Log MessagesAs mentioned earlier a DB2 client communicates with a corresponding iSeries server job This server job runs the SQL requests on behalf of the client More precisely when a DB2 client submits an SQL statement the statement is passed to a server job that in turn calls the DB2 runtime to execute the statement The results are then reformatted and marshaled to the client The iSeries DRDA server jobs are called QRWTSRVR and they run in the QUSRWRK subsystem At any given time there may be a large number of DRDA server jobs active on the system so the first step is to identify the job that serves the particular client connection The easiest method to accomplish this task is to run the following CL command from the i5OS prompt

WRKOBJLCK OBJ(DB2USER) OBJTYPE(USRPRF)

Here DB2USER is the user profile that is used to connect to the iSeries server Note that a QRWTSRVR job is assigned to a client after the connection has been established so the developer needs to set a breakpoint in the client application below the CONNECT TO statement

Once the Work with Object Locks appears key in 5 (Work with Job) next to the only QRWTSRVR job that should be listed This shows the Work with Job dialog Select option 10 to display the job log for the database server job Now the developer can search the job log for any error messages generated by the DB2 runtime

Sometimes it is also useful to include debug messages in the job log The debug messages are informational messages written to the job log about the implementation of a query They describe query implementation methods such as use of indexes join order ODP implementation (reusable versus non-reusable) and so on The easiest way to instruct the iSeries server to include the debug messages is to call the following stored procedure just after the connection to the iSeries server is established

EXEC SQL call qsysqcmdexc(STRDBGUPDPROD(YES)000000002000000)

A sample of the job log messages with debug messages enabled is shown below in Figure 20

Arrival sequence access was used for file STAFFAccess path suggestion for file STAFFQuery options used to build the OS400 query access plan Ending debug message for query ODP created Blocking used for queryCursor SQLCUR201 opened1 rows fetched from cursor SQLCUR201Row not found for SQLCUR201ODP deleted Cursor SQLCUR201 closedDESCRIBE of prepared statement STMT0201 completed

Figure 20 mdash Joblog with debug messages enabled

So the job log offers fairly detailed information on how the AIX client requests were implemented by the DB2 runtime

39

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 DRDA trace utilityThe DB2 DRDA trace utility (db2drdat) provides detailed information about the data streams exchanged between DB2 Connect and target database server The output file produced by the utility contains send and receive communications buffers TCPIP error messages and SQL Communications Area (SQLCA) information Please refer to lsquoDB2 Connect Userrsquos Guidersquo manual for in-depth discussion of the DRDA trace utility

Accessing DB2 UDB for iSeries from CLI DB2 Call Level Interface (CLI ) is based on the Microsoft Open Database Connectivity (ODBC) specification and the ISO CLI standard The DB2 CLI interface gained popularity among DB2 application providers because the developer can build an ODBC application by simply linking the application with libdb2 library on a UNIX server In other words the developer directly utilizes the DB2 ODBC driver services without a need for an ODBC driver manager Additionally in contrast to embedded SQL the developer does not need to precompile or bind DB2 CLI applications because they use packages provided with DB2 UDB The developer simply compiles and links the application

Prerequisites A DB2 CLI application running in an AIX partition will use DB2 Connect services to access DB2 UDB for iSeries therefore make sure that all components listed in Prerequisites section of this paper on page 24 are installed The developer also needs to create a remote database connection as described in the DB2 Connect configuration section of this paper on page 24

Dynamic SQL and Access Plan Caching A DB2 CLI client application uses the dynamic SQL interface and does not have the capability to utilize the extended dynamic SQL support Therefore it runs lsquopurersquo dynamic SQL statements That does not mean however that the process of parsing validating and optimizing will be repeated for every execution of a given dynamic SQL statement

The DB2 UDB for iSeries database implements an internal object called System-Wide SQL Statement Cache (SWSC) The SWSC can improve the performance of programs using dynamic SQL statements by caching the access plans in a system-wide cache When a dynamic SQL statement is submitted the SQL runtime searches the SWSC to see if this statement has been previously executed If so then DB2 retrieves and reuses the key information associated with the cached statement and thereby the processing time and the resources utilization can be significantly reduced

Simple DB2 CLI C++ ApplicationThis section covers DB2 CLI implementation details for a sample C++ program called testclicpp (the source is provided at the end of this paper in Appendix C) To compile the source with Visual C++ complier use the following command in the AIX partition

xlC ndashI$INSTHOMEsqllibinclude ndashc testclicppxlC ndasho testcli testclio ndashL$INSTHOMEsqlliblib ndashldb2

The application performs a join between STAFF and ORG tables located in DB2USER schema (library) The join statement retrieves the DEPTNAME column from ORG NAME and JOB columns from STAFF and calculates the total compensation for an employee by adding SALARY and COMM columns in STAFF The results are sorted by total compensation The selection criterion is based on the current value of the department name parameter Here is the SELECT statement used by testcli

40

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

select name job salary + coalesce(comm0) as compensationfrom org o staff swhere odeptnumb = sdeptand deptname = order by compensation desc

Figure 21 shows the software components involved in the execution of this sample application

Figure 21 How a DB2 CLI client accesses DB2 UDB on an iSeries server

Although the testcli application is fairly simple it covers some important aspects of efficient CLI programming for DB2 UDB for iSeries

Reusable Open Data Paths (ODPs)An Open Data Path (ODP) definition is an internal i5OS object that is created when certain SQL statements (such as OPEN INSERT UPDATE and DELETE) are executed for the first time in a given job (or connection) The ODP can be thought of as a runtime implementation of an access plan The access plan created at the optimization time provides a recipe or in other words a sequence of steps necessary to execute the statement The ODP on the other hand provides the executable code for all requested IO operations The process of creating new ODP objects is fairly CPU- and IO-intensive so whenever possible the iSeries DB2 runtime tries to reuse existing ODPs For instance a SQLCloseCursor() API call may close the SQL cursor but leave the ODP available to be used the next time the cursor is opened This can significantly reduce the processing and response time in running SQL statements A reusable OPD usually requires 10 to 20 times less CPU resources than a newly created ODP Therefore it is important that the applications employ programming techniques that allow the DB2 runtime to reuse ODPs

With dynamic interfaces such as CLI full opens are avoided by using a prepare once execute many programming paradigm It means that when an SQL statement is going to be executed more than once you should prepare the statement just once and then reuse the prepared

41

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

statements for consecutive executions Although DB2 UDB does try to convert literals to parameter markers so that similar statements can be reused it is a better programming practice to explicitly implement parameter markers That way the chances for reusable ODPs are quite significantly improved The code snippet in Figure 22 illustrates how to implement the prepare once execute many programming technique

Define A SELECT SQL Statementstrcpy((char ) SQLStmt select name job salary + ifnull(comm0) ascompensation )ptr = strcat( (char ) SQLStmt from org o staff s )ptr = strcat( (char ) SQLStmt where odeptnumb = sdept)ptr = strcat( (char ) SQLStmt and deptname = )ptr = strcat( (char ) SQLStmt order by compensation desc) [1]

Prepare The SQL Statementrc = SQLPrepare(ExampleStmtHandle SQLStmt SQL_NTS) [2]

Bind The Columns In The Result Data Set Returned To Application Variablesrc = SQLBindCol(ExampleStmtHandle 1 SQL_C_CHAR (SQLPOINTER)

ExampleName sizeof(ExampleName) NULL)rc = SQLBindCol(ExampleStmtHandle 2 SQL_C_CHAR (SQLPOINTER)

ExampleJob sizeof(ExampleJob) NULL)rc = SQLBindCol(ExampleStmtHandle 3 SQL_C_DOUBLE (SQLPOINTER)

ampExampleComp sizeof(ExampleComp) NULL)

for (int i = 0 i lt LOOPS i++)rc=SQLBindParameter(ExampleStmtHandle

1SQL_PARAM_INPUTSQL_C_CHARSQL_CHAR10(SQLPOINTER) currentDepartment[i8]0NULL) [3]

rc = SQLExecute(ExampleStmtHandle) [4]cout ltlt endl ltlt Current Dept ltlt currentDepartment[i8] ltlt endl Display The Results Of The SQL QueryExampleShowResults()

Figure 22 Use the prepare once execute many programming technique

The error-handling code has been removed for clarity At [1] the statement text is assigned to a variable Note that a parameter marker is used in the WHERE clause The statement is then prepared just once at [2] The current value of the parameter is bound to the prepared statement at [3] The prepared statement is executed at [4] Steps [3] and [4] are repeatedly executed in a for loop

Techniques to Further Improve DB2 CLI Performance Thus far this paper has discussed the techniques used by a sample application to tune the CLI performance However depending on the application architecture other methods of improving CLI performance may be considered

Connection PoolingCurrently the CLI application connecting through DB2 Connect to DB2 UDB for iSeries does not take advantage of the connection pooling mechanism implemented by DB2 Connect Therefore for performance reasons the author strongly recommends that the application server that obtains and drops connections very frequently implements its own database connection pooling mechanism that would assign an existing pooled database connection to a new AIX process or thread

42

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Blocking

For queries which result in returning large data blocks from the iSeries server (usually 32K of data and above) ensure that the database manager configuration parameter RQRIOBLK is set to 32767 This can be done using the Command Line Processor (CLP) as follows

db2 update database manager configuration using RQRIOBLK 32767

TroubleshootingThe experience of the author shows that two tools are particularly useful for pinning down the potential problem areas bull Joblog messages for a database server job usually provides enough details to isolate DB2

runtime issues bull CLI trace utility provides granular information about the data flow between the AIX application

and the database server job

Job Log MessagesThe process of finding and analyzing the job log for a DB2 CLI connection is identical to the process outlined for an embedded SQL application in the Job Log Message section of this paper on page 39

CLI Trace The DB2 CLIODBCJDBC trace utility provides very detailed information about the data streams exchanged between DB2 Connect and target database server Refer to the DB2 Information Center for more information on how to set up and analyze the CLI traces httppublibboulderibmcominfocenterdb2v8luwindexjsptopic=comibmdb2udbdocadc000 7959htm

43

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Trademarks

IBM eServer iSeries AIX AIX 5L i5OS WebSphere DB2 DB2 Universal Database DB2 Connect OS400 zOS OS390 Distributed Relational Database Architecture DRDA and DB2 Information Integration are trademarks or registered trademarks of International Business Machines Corporation in the United States and other countries

Java and all Java-based trademarks are trademarks of Sun Microsystems Inc in the United States other countries or both

Linux is a registered trademark of Linus Torvalds in the United States other countries or both

UNIX is a registered trademark of The Open Group in the United States and other countries

Microsoft and Windows are registered trademarks of Microsoft Corporation in the United States andor other countries

All other registered trademarks and trademarks are properties of their respective owners

IBM makes no commitment to make available any products referred to herein

References in this publication to IBM products or services do not imply that IBM intends to make them available in every country in which IBM operates

Additional Information ITSO offers a Redbook that can be helpful to those who want to learn more about i5OS AIX integration

bull AIX Integration with I5OS on the IBM eServer iSeries Server (SG24-6551)

Jarek Miszczyk is the Senior Software Engineer IBM eServer Solutions Enablement IBM Rochester

[Portions of this white paper reprinted with permission from MC Mag Online published by MC Press LLP httpwwwmcpressonlinecom]

Acknowledgments The author would like to thank the following people for their advice contributions and support on this paper

Bob Bittner IBM Rochester Jon Rush IBM Rochester Prasad Vallurupalli IBM Rochester Neil Willis IBM Rochester

44

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix A Source Listing of TestJDBCjava

package comibmiseriespwdimport javasqlimport javaxnamingimport javautilHashtableimport javautilimport javaxsqlimport comibmas400access

public class TestJDBC public static void main(javalangString[] args)

throws Exception

int numOfLoops = 5000int outerNumOfLoops = 5boolean firstExec = trueConnection conStatement sPreparedStatement psPreparedStatement pstmtdelCallableStatement cstmPreparedStatement pstmtHashtable env = new Hashtable()

envput(ContextINITIAL_CONTEXT_FACTORYcomsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env)Systemoutprintln(Deploying connection pooling data source)deployDataSource() Do the work with connection pooling onlyAS400JDBCConnectionPoolDataSource tkcpds =

(AS400JDBCConnectionPoolDataSource)ctxlookup(jdbcToolkitDataSource) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPool pool = new AS400JDBCConnectionPool(tkcpds) Adds 1 connection to the pool that can be used by theapplication (creates the physical database connections based onthe data source)poolfill(1)Systemoutprintln(nStart timing Toolkit connection pooling)long startTime = SystemcurrentTimeMillis()

for (int i = 0 i lt outerNumOfLoops i++) con = poolgetConnection()consetAutoCommit(false) deleteif ( i == 0)

long startDelete = SystemcurrentTimeMillis()cstm = cstm = conprepareCall(

CALL qsysqcmdexc(CLRPFM FILE(DB2USERCOFFEES) + 000000002800000))

cstmexecuteUpdate()cstmclose()long endDelete = SystemcurrentTimeMillis()Systemoutprintln(Delete all records +

(endDelete - startDelete) + ms elapsed)

45

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

String sqlinstrlong startInsert = SystemcurrentTimeMillis() insert

pstmt =conprepareStatement(INSERT INTO COFFEES VALUES( ))for (int j = 0 j lt numOfLoops j++) pstmtsetString(1 Kona_ + IntegertoString(i))pstmtsetInt(2 150)pstmtsetFloat(3 999f)pstmtsetInt(4 0)pstmtsetInt(5 0)pstmtaddBatch()int [] updateCounts = pstmtexecuteBatch()concommit()pstmtclose()long endInsert = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for + numOfLoops + inserts

+ (endInsert - startInsert)) selectlong startSelect = SystemcurrentTimeMillis()ps = conprepareStatement(SELECT FROM COFFEES)ResultSet rs = psexecuteQuery()rsnext()rsclose()concommit()psclose()long endSelect = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for select +

(endSelect - startSelect))consetAutoCommit(true)conclose()long endTime = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for + outerNumOfLoops +

loops + (endTime - startTime))Systemexit(0)

private static void deployDataSource()throws ExceptionString serverName = teraplex String databaseName = TERAPLEX String userName = db2user String password = db2pwd

Establish a JNDI context and bind the connection pool data sourceHashtable env = new Hashtable()envput(ContextINITIAL_CONTEXT_FACTORY

comsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPoolDataSource tkcpds = new

AS400JDBCConnectionPoolDataSource()tkcpdssetServerName(serverName) tkcpdssetDatabaseName(databaseName) tkcpdssetUser(userName) tkcpdssetPassword(password) tkcpdssetDescription(Toolkit Connection Pooling DataSource)tkcpdssetSavePasswordWhenSerialized(true)tkcpdssetExtendedDynamic(true)

46

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

tkcpdssetPackage(JDBCDS)tkcpdssetPackageCache(true)tkcpdssetPackageCriteria(select)enable the following properties as requiredcpdssetTrace(true)tkcpdssetServerTraceCategories( AS400JDBCDataSourceSERVER_TRACE_DEBUG_SERVER_JOB)

ctxrebind(jdbcToolkitDataSource tkcpds)

47

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix B mdash Source Listing of cursorsjsqc

Source File Name = cursorsjsqc Licensed Materials - Property of IBM (C) COPYRIGHT International Business Machines Corp 1995 2000 2004 All Rights Reserved US Government Users Restricted Rights - Use duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp PURPOSE This sample program demonstrates the use of a CURSOR The CURSOR is processed using static SQL EXTERNAL DEPENDENCIES - Ensure existence of database for precompile purposes - Precompile with the SQL precompiler (PREP in DB2) - Bind to a database (BIND in DB2) - Compile and link with the IBM Cset++ compiler (AIX and OS2) or the Microsoft Visual C++ compiler (Windows) or the compiler supported on your platform For more information about these samples see the README file For more information on programming in C see the - Programming in C and C++ section of the Application Development Guide For more information on building C applications see the - Building C Applications section of the Application Building Guide For more information on the SQL language see the SQL Reference

include ltstdiohgt include ltstdlibhgt include ltstringhgtinclude ltsqlhgtinclude ltsqlenvhgtinclude ltsqldahgtinclude ltsqlcahgt

int SqlInfoPrint( char struct sqlca int char )void TransRollback( void)

define EMB_SQL_CHECK( MSG_STR ) rc = SqlInfoPrint( MSG_STR ampsqlca __LINE__ __FILE__) if ( rc = 0 ) TransRollback( )

return 1

EXEC SQL INCLUDE SQLCA

int main(int argc char argv[])

EXEC SQL BEGIN DECLARE SECTIONchar dname[15]

48

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

char pname[10]double compchar userid[9]char passwd[19]

EXEC SQL END DECLARE SECTION

int rc = 0printf( Sample C program CURSORSJ n )if (argc == 1)

EXEC SQL CONNECT TO TPLXEMB_SQL_CHECK(CONNECT TO TPLX)

else if (argc == 3)

strcpy (userid argv[1])strcpy (passwd argv[2])EXEC SQL CONNECT TO TPLX USER userid USING passwdEMB_SQL_CHECK(CONNECT TO TPLX)

else

printf (nUSAGE cursor [userid passwd]nn)return 1

endif

EXEC SQL DECLARE c1 CURSOR FORselect deptname name salary + ifnull(comm0) as compensationfrom org o staff swhere odeptnumb = sdeptorder by deptname compensation desc

EXEC SQL OPEN c1EMB_SQL_CHECK(OPEN CURSOR)

printf(DEPARTMENT NAME COMPENSn)printf(-----------------------------------n)do

EXEC SQL FETCH c1 INTO dname pname compif (SQLCODE = 0) breakprintf( -1515s -1010s 72fn dname pname comp )

while ( 1 )

EXEC SQL CLOSE c1EMB_SQL_CHECK(CLOSE CURSOR)

EXEC SQL CONNECT RESETEMB_SQL_CHECK(CONNECT RESET)

exit(0)

end of program CURSORSJSQC

int SqlInfoPrint( char appMsgstruct sqlca pSqlcaint linechar file )

int rc = 0char sqlInfo[1024]char sqlInfoToken[1024]char sqlstateMsg[1024]char errorMsg[1024]

if (pSqlca-gtsqlcode = 0 ampamp pSqlca-gtsqlcode = 100)

49

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

strcpy(sqlInfo )if( pSqlca-gtsqlcode lt 0) sprintf( sqlInfoToken n---- error report ----n)

strcat( sqlInfo sqlInfoToken)else sprintf( sqlInfoToken n---- warning report ----n)

strcat( sqlInfo sqlInfoToken) endif

sprintf( sqlInfoToken app message = sn appMsg)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken line = dn line)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken file = sn file)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken SQLCODE = ldn pSqlca-gtsqlcode)strcat( sqlInfo sqlInfoToken)

get error message rc = sqlaintp( errorMsg 1024 80 pSqlca) return code is the length of the errorMsg string if( rc gt 0) sprintf( sqlInfoToken sn errorMsg)

strcat( sqlInfo sqlInfoToken)

get SQLSTATE message rc = sqlogstt( sqlstateMsg 1024 80 pSqlca-gtsqlstate)if (rc == 0) sprintf( sqlInfoToken sn sqlstateMsg)

strcat( sqlInfo sqlInfoToken)

if( pSqlca-gtsqlcode lt 0) sprintf( sqlInfoToken --- end error report ---n)

strcat( sqlInfo sqlInfoToken)printf(s sqlInfo)return 1

else sprintf( sqlInfoToken --- end warning report ---n)

strcat( sqlInfo sqlInfoToken)printf(s sqlInfo)return 0

endif endif

return 0

void TransRollback( ) struct sqlca sqlca

int rc = 0 rollback the transaction printf( nRolling back the transaction n)

EXEC SQL ROLLBACKrc = SqlInfoPrint( ROLLBACK ampsqlca __LINE__ __FILE__)if( rc == 0) printf( The transaction was rolled backn)

50

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

51

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix C mdash Source Listing of testclicpp

Include The Appropriate Header Filesinclude ltsqlclihgtinclude ltsqlcli1hgtinclude ltsqlutilhgtinclude ltsqlenvhgtinclude ltstdiohgt include ltiostreamgt include ltlocalehgt include ltstringhgtdefine SQL_SQLSTATE_SIZE 5define LOOPS 8

using namespace std

Define The CLI_Class Classclass CLI_Class

Attributespublic

SQLHANDLE EnvHandleSQLHANDLE ConHandleSQLHANDLE StmtHandleSQLRETURN rcSQLCHAR Job[6]SQLCHAR Name[10]SQLDOUBLE Comp

Operationspublic

CLI_Class()~CLI_Class()SQLRETURN ShowResults()

Constructor Destructor

SQLRETURN printError( SQLHDBC SQLHSTMT)

Define The Class ConstructorCLI_ClassCLI_Class()

setlocale( LC_ALL )

Initialize The Return Code Variablerc = SQL_SUCCESS

Allocate An Environment Handlerc = SQLAllocHandle(SQL_HANDLE_ENV SQL_NULL_HANDLE ampEnvHandle)

Allocate A Connection Handleif (rc == SQL_SUCCESS)

rc = SQLAllocHandle(SQL_HANDLE_DBC EnvHandle ampConHandle)

Define The Class DestructorCLI_Class~CLI_Class()

Free The Connection Handleif (ConHandle = NULL)

SQLFreeHandle(SQL_HANDLE_DBC ConHandle)

Free The Environment Handle

52

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

if (EnvHandle = NULL)SQLFreeHandle(SQL_HANDLE_ENV EnvHandle)

Define The ShowResults() Member FunctionSQLRETURN CLI_ClassShowResults(void)

While There Are Records In The Result Data Set Generated Retrieve And Display Themcout ltlt Name Job Compensation ltlt endlcout ltlt --------- ------ ------------ ltlt endlcoutsetf(iosleft)coutprecision(2)coutsetf(iosfixed)while (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)

rc = SQLFetch(StmtHandle)if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)

coutwidth(15)cout ltlt Name

coutwidth(10)cout ltlt Job

coutwidth(7)cout ltlt Comp ltltendl

if(rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO ampamp rc = SQL_NO_DATA)printError(ConHandle StmtHandle)

else

rc = 0SQLCloseCursor(StmtHandle)

Return The ODBC API Return Code To The Calling Functionreturn(rc)

SQLRETURN CLI_ClassprintError (SQLHDBC hdbc

SQLHSTMT hstmt)

SQLCHAR buffer[SQL_MAX_MESSAGE_LENGTH + 1]SQLCHAR sqlstate[SQL_SQLSTATE_SIZE + 1]SQLINTEGER sqlcodeSQLSMALLINT lengthSQLRETURN rcwhile ((rc = SQLError(SQL_NULL_HENV hdbc hstmt

sqlstateampsqlcodebufferSQL_MAX_MESSAGE_LENGTH + 1amplength)) == SQL_SUCCESS || rc ==

SQL_SUCCESS_WITH_INFO)

cout ltlt SQLSTATE ltlt sqlstate ltlt endlcout ltlt SQLCODE ltlt sqlcode ltlt endlcout ltlt Error msg ltlt buffer ltlt endl

53

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

cout ltlt----------------------------- ltlt endl ltlt endl

return(SQL_ERROR)

----------------------------------------------------------------- The Main Function -----------------------------------------------------------------int main()

Declare The Local Memory Variables

(SQLCHAR ) db2user SQL_NTS (SQLCHAR ) test26t SQL_NTS)

SQLRETURNSQLCHARSQLCHARSQLCHARchar

SQLCHAR

rc = SQL_SUCCESSDBName[10] = TPLXSQLStmt[255]c[10]ptrcurrentDepartment[8][15] = Head Office

New England Mid Atlantic South Atlantic Great Lakes PlainsPacificMountain

Create An Instance Of The CLI_Class ClassCLI_Class Example

Connect To iSeries Database if (ExampleConHandle = NULL)

rc = SQLConnect(ExampleConHandle DBName SQL_NTS

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)ExampleprintError(ExampleConHandle SQL_NULL_HSTMT)

return(rc)

cout ltlt Successfully connected to ltlt DBName ltlt ltlt endlrc = SQLSetConnectAttr(ExampleConHandle SQL_ATTR_AUTOCOMMIT

(SQLPOINTER) SQL_AUTOCOMMIT_OFF SQL_IS_UINTEGER) Allocate An SQL Statement Handlerc = SQLAllocHandle(SQL_HANDLE_STMT ExampleConHandle

ampExampleStmtHandle)if (rc == SQL_SUCCESS)

Define A SELECT SQL Statement

strcpy((char ) SQLStmt select name job salary + ifnull(comm0) ascompensation )

ptr = strcat( (char ) SQLStmt from org o staff s )ptr = strcat( (char ) SQLStmt where odeptnumb = sdept)ptr = strcat( (char ) SQLStmt and deptname = )ptr = strcat( (char ) SQLStmt order by compensation desc)

Prepare The SQL Statementrc = SQLPrepare(ExampleStmtHandle SQLStmt SQL_NTS)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)ExampleprintError(ExampleConHandle ExampleStmtHandle)

54

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

return(rc)

Bind The Columns In The Result Data Set Returned To Application Variables

rc = SQLBindCol(ExampleStmtHandle 1 SQL_C_CHAR (SQLPOINTER)ExampleName sizeof(ExampleName) NULL)

rc = SQLBindCol(ExampleStmtHandle 2 SQL_C_CHAR (SQLPOINTER)ExampleJob sizeof(ExampleJob) NULL)

rc = SQLBindCol(ExampleStmtHandle 3 SQL_C_DOUBLE (SQLPOINTER)ampExampleComp sizeof(ExampleComp) NULL)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO) ExampleprintError(ExampleConHandle ExampleStmtHandle)

return(rc)

while (true)

for (int i = 0 i lt LOOPS i++)

rc=SQLBindParameter(ExampleStmtHandle1SQL_PARAM_INPUTSQL_C_CHARSQL_CHAR

150(SQLPOINTER) currentDepartment[i8]0NULL)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)

ExampleprintError(ExampleConHandle ExampleStmtHandle)return(rc)

rc = SQLExecute(ExampleStmtHandle)if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)

ExampleprintError(ExampleConHandle ExampleStmtHandle)return(rc)

cout ltlt endl ltlt Current Dept ltlt currentDepartment[i8] ltlt

endl Display The Results Of The SQL QueryExampleShowResults()if(rc = 0)break

if ( i500 == 0 ampamp i gt 0 )cout ltlt Loops ltlt i ltlt ltlt endl

cout ltlt AFTER ltlt LOOPS ltlt loops Press X to exit ltlt endlcin gtgt cif (c[0] == x || c[0] == X)

break

Free The SQL Statement Handleif (ExampleStmtHandle = NULL )

SQLFreeHandle(SQL_HANDLE_STMT ExampleStmtHandle) Disconnect From The Northwind Sample Databaserc = SQLDisconnect(ExampleConHandle)

Return To The Operating Systemreturn(rc)

55

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 Connect data access This section will explore the most important aspects of DB2 Connect ndash iSeries integration - including configuration tips and coding examples

DB2 Connect provides functionality for accessing data stored in DB2 UDB for iSeries as well as DB2 UDB for zOS and DB2 UDB for OS390reg DB2 Connect offers capabilities to access DB2 family members via several SQL interfaces gateway functions such as connection pooling and federated database functionality Many applications supporting the DB2 family of products leverage DB2 Connect as a key middleware component DB2 Connect is offered as separate AIX license products

Enterprise Edition Application Server Edition

In addition to DB2 Connect there are several other DB2 UDB Version 81 products that are supported on AIX

DB2 Universal Database Enterprise Server Edition DB2 Universal Database Workgroup Server Unlimited Edition DB2 Universal Database Workgroup Server Edition DB2 Universal Database Universal Developers Edition All Clients

The DB2 Connect Enterprise Edition functionality is also contained in DB2 Enterprise Server Edition for AIX

22

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 Connect in a nutshell In the scenario described in this paper the DB2 Connect functions contained in DB2 Enterprise Edition for AIX are utilized DB2 Connect Enterprise Edition provides support for both local and remote DB2 clients This is illustrated in Figure 11 Accessing DB2 UDB for iSeries with DB2 Connect

Figure 11 Accessing DB2 UDB for iSeries with DB2 Connect

DB2 Connect implements the Distributed Relational Database Architecturetrade (DRDAreg) to reduce the cost and complexity of accessing data stored in DB2 UDB for iSeries and other DRDA-compliant database servers DRDA defines the rules the protocols and the semantics for accessing distributed data Applications can access data in a distributed relational environment by using SQL statements In a distributed environment the system running the application and sending the SQL requests across the network is called the application requester (AR) A remote database server that executes SQL requests submitted by an application requester is known as the application server (AS) In the example shown in Figure 11 (above) DB2 Connect plays the role of an application requester while DB2 UDB for iSeries is an application server In this case DB2 Connect communicates with the iSeries database through TCPIP The iSeries DRDA application server implementation is based on multiple connection-oriented server jobs running in the QSYSWRK subsystem A DRDA listener job (QRWTLSTN) listens for TCP connect requests on port 446 Once an application requester connects to the listener job the listener wakes up one of the QRWTSRVR prestart jobs and assigns it to a given client connection Any further communication occurs directly between the client application and the QRWTSRVR job

DB2 Connect supports a wide range of programming interfaces that can be used by AIX applications to access the iSeries database Embedded SQL frac34 Both static and dynamic SQL frac34 Various programming languages (Java CC++ Cobol Fortran REXX)

DB2 Call Level Interface (DB2 CLI) ODBC JDBC frac34 DB2 JDBC Type 2 Driver frac34 DB2 JDBC Type 4 Driver (Universal JDBC Driver)

23

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Note that DB2 Connect supports access to DB2 UDB for iSeries through DB2 JDBC Universal driver However for performance and ease of maintenance reasons IBM recommends that Java applications running in AIX use native iSeries Toolbox JDBC driver See the JDBC Data Access section of this paper (above) for more details On the other hand DB2 Connect is a very efficient and robust connectivity option for AIX applications especially in the environments that are not directly supported by the native iSeries JDBC driver Here are several possible scenarios that would require DB2 Connect installed in a AIX partition

Embedded SQL interface is used to access DB2 CLI or ODBC interface is used to access DB2 A single SQL interface is needed to access multiple back end DB2 server Specific DB2 Connect functionality is needed such as distributed join or connection

pooling

Prerequisites One of the DB2 Connect products or DB2 Enterprise Server Edition for AIX V81 is needed Additionally DB2 Application Development Client is required in the AIX partition to compile DB2 applications

For maximum database server stability the developer should install the latest database group PTF (SF99503 for i5OS V5R3) on the iSeries server The Informational APAR ii13348 is keeping track of any fixes relevant to DRDA above and beyond the current database group PTF

DB2 Connect configuration The following example employs i5OS V5R3 and DB2 UDB Enterprise Server Edition for AIX Version 81 FixPak 6

Configuration steps in the iSeries partition The following process lists the necessary steps to be performed on the iSeries server 1) Verify that the TCPIP stack is working correctly It is assumed that the Virtual LAN is used to

communicate with the i5OS partition First obtain the IP address of the iSeries server or its hostname and ping the iSeries server from the AIX partition

2) Create a relational database (RDB) entry for the iSeries database in the i5OS partition If this has already been created it can be displayed by using the DSPRDBDIRE command Make sure that the RDB entry with a location of LOCAL exists on the iSeries server If it does not exist use the ADDRDBDIRE command to add the appropriate RDB entry For example the following command would add an RDB entry named TPLX For simplicity it is recommended that the TCPIP host name and RDB entry remain the same

ADDRDBDIRE RDB(TPLX) RMTLOCNAME(LOCAL)

3) Create a collection called NULLID This is necessary because the utilities shipped with DB2 Connect and DB2 UDB for AIX store their packages in the NULLID collection Since it does not exist by default in the iSeries server you must create it using the following command

CRTLIB LIB(NULLID)

4) Products that support DRDA automatically perform any necessary code page conversions at the receiving system For this to happen both systems need a translation table from their code page to the partner code page The default Coded Character Set Identifier (CCSID) on the iSeries server is 65535 Since DB2 Connect does not have a translation table for this code page the developer needs to change the individual user profiles to contain a CCSID that can be converted properly by DB2 Connect For US English this is 037 For other languages see DB2 Connect Personal Edition Quick Beginning GC09-2967 The following command changes the CCSID for an individual user profile to 037

24

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

CHGUSRPRF userid CCSID(037)

5) Verify that the default port 446 for DRDA service is being used To do this go to the Configure TCPIP menu (CFGTCP) select Configure Related Tables and then select Work with service table entries Verify that the DRDA service is set for port 446

6) The Distributed Data Management (DDM) job must be started for DRDA to work If you want the DDM job to be automatically started whenever TCPIP is started change the attributes of the DDM job using the CHGDDMTCPA command and set the Autostart server parameter to YES

7) If the system administrator chooses not to autostart the server issue the following command to start the DDM server job

STRTCPSVR SERVER(DDM)

8) Make sure that the user profiles that will be used to connect to the iSeries server exist on the server

25

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Configuration steps in the AIX partition The following steps are required for DB2 Connect to be configured in the AIX partition 1) Sign on to the AIX partition as the DB2 administrator 2) Launch Client Configuration Assistant (db2ca from the command prompt) It is assumed that

VNC or an X-Windows server are being used on the workstation so that the db2ca GUI can be properly rendered

3) From the Selected pull-down menu select the Add Database using Wizard option The Select how you want to setup a connection dialog appears Select Manually configure a connection to a database and click Next This is shown in Figure 12

Figure 12 Accessing DB2 UDB for iSeries with DB2 Connect

26

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

4) On the Select a communications protocol choose TCPIP and select The database physical resides on a host or OS400 system Then select the option Connect directly to the server as shown in Figure 13 Click Next

Figure 13 mdash Selecting communications protocol

27

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

5) On the TCPIP tab fill in the host name of the iSeries server The port number should be 446 This is shown in Figure 14 Click Next

Figure 14 mdash Specifying TCPIP communication parameters

28

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

6) On the Database tab fill in the Relational Database name Use the RDB entry name (specified in step 2) in the Configuration steps in the iSeries partition section as shown in Figure 15 Click Next

Figure 15 mdash Specifying the remote database

7) If you plan to use the ODBC applications select Register this database for ODBC as a system data source on the ODBC tab Click Next

29

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

8) On the Specify the node option dialog select OS400 from the Operating System pull-down menu This is shown in Figure 16 Click Finish

Figure 16 mdash Specifying the node options

30

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

9) The Test Connection dialog appears This allows the developer to verify that the connection works Select both CLI and JDBC check boxes You are also prompted for an iSeries user ID and password as shown in Figure 17

Figure 17 mdash Testing the connection

31

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

10) The successful connection to the database server is confirmed by the message box shown in Figure 18

Figure 18 mdash Test Connection results 11) At this time a newly configured database connection should appear in the main DB2

Configuration Assistant window It is recommended that the DB2 utilities are also bound to the iSeries database The bind process creates the necessary SQL packages on the remote database In the main Configuration Assistant window click the TPLX database entry and then select Selected-gtBindhellip

32

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

12) The Bind dialog appears Click Select All and then enter the connection information as shown in Figure 19 Click Bind The Results message box appears This allows the developer to monitor the progress of the binding process Watch for any error and warning messages

Figure 19 mdash Binding the DB2 utilities This concludes the DB2 Connect configuration steps

33

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Accessing DB2 UDB for iSeries from C embedded SQL

As mentioned earlier DB2 Connect allows developers to compile and run embedded SQL applications that access DB2 UDB for iSeries data This section covers implementation details for a C embedded SQL application called cursorsjsqc (see Appendix B for source code)

Prerequisites An embedded SQL application running in an AIX partition will use DB2 Connect services to access DB2 UDB for iSeries therefore the developer needs to make sure that all components listed in section Prerequisites on page 24 are installed The developer also needs to create a remote database connection as described in the DB2 Connect configuration section of this paper on page 24

Static SQL and SQL packages To successfully run against a DB2 UDB for iSeries database an embedded SQL application needs to be first precompiled and bound to the back-end database This process creates an SQL package on the target iSeries server The SQL package contains the access plan information for the SQL statements executed by the application The internal structure of the package as well as the method how its content is used by the SQL runtime to facilitate the access plan reuse is similar to the Extended Dynamic SQL support covered in detail in the Extended Dynamic SQL and Statement Caching section of this paper (on page 9) There are however important differences between the packages created by the extended dynamic SQL support and the packages created for embedded SQL DRDA client applications The extended dynamic SQL packages support dynamic SQL interfaces such as JDBC

that can submit ad hoc SQL statements at the run time The SQL runtime can prepare the dynamic statements and add them to the package On the other hand the DRDA packages are created at the precompile time and contain static SQL In order to add new statements to the package the application needs to be precompiled and rebound again

The extended dynamic SQL package can dynamically grow up to 500MB by allocating new space as required The DRDA packages since they are created at the precompile time have a fix size and do not grow over their life time

Simple embedded SQL application The application is based on a source code provided in the DB2 UDB samples directory typically to be found at homedb2inst1sqllibsamples The cursorsjsqc performs a join between STAFF and ORG tables located in DB2USER schema (library) on the TPLX database server (the source is provided at the end of this paper in Appendix B) The join statement retrieves the DEPTNAME column from ORG NAME column from STAFF and calculates the total compensation for an employee by adding SALARY and COMM columns in STAFF The results are sorted by department name and total compensation Here is the SELECT statement used by the application

SELECT deptname name salary + IFNULL(comm0) as compensationFROM org o staff sWHERE odeptnumb = sdeptORDER BY deptname compensation DESC

The application iterates through the selected records and prints out the data to the standard output device The sample DB2USER schema was created with the following SQL statements

db2 CONNECT TO tplx USER db2user USING mypassworddb2 CALL QSYSCREATE_SQL_SAMPLE(DB2USER)

34

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Make sure that the AIX partition is logged into with the DB2 admin user profile If the defaults were selected at the DB2 installation time this profile name is db2inst1 It is also assumed that DB2USER user exists on the iSeries server and that it has appropriate authority

There are several steps that are required to create an executable for the cursorsjsqc source code First the DB2 PRECOMPILE utility needs to be called The utility creates a bind file that is used to bind the required SQL package to the TPLX database It also converts embedded SQL statements into DB2 run-time API calls and produces a pure C source file that can be processed by an AIX C compiler

db2 CONNECT TO tplx USER db2user USING mypassworddb2 prep cursorsjsqc bindfile

Note that the connect statement is required only if the developer is not already connected to the database on an iSeries server Watch for any error or warning messages returned by the DB2 prep utility The prepare step should produce cursorsjbnd and cursorsjc files in the current directory Now the developer can invoke the bind utility to prepare the statements contained in the bind file and create the package on the target iSeries database server

db2 bind cursorsjbnd

It is assumed that Visual C++ 60 is installed and configured in the AIX partition Refer to the ldquoDeveloping and Porting C and C++ Applications on AIXrdquo redbook for more information on how to use the Visual C++ compiler httpibmcomredbooksabstractssg245674htmlOpen

Use the following commands to compile the C source generated by the precompile utility

xlc -I$INSTHOMEsqllibinclude ndashc cursorsjcxlc ndasho cursorsj cursorsjo -L$INSTHOMEsqlliblib ndashldb2

Run the program from the AIX prompt

cursorsj db2user mypassword

Distributed Join DB2 UDB Version 8 provides core federated server functionality A federated system consists of a DB2 UDB instance that operates as a federated server a database that acts as the federated database one or more data sources and clients (users and applications) that access the database and data sources Federated server permits objects stored in multiple databases to be accessed together in the same query For example a query can refer to a table that resides in DB2 UDB for iSeries and join it to a table stored in DB2 UDB for AIX Such a query would constitute so called distributed join The support for DB2 UDB for iSeries as a federated data source is provided by core federated server functionality directly implemented in DB2 UDB Enterprise Server Edition and DB2 UDB Connect Enterprise Edition All other DB2 UDB family members are also supported directly by core DB2 UDB federated server An additional software product DB2 Information Integratortrade is required to access non-DB2 UDB databases such as Oracle Sybase or Microsoftreg SQL Server Consult the following white papers for a detailed discussion on DB2 federated server support Heterogeneous data access for iSeries applications Version 2 httpibmcomserversenablesiteeducationiborecordhtmlhetdata Fundamentals of IBM DB2 Federated Server and Relational Connect httpwww7bsoftwareibmcomdmddlibrarytecharticle0206purnell0206purnellhtml

35

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Distributed Join Example In this section the steps that are required to configure DB2 UDB for iSeries as a federated data source will be illustrated Then the cursorsjsqc program will be ldquotweakedrdquo so that it executes a distributed join query that accesses data stored on an iSeries server and in the local DB2 UDB for AIX database It is assumed that the developer is familiar with the DB2 federated server concepts

Note Run the following commands from the Command Line Processor prompt Load the utility by executing the db2 command at the AIX prompt 1) First the local DB2 UDB for AIX instance needs to be enabled as a DB2 federated server

This is done by setting the database manager configuration parameter FEDERATED to YES

db2=gt update dbm cfg using FEDERATED YES

The database instance needs to be restarted for the change to take effect

NOTE A federated database is a regular database in a DB2 UDB instance that has the FEDERATED parameter enabled Therefore in this example the SAMPLE database that was created earlier is used as the federated database A new database can also be created using the CREATE DATABASE command

2) Connect to the federated database

db2=gt connect to sample

3) Use the CREATE WRAPPER statement to register a wrapper for the iSeries data source Wrappers are library routines that are used by the federated server to perform operations such as connecting to a data source and retrieving data from it The default wrapper name for DB2 UDB for iSeries is DRDA Here is the command to register the DRDA wrapper

db2=gt create wrapper drda

4) Use the CREATE SERVER statement to register a data source as a server within the federated database The server definition specifies the type and version of the data source and the wrapper used for communications with this data source For the DB2 UDB for iSeries data source the node and the database names are also needed The node and database name parameters have been configured for our TPLX database in the Configuration steps in the AIX partition section (on page 24) Use the following DB2 UDB command to lookup these parameter on the federated server

db2=gt list database directory

In this case the command produced the following output

Database alias = TPLX Database name = DCSE99E1 Node name = NDE9BF76 Database release level = a00 Comment = Directory entry type = Remote Authentication = SERVER Catalog database partition number = -1

36

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Note that the node name is set to NDE9BF76 The name was generated by the Configuration Administrator utility (db2ca)

Here is the command to register the TPLX database as a federated server

db2=gt create server tplx type db2400 version 530 wrapperdrda authorization db2user password mypassword options(nodeNDE9BF76 dbname TPLX)

The command is quite complex so make sure that the syntax is correct

5) Define the user mappings that instructs the federated server what user ID and password should be used when connecting to the iSeries data source

db2=gt create user mapping for user server tplxoptions(remote_authid db2user remote_password mypassword)

Specify the nickname for the iSeries table or view A nickname is an identifier that is used by the federated server to reference an object located at the data source The following command creates a nickname for the STAFF table located in the DB2USER schema on the TPLX database

db2=gt create nickname tplx_staff for tplxdb2userstaff

6) Test the distributed join query

db2=gt SELECT deptname name salary + COALESCE(comm0) ascompensation FROM org o tplx_staff s WHERE odeptnumb =sdept ORDER BY deptname compensation DESC

Note that the native iSeries function IFNULL has been substituted with an equivalent DB2 UDB function COALESCE COALESCE is also supported on iSeries servers For better portability IBM encourages the use of COALESCE rather than IFNULL Note also that the query runs on the federated server rather than on TPLX It accesses the ORG table in the local DB2 UDB for AIX SAMPLE database and the STAFF table that resides in TPLX The federated server performs the necessary distributed join

7) Modify the cursorsjsqc so that it executes a distributed join There are two source code modifications - Change the CONNECT TO statements Now the application needs to connect to the

federated database SAMPLE rather than to TPLX

EXEC SQL CONNECT TO SAMPLEEXEC SQL CONNECT TO SAMPLE USER userid USING passwd

- Modify the select statement so that it performs a distributed join Use the statement (shown in step 6) above Save the new source version as cursordjsqc

- Prepare bind and compile the distributed join version of the program as described in the Simple C embedded SQL application section (on page 34)

db2 prep cursordjsqc bindfiledb2 bind cursordjbndxlc -I$INSTHOMEsqllibinclude ndashc cursordjcxlc ndasho cursordj cursordjo -L$INSTHOMEsqlliblib ndashldb2

37

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

- Run the program from the AIX prompt

cursordj

Connection Pooling and Connection ConcentratorA modern Web-based application typically executes a large number of short-lived transactions Executing a transaction in this environment means establishing a database connection executing a few SQL statements and terminating this connection Creating connections to the database server is a very costly process To reduce the unnecessary workload DB2 Connect implements connection pooling and connection concentrator Connection pooling mechanism allows DB2 Connect to reuse an existing connection infrastructure for subsequent connection requests The connection concentrator is an advanced technology that allows DB2 Connect to serve a potentially very large number of clients with a limited number of database connections This is accomplished by decoupling clients from a particular database connection

Note that currently neither connection pooling nor connection concentrator support DB2 UDB for iSeries Therefore for performance reasons the author strongly recommends that the application server that obtains and drops connections very frequently implements its own database connection pooling mechanism that would assign an existing pooled database connection to a new AIX process or thread

TroubleshootingTroubleshooting a multi-tier application may be a bit tricky because the developer needs to deal with software components that reside in separate partitions The authorrsquos experience shows that two tools are particularly useful for pinning down the potential problem areas The joblog messages for a database server job usually provide enough details to isolate DB2

UDB for iSeries runtime issues The DRDA trace utility provides granular information about the data flow between the AIX

application and the iSeries server job

38

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Job Log MessagesAs mentioned earlier a DB2 client communicates with a corresponding iSeries server job This server job runs the SQL requests on behalf of the client More precisely when a DB2 client submits an SQL statement the statement is passed to a server job that in turn calls the DB2 runtime to execute the statement The results are then reformatted and marshaled to the client The iSeries DRDA server jobs are called QRWTSRVR and they run in the QUSRWRK subsystem At any given time there may be a large number of DRDA server jobs active on the system so the first step is to identify the job that serves the particular client connection The easiest method to accomplish this task is to run the following CL command from the i5OS prompt

WRKOBJLCK OBJ(DB2USER) OBJTYPE(USRPRF)

Here DB2USER is the user profile that is used to connect to the iSeries server Note that a QRWTSRVR job is assigned to a client after the connection has been established so the developer needs to set a breakpoint in the client application below the CONNECT TO statement

Once the Work with Object Locks appears key in 5 (Work with Job) next to the only QRWTSRVR job that should be listed This shows the Work with Job dialog Select option 10 to display the job log for the database server job Now the developer can search the job log for any error messages generated by the DB2 runtime

Sometimes it is also useful to include debug messages in the job log The debug messages are informational messages written to the job log about the implementation of a query They describe query implementation methods such as use of indexes join order ODP implementation (reusable versus non-reusable) and so on The easiest way to instruct the iSeries server to include the debug messages is to call the following stored procedure just after the connection to the iSeries server is established

EXEC SQL call qsysqcmdexc(STRDBGUPDPROD(YES)000000002000000)

A sample of the job log messages with debug messages enabled is shown below in Figure 20

Arrival sequence access was used for file STAFFAccess path suggestion for file STAFFQuery options used to build the OS400 query access plan Ending debug message for query ODP created Blocking used for queryCursor SQLCUR201 opened1 rows fetched from cursor SQLCUR201Row not found for SQLCUR201ODP deleted Cursor SQLCUR201 closedDESCRIBE of prepared statement STMT0201 completed

Figure 20 mdash Joblog with debug messages enabled

So the job log offers fairly detailed information on how the AIX client requests were implemented by the DB2 runtime

39

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

DB2 DRDA trace utilityThe DB2 DRDA trace utility (db2drdat) provides detailed information about the data streams exchanged between DB2 Connect and target database server The output file produced by the utility contains send and receive communications buffers TCPIP error messages and SQL Communications Area (SQLCA) information Please refer to lsquoDB2 Connect Userrsquos Guidersquo manual for in-depth discussion of the DRDA trace utility

Accessing DB2 UDB for iSeries from CLI DB2 Call Level Interface (CLI ) is based on the Microsoft Open Database Connectivity (ODBC) specification and the ISO CLI standard The DB2 CLI interface gained popularity among DB2 application providers because the developer can build an ODBC application by simply linking the application with libdb2 library on a UNIX server In other words the developer directly utilizes the DB2 ODBC driver services without a need for an ODBC driver manager Additionally in contrast to embedded SQL the developer does not need to precompile or bind DB2 CLI applications because they use packages provided with DB2 UDB The developer simply compiles and links the application

Prerequisites A DB2 CLI application running in an AIX partition will use DB2 Connect services to access DB2 UDB for iSeries therefore make sure that all components listed in Prerequisites section of this paper on page 24 are installed The developer also needs to create a remote database connection as described in the DB2 Connect configuration section of this paper on page 24

Dynamic SQL and Access Plan Caching A DB2 CLI client application uses the dynamic SQL interface and does not have the capability to utilize the extended dynamic SQL support Therefore it runs lsquopurersquo dynamic SQL statements That does not mean however that the process of parsing validating and optimizing will be repeated for every execution of a given dynamic SQL statement

The DB2 UDB for iSeries database implements an internal object called System-Wide SQL Statement Cache (SWSC) The SWSC can improve the performance of programs using dynamic SQL statements by caching the access plans in a system-wide cache When a dynamic SQL statement is submitted the SQL runtime searches the SWSC to see if this statement has been previously executed If so then DB2 retrieves and reuses the key information associated with the cached statement and thereby the processing time and the resources utilization can be significantly reduced

Simple DB2 CLI C++ ApplicationThis section covers DB2 CLI implementation details for a sample C++ program called testclicpp (the source is provided at the end of this paper in Appendix C) To compile the source with Visual C++ complier use the following command in the AIX partition

xlC ndashI$INSTHOMEsqllibinclude ndashc testclicppxlC ndasho testcli testclio ndashL$INSTHOMEsqlliblib ndashldb2

The application performs a join between STAFF and ORG tables located in DB2USER schema (library) The join statement retrieves the DEPTNAME column from ORG NAME and JOB columns from STAFF and calculates the total compensation for an employee by adding SALARY and COMM columns in STAFF The results are sorted by total compensation The selection criterion is based on the current value of the department name parameter Here is the SELECT statement used by testcli

40

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

select name job salary + coalesce(comm0) as compensationfrom org o staff swhere odeptnumb = sdeptand deptname = order by compensation desc

Figure 21 shows the software components involved in the execution of this sample application

Figure 21 How a DB2 CLI client accesses DB2 UDB on an iSeries server

Although the testcli application is fairly simple it covers some important aspects of efficient CLI programming for DB2 UDB for iSeries

Reusable Open Data Paths (ODPs)An Open Data Path (ODP) definition is an internal i5OS object that is created when certain SQL statements (such as OPEN INSERT UPDATE and DELETE) are executed for the first time in a given job (or connection) The ODP can be thought of as a runtime implementation of an access plan The access plan created at the optimization time provides a recipe or in other words a sequence of steps necessary to execute the statement The ODP on the other hand provides the executable code for all requested IO operations The process of creating new ODP objects is fairly CPU- and IO-intensive so whenever possible the iSeries DB2 runtime tries to reuse existing ODPs For instance a SQLCloseCursor() API call may close the SQL cursor but leave the ODP available to be used the next time the cursor is opened This can significantly reduce the processing and response time in running SQL statements A reusable OPD usually requires 10 to 20 times less CPU resources than a newly created ODP Therefore it is important that the applications employ programming techniques that allow the DB2 runtime to reuse ODPs

With dynamic interfaces such as CLI full opens are avoided by using a prepare once execute many programming paradigm It means that when an SQL statement is going to be executed more than once you should prepare the statement just once and then reuse the prepared

41

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

statements for consecutive executions Although DB2 UDB does try to convert literals to parameter markers so that similar statements can be reused it is a better programming practice to explicitly implement parameter markers That way the chances for reusable ODPs are quite significantly improved The code snippet in Figure 22 illustrates how to implement the prepare once execute many programming technique

Define A SELECT SQL Statementstrcpy((char ) SQLStmt select name job salary + ifnull(comm0) ascompensation )ptr = strcat( (char ) SQLStmt from org o staff s )ptr = strcat( (char ) SQLStmt where odeptnumb = sdept)ptr = strcat( (char ) SQLStmt and deptname = )ptr = strcat( (char ) SQLStmt order by compensation desc) [1]

Prepare The SQL Statementrc = SQLPrepare(ExampleStmtHandle SQLStmt SQL_NTS) [2]

Bind The Columns In The Result Data Set Returned To Application Variablesrc = SQLBindCol(ExampleStmtHandle 1 SQL_C_CHAR (SQLPOINTER)

ExampleName sizeof(ExampleName) NULL)rc = SQLBindCol(ExampleStmtHandle 2 SQL_C_CHAR (SQLPOINTER)

ExampleJob sizeof(ExampleJob) NULL)rc = SQLBindCol(ExampleStmtHandle 3 SQL_C_DOUBLE (SQLPOINTER)

ampExampleComp sizeof(ExampleComp) NULL)

for (int i = 0 i lt LOOPS i++)rc=SQLBindParameter(ExampleStmtHandle

1SQL_PARAM_INPUTSQL_C_CHARSQL_CHAR10(SQLPOINTER) currentDepartment[i8]0NULL) [3]

rc = SQLExecute(ExampleStmtHandle) [4]cout ltlt endl ltlt Current Dept ltlt currentDepartment[i8] ltlt endl Display The Results Of The SQL QueryExampleShowResults()

Figure 22 Use the prepare once execute many programming technique

The error-handling code has been removed for clarity At [1] the statement text is assigned to a variable Note that a parameter marker is used in the WHERE clause The statement is then prepared just once at [2] The current value of the parameter is bound to the prepared statement at [3] The prepared statement is executed at [4] Steps [3] and [4] are repeatedly executed in a for loop

Techniques to Further Improve DB2 CLI Performance Thus far this paper has discussed the techniques used by a sample application to tune the CLI performance However depending on the application architecture other methods of improving CLI performance may be considered

Connection PoolingCurrently the CLI application connecting through DB2 Connect to DB2 UDB for iSeries does not take advantage of the connection pooling mechanism implemented by DB2 Connect Therefore for performance reasons the author strongly recommends that the application server that obtains and drops connections very frequently implements its own database connection pooling mechanism that would assign an existing pooled database connection to a new AIX process or thread

42

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Blocking

For queries which result in returning large data blocks from the iSeries server (usually 32K of data and above) ensure that the database manager configuration parameter RQRIOBLK is set to 32767 This can be done using the Command Line Processor (CLP) as follows

db2 update database manager configuration using RQRIOBLK 32767

TroubleshootingThe experience of the author shows that two tools are particularly useful for pinning down the potential problem areas bull Joblog messages for a database server job usually provides enough details to isolate DB2

runtime issues bull CLI trace utility provides granular information about the data flow between the AIX application

and the database server job

Job Log MessagesThe process of finding and analyzing the job log for a DB2 CLI connection is identical to the process outlined for an embedded SQL application in the Job Log Message section of this paper on page 39

CLI Trace The DB2 CLIODBCJDBC trace utility provides very detailed information about the data streams exchanged between DB2 Connect and target database server Refer to the DB2 Information Center for more information on how to set up and analyze the CLI traces httppublibboulderibmcominfocenterdb2v8luwindexjsptopic=comibmdb2udbdocadc000 7959htm

43

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Trademarks

IBM eServer iSeries AIX AIX 5L i5OS WebSphere DB2 DB2 Universal Database DB2 Connect OS400 zOS OS390 Distributed Relational Database Architecture DRDA and DB2 Information Integration are trademarks or registered trademarks of International Business Machines Corporation in the United States and other countries

Java and all Java-based trademarks are trademarks of Sun Microsystems Inc in the United States other countries or both

Linux is a registered trademark of Linus Torvalds in the United States other countries or both

UNIX is a registered trademark of The Open Group in the United States and other countries

Microsoft and Windows are registered trademarks of Microsoft Corporation in the United States andor other countries

All other registered trademarks and trademarks are properties of their respective owners

IBM makes no commitment to make available any products referred to herein

References in this publication to IBM products or services do not imply that IBM intends to make them available in every country in which IBM operates

Additional Information ITSO offers a Redbook that can be helpful to those who want to learn more about i5OS AIX integration

bull AIX Integration with I5OS on the IBM eServer iSeries Server (SG24-6551)

Jarek Miszczyk is the Senior Software Engineer IBM eServer Solutions Enablement IBM Rochester

[Portions of this white paper reprinted with permission from MC Mag Online published by MC Press LLP httpwwwmcpressonlinecom]

Acknowledgments The author would like to thank the following people for their advice contributions and support on this paper

Bob Bittner IBM Rochester Jon Rush IBM Rochester Prasad Vallurupalli IBM Rochester Neil Willis IBM Rochester

44

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix A Source Listing of TestJDBCjava

package comibmiseriespwdimport javasqlimport javaxnamingimport javautilHashtableimport javautilimport javaxsqlimport comibmas400access

public class TestJDBC public static void main(javalangString[] args)

throws Exception

int numOfLoops = 5000int outerNumOfLoops = 5boolean firstExec = trueConnection conStatement sPreparedStatement psPreparedStatement pstmtdelCallableStatement cstmPreparedStatement pstmtHashtable env = new Hashtable()

envput(ContextINITIAL_CONTEXT_FACTORYcomsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env)Systemoutprintln(Deploying connection pooling data source)deployDataSource() Do the work with connection pooling onlyAS400JDBCConnectionPoolDataSource tkcpds =

(AS400JDBCConnectionPoolDataSource)ctxlookup(jdbcToolkitDataSource) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPool pool = new AS400JDBCConnectionPool(tkcpds) Adds 1 connection to the pool that can be used by theapplication (creates the physical database connections based onthe data source)poolfill(1)Systemoutprintln(nStart timing Toolkit connection pooling)long startTime = SystemcurrentTimeMillis()

for (int i = 0 i lt outerNumOfLoops i++) con = poolgetConnection()consetAutoCommit(false) deleteif ( i == 0)

long startDelete = SystemcurrentTimeMillis()cstm = cstm = conprepareCall(

CALL qsysqcmdexc(CLRPFM FILE(DB2USERCOFFEES) + 000000002800000))

cstmexecuteUpdate()cstmclose()long endDelete = SystemcurrentTimeMillis()Systemoutprintln(Delete all records +

(endDelete - startDelete) + ms elapsed)

45

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

String sqlinstrlong startInsert = SystemcurrentTimeMillis() insert

pstmt =conprepareStatement(INSERT INTO COFFEES VALUES( ))for (int j = 0 j lt numOfLoops j++) pstmtsetString(1 Kona_ + IntegertoString(i))pstmtsetInt(2 150)pstmtsetFloat(3 999f)pstmtsetInt(4 0)pstmtsetInt(5 0)pstmtaddBatch()int [] updateCounts = pstmtexecuteBatch()concommit()pstmtclose()long endInsert = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for + numOfLoops + inserts

+ (endInsert - startInsert)) selectlong startSelect = SystemcurrentTimeMillis()ps = conprepareStatement(SELECT FROM COFFEES)ResultSet rs = psexecuteQuery()rsnext()rsclose()concommit()psclose()long endSelect = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for select +

(endSelect - startSelect))consetAutoCommit(true)conclose()long endTime = SystemcurrentTimeMillis()Systemoutprintln(Time elapsed for + outerNumOfLoops +

loops + (endTime - startTime))Systemexit(0)

private static void deployDataSource()throws ExceptionString serverName = teraplex String databaseName = TERAPLEX String userName = db2user String password = db2pwd

Establish a JNDI context and bind the connection pool data sourceHashtable env = new Hashtable()envput(ContextINITIAL_CONTEXT_FACTORY

comsunjndifscontextRefFSContextFactory)Context ctx = new InitialContext(env) Create an AS400JDBCConnectionPool objectAS400JDBCConnectionPoolDataSource tkcpds = new

AS400JDBCConnectionPoolDataSource()tkcpdssetServerName(serverName) tkcpdssetDatabaseName(databaseName) tkcpdssetUser(userName) tkcpdssetPassword(password) tkcpdssetDescription(Toolkit Connection Pooling DataSource)tkcpdssetSavePasswordWhenSerialized(true)tkcpdssetExtendedDynamic(true)

46

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

tkcpdssetPackage(JDBCDS)tkcpdssetPackageCache(true)tkcpdssetPackageCriteria(select)enable the following properties as requiredcpdssetTrace(true)tkcpdssetServerTraceCategories( AS400JDBCDataSourceSERVER_TRACE_DEBUG_SERVER_JOB)

ctxrebind(jdbcToolkitDataSource tkcpds)

47

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix B mdash Source Listing of cursorsjsqc

Source File Name = cursorsjsqc Licensed Materials - Property of IBM (C) COPYRIGHT International Business Machines Corp 1995 2000 2004 All Rights Reserved US Government Users Restricted Rights - Use duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp PURPOSE This sample program demonstrates the use of a CURSOR The CURSOR is processed using static SQL EXTERNAL DEPENDENCIES - Ensure existence of database for precompile purposes - Precompile with the SQL precompiler (PREP in DB2) - Bind to a database (BIND in DB2) - Compile and link with the IBM Cset++ compiler (AIX and OS2) or the Microsoft Visual C++ compiler (Windows) or the compiler supported on your platform For more information about these samples see the README file For more information on programming in C see the - Programming in C and C++ section of the Application Development Guide For more information on building C applications see the - Building C Applications section of the Application Building Guide For more information on the SQL language see the SQL Reference

include ltstdiohgt include ltstdlibhgt include ltstringhgtinclude ltsqlhgtinclude ltsqlenvhgtinclude ltsqldahgtinclude ltsqlcahgt

int SqlInfoPrint( char struct sqlca int char )void TransRollback( void)

define EMB_SQL_CHECK( MSG_STR ) rc = SqlInfoPrint( MSG_STR ampsqlca __LINE__ __FILE__) if ( rc = 0 ) TransRollback( )

return 1

EXEC SQL INCLUDE SQLCA

int main(int argc char argv[])

EXEC SQL BEGIN DECLARE SECTIONchar dname[15]

48

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

char pname[10]double compchar userid[9]char passwd[19]

EXEC SQL END DECLARE SECTION

int rc = 0printf( Sample C program CURSORSJ n )if (argc == 1)

EXEC SQL CONNECT TO TPLXEMB_SQL_CHECK(CONNECT TO TPLX)

else if (argc == 3)

strcpy (userid argv[1])strcpy (passwd argv[2])EXEC SQL CONNECT TO TPLX USER userid USING passwdEMB_SQL_CHECK(CONNECT TO TPLX)

else

printf (nUSAGE cursor [userid passwd]nn)return 1

endif

EXEC SQL DECLARE c1 CURSOR FORselect deptname name salary + ifnull(comm0) as compensationfrom org o staff swhere odeptnumb = sdeptorder by deptname compensation desc

EXEC SQL OPEN c1EMB_SQL_CHECK(OPEN CURSOR)

printf(DEPARTMENT NAME COMPENSn)printf(-----------------------------------n)do

EXEC SQL FETCH c1 INTO dname pname compif (SQLCODE = 0) breakprintf( -1515s -1010s 72fn dname pname comp )

while ( 1 )

EXEC SQL CLOSE c1EMB_SQL_CHECK(CLOSE CURSOR)

EXEC SQL CONNECT RESETEMB_SQL_CHECK(CONNECT RESET)

exit(0)

end of program CURSORSJSQC

int SqlInfoPrint( char appMsgstruct sqlca pSqlcaint linechar file )

int rc = 0char sqlInfo[1024]char sqlInfoToken[1024]char sqlstateMsg[1024]char errorMsg[1024]

if (pSqlca-gtsqlcode = 0 ampamp pSqlca-gtsqlcode = 100)

49

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

strcpy(sqlInfo )if( pSqlca-gtsqlcode lt 0) sprintf( sqlInfoToken n---- error report ----n)

strcat( sqlInfo sqlInfoToken)else sprintf( sqlInfoToken n---- warning report ----n)

strcat( sqlInfo sqlInfoToken) endif

sprintf( sqlInfoToken app message = sn appMsg)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken line = dn line)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken file = sn file)strcat( sqlInfo sqlInfoToken)sprintf( sqlInfoToken SQLCODE = ldn pSqlca-gtsqlcode)strcat( sqlInfo sqlInfoToken)

get error message rc = sqlaintp( errorMsg 1024 80 pSqlca) return code is the length of the errorMsg string if( rc gt 0) sprintf( sqlInfoToken sn errorMsg)

strcat( sqlInfo sqlInfoToken)

get SQLSTATE message rc = sqlogstt( sqlstateMsg 1024 80 pSqlca-gtsqlstate)if (rc == 0) sprintf( sqlInfoToken sn sqlstateMsg)

strcat( sqlInfo sqlInfoToken)

if( pSqlca-gtsqlcode lt 0) sprintf( sqlInfoToken --- end error report ---n)

strcat( sqlInfo sqlInfoToken)printf(s sqlInfo)return 1

else sprintf( sqlInfoToken --- end warning report ---n)

strcat( sqlInfo sqlInfoToken)printf(s sqlInfo)return 0

endif endif

return 0

void TransRollback( ) struct sqlca sqlca

int rc = 0 rollback the transaction printf( nRolling back the transaction n)

EXEC SQL ROLLBACKrc = SqlInfoPrint( ROLLBACK ampsqlca __LINE__ __FILE__)if( rc == 0) printf( The transaction was rolled backn)

50

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

51

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

Appendix C mdash Source Listing of testclicpp

Include The Appropriate Header Filesinclude ltsqlclihgtinclude ltsqlcli1hgtinclude ltsqlutilhgtinclude ltsqlenvhgtinclude ltstdiohgt include ltiostreamgt include ltlocalehgt include ltstringhgtdefine SQL_SQLSTATE_SIZE 5define LOOPS 8

using namespace std

Define The CLI_Class Classclass CLI_Class

Attributespublic

SQLHANDLE EnvHandleSQLHANDLE ConHandleSQLHANDLE StmtHandleSQLRETURN rcSQLCHAR Job[6]SQLCHAR Name[10]SQLDOUBLE Comp

Operationspublic

CLI_Class()~CLI_Class()SQLRETURN ShowResults()

Constructor Destructor

SQLRETURN printError( SQLHDBC SQLHSTMT)

Define The Class ConstructorCLI_ClassCLI_Class()

setlocale( LC_ALL )

Initialize The Return Code Variablerc = SQL_SUCCESS

Allocate An Environment Handlerc = SQLAllocHandle(SQL_HANDLE_ENV SQL_NULL_HANDLE ampEnvHandle)

Allocate A Connection Handleif (rc == SQL_SUCCESS)

rc = SQLAllocHandle(SQL_HANDLE_DBC EnvHandle ampConHandle)

Define The Class DestructorCLI_Class~CLI_Class()

Free The Connection Handleif (ConHandle = NULL)

SQLFreeHandle(SQL_HANDLE_DBC ConHandle)

Free The Environment Handle

52

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

if (EnvHandle = NULL)SQLFreeHandle(SQL_HANDLE_ENV EnvHandle)

Define The ShowResults() Member FunctionSQLRETURN CLI_ClassShowResults(void)

While There Are Records In The Result Data Set Generated Retrieve And Display Themcout ltlt Name Job Compensation ltlt endlcout ltlt --------- ------ ------------ ltlt endlcoutsetf(iosleft)coutprecision(2)coutsetf(iosfixed)while (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)

rc = SQLFetch(StmtHandle)if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)

coutwidth(15)cout ltlt Name

coutwidth(10)cout ltlt Job

coutwidth(7)cout ltlt Comp ltltendl

if(rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO ampamp rc = SQL_NO_DATA)printError(ConHandle StmtHandle)

else

rc = 0SQLCloseCursor(StmtHandle)

Return The ODBC API Return Code To The Calling Functionreturn(rc)

SQLRETURN CLI_ClassprintError (SQLHDBC hdbc

SQLHSTMT hstmt)

SQLCHAR buffer[SQL_MAX_MESSAGE_LENGTH + 1]SQLCHAR sqlstate[SQL_SQLSTATE_SIZE + 1]SQLINTEGER sqlcodeSQLSMALLINT lengthSQLRETURN rcwhile ((rc = SQLError(SQL_NULL_HENV hdbc hstmt

sqlstateampsqlcodebufferSQL_MAX_MESSAGE_LENGTH + 1amplength)) == SQL_SUCCESS || rc ==

SQL_SUCCESS_WITH_INFO)

cout ltlt SQLSTATE ltlt sqlstate ltlt endlcout ltlt SQLCODE ltlt sqlcode ltlt endlcout ltlt Error msg ltlt buffer ltlt endl

53

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

cout ltlt----------------------------- ltlt endl ltlt endl

return(SQL_ERROR)

----------------------------------------------------------------- The Main Function -----------------------------------------------------------------int main()

Declare The Local Memory Variables

(SQLCHAR ) db2user SQL_NTS (SQLCHAR ) test26t SQL_NTS)

SQLRETURNSQLCHARSQLCHARSQLCHARchar

SQLCHAR

rc = SQL_SUCCESSDBName[10] = TPLXSQLStmt[255]c[10]ptrcurrentDepartment[8][15] = Head Office

New England Mid Atlantic South Atlantic Great Lakes PlainsPacificMountain

Create An Instance Of The CLI_Class ClassCLI_Class Example

Connect To iSeries Database if (ExampleConHandle = NULL)

rc = SQLConnect(ExampleConHandle DBName SQL_NTS

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)ExampleprintError(ExampleConHandle SQL_NULL_HSTMT)

return(rc)

cout ltlt Successfully connected to ltlt DBName ltlt ltlt endlrc = SQLSetConnectAttr(ExampleConHandle SQL_ATTR_AUTOCOMMIT

(SQLPOINTER) SQL_AUTOCOMMIT_OFF SQL_IS_UINTEGER) Allocate An SQL Statement Handlerc = SQLAllocHandle(SQL_HANDLE_STMT ExampleConHandle

ampExampleStmtHandle)if (rc == SQL_SUCCESS)

Define A SELECT SQL Statement

strcpy((char ) SQLStmt select name job salary + ifnull(comm0) ascompensation )

ptr = strcat( (char ) SQLStmt from org o staff s )ptr = strcat( (char ) SQLStmt where odeptnumb = sdept)ptr = strcat( (char ) SQLStmt and deptname = )ptr = strcat( (char ) SQLStmt order by compensation desc)

Prepare The SQL Statementrc = SQLPrepare(ExampleStmtHandle SQLStmt SQL_NTS)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)ExampleprintError(ExampleConHandle ExampleStmtHandle)

54

Accessing DB2 UDB for iSeries data from AIX Applications - Optimize AIX access to your DB2 UDB for iSeries database

return(rc)

Bind The Columns In The Result Data Set Returned To Application Variables

rc = SQLBindCol(ExampleStmtHandle 1 SQL_C_CHAR (SQLPOINTER)ExampleName sizeof(ExampleName) NULL)

rc = SQLBindCol(ExampleStmtHandle 2 SQL_C_CHAR (SQLPOINTER)ExampleJob sizeof(ExampleJob) NULL)

rc = SQLBindCol(ExampleStmtHandle 3 SQL_C_DOUBLE (SQLPOINTER)ampExampleComp sizeof(ExampleComp) NULL)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO) ExampleprintError(ExampleConHandle ExampleStmtHandle)

return(rc)

while (true)

for (int i = 0 i lt LOOPS i++)

rc=SQLBindParameter(ExampleStmtHandle1SQL_PARAM_INPUTSQL_C_CHARSQL_CHAR

150(SQLPOINTER) currentDepartment[i8]0NULL)

if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)

ExampleprintError(ExampleConHandle ExampleStmtHandle)return(rc)

rc = SQLExecute(ExampleStmtHandle)if (rc = SQL_SUCCESS ampamp rc = SQL_SUCCESS_WITH_INFO)

ExampleprintError(ExampleConHandle ExampleStmtHandle)return(rc)

cout ltlt endl ltlt Current Dept ltlt currentDepartment[i8] ltlt

endl Display The Results Of The SQL QueryExampleShowResults()if(rc = 0)break

if ( i500 == 0 ampamp i gt 0 )cout ltlt Loops ltlt i ltlt ltlt endl

cout ltlt AFTER ltlt LOOPS ltlt loops Press X to exit ltlt endlcin gtgt cif (c[0] == x || c[0] == X)

break

Free The SQL Statement Handleif (ExampleStmtHandle = NULL )

SQLFreeHandle(SQL_HANDLE_STMT ExampleStmtHandle) Disconnect From The Northwind Sample Databaserc = SQLDisconnect(ExampleConHandle)

Return To The Operating Systemreturn(rc)

55