14.01.2013 Views

IBM Informix Developer's Handbook - IBM Redbooks

IBM Informix Developer's Handbook - IBM Redbooks

IBM Informix Developer's Handbook - IBM Redbooks

SHOW MORE
SHOW LESS

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

<strong>IBM</strong> <strong>Informix</strong><br />

Developer’s <strong>Handbook</strong><br />

Learn application development with<br />

supported APIs, drivers, and interfaces<br />

Understand <strong>Informix</strong> supported<br />

programming environments<br />

Follow practical examples to<br />

develop an <strong>Informix</strong> application<br />

ibm.com/redbooks<br />

Front cover<br />

Whei-Jen Chen<br />

Krishna Doddi<br />

Manoj Ghogale<br />

David Jay<br />

Javier Sagrera


International Technical Support Organization<br />

<strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong><br />

October 2010<br />

SG24-7884-00


Note: Before using this information and the product it supports, read the information in<br />

“Notices” on page ix.<br />

First Edition (October 2010)<br />

This edition applies to <strong>IBM</strong> <strong>Informix</strong> Version 11.5.<br />

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

Note to U.S. Government Users Restricted Rights -- Use, duplication or disclosure restricted by GSA ADP<br />

Schedule Contract with <strong>IBM</strong> Corp.


Contents<br />

Notices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ix<br />

Trademarks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . x<br />

Preface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xi<br />

The team who wrote this book . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xi<br />

Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xiii<br />

Now you can become a published author, too! . . . . . . . . . . . . . . . . . . . . . . . . xiii<br />

Comments welcome. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xiv<br />

Stay connected to <strong>IBM</strong> <strong>Redbooks</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xiv<br />

Chapter 1. Introduction to <strong>IBM</strong> <strong>Informix</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1<br />

1.1 Server options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2<br />

1.1.1 <strong>Informix</strong> servers. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2<br />

1.2 <strong>Informix</strong> tools for developers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9<br />

1.2.1 <strong>Informix</strong> Connect . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9<br />

1.2.2 <strong>Informix</strong> Client Software Development Kit. . . . . . . . . . . . . . . . . . . . . . 9<br />

1.2.3 4GL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15<br />

1.2.4 Ruby on Rails . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15<br />

1.2.5 <strong>Informix</strong> DataBlade Developers Kit . . . . . . . . . . . . . . . . . . . . . . . . . . 15<br />

1.2.6 <strong>Informix</strong> Spatial DataBlade . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16<br />

1.2.7 PHP on <strong>Informix</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17<br />

1.3 <strong>Informix</strong> overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17<br />

1.3.1 Architecture overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18<br />

1.3.2 <strong>Informix</strong> developer environment . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21<br />

1.3.3 <strong>Informix</strong> capabilities. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22<br />

Chapter 2. Setting up an <strong>Informix</strong> development environment . . . . . . . . . 25<br />

2.1 Server setup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26<br />

2.1.1 Planning for the installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26<br />

2.1.2 Installing <strong>Informix</strong> Server. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26<br />

2.1.3 Configuring <strong>Informix</strong> Server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27<br />

2.2 Client setup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34<br />

2.2.1 <strong>Informix</strong> Client options. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34<br />

2.2.2 Installing and setting up Client SDK . . . . . . . . . . . . . . . . . . . . . . . . . 36<br />

2.2.3 Setting up <strong>IBM</strong> Data Server drivers. . . . . . . . . . . . . . . . . . . . . . . . . . 43<br />

2.2.4 Setting up <strong>Informix</strong> JDBC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53<br />

Chapter 3. Working with the ODBC driver . . . . . . . . . . . . . . . . . . . . . . . . . 57<br />

3.1 ODBC and <strong>Informix</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58<br />

© Copyright <strong>IBM</strong> Corp. 2010. All rights reserved. iii


3.2 Setup and configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58<br />

3.2.1 <strong>IBM</strong> <strong>Informix</strong> ODBC Driver . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58<br />

3.2.2 <strong>IBM</strong> Data Server Driver for ODBC and CLI. . . . . . . . . . . . . . . . . . . . 70<br />

3.2.3 Verifying connectivity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74<br />

3.3 Developing an ODBC application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75<br />

3.3.1 Connecting to the database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75<br />

3.3.2 Type mapping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79<br />

3.3.3 Performing database operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82<br />

3.3.4 Handling special data types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95<br />

3.3.5 Error handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112<br />

3.3.6 Troubleshooting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117<br />

Chapter 4. Working with ESQL/C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125<br />

4.1 <strong>Informix</strong> ESQL/C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126<br />

4.2 Setup and configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127<br />

4.3 Windows system configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127<br />

4.4 Developing an ESQL/C application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128<br />

4.4.1 Creating an ESQL/C application . . . . . . . . . . . . . . . . . . . . . . . . . . . 128<br />

4.4.2 Performing database operations . . . . . . . . . . . . . . . . . . . . . . . . . . . 133<br />

4.4.3 Data types mapping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141<br />

4.4.4 Handling special data types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142<br />

4.4.5 Exception handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148<br />

4.4.6 Troubleshooting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150<br />

Chapter 5. Working with the JDBC drivers . . . . . . . . . . . . . . . . . . . . . . . . 153<br />

5.1 JDBC drivers for an <strong>Informix</strong> database . . . . . . . . . . . . . . . . . . . . . . . . . . 154<br />

5.1.1 <strong>IBM</strong> <strong>Informix</strong> JDBC Driver . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154<br />

5.1.2 <strong>IBM</strong> Data Server Driver for JDBC and SQLJ . . . . . . . . . . . . . . . . . 156<br />

5.2 Setup and configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157<br />

5.2.1 Configuration. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157<br />

5.2.2 Verify connectivity with <strong>Informix</strong> JDBC Driver . . . . . . . . . . . . . . . . . 158<br />

5.2.3 Verify connectivity with the Data Server Driver . . . . . . . . . . . . . . . . 160<br />

5.3 JDBC type mapping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161<br />

5.4 Performing database operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163<br />

5.4.1 Connection to the database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163<br />

5.4.2 Manipulating data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168<br />

5.5 <strong>Informix</strong> additional features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174<br />

5.5.1 Batch inserts or updates and using ResultSet metadata . . . . . . . . 175<br />

5.5.2 BIGSERIAL data type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 177<br />

5.5.3 <strong>Informix</strong> smart large objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 178<br />

5.5.4 Secure Socket Layer. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182<br />

5.6 Typical errors. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185<br />

5.6.1 Class not found errors. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186<br />

iv <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


5.6.2 Connectivity errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186<br />

5.6.3 Syntax errors. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187<br />

5.7 Tracing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187<br />

5.7.1 <strong>IBM</strong> <strong>Informix</strong> JDBC Driver . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187<br />

5.7.2 <strong>IBM</strong> Data Server Driver for JDBC . . . . . . . . . . . . . . . . . . . . . . . . . . 188<br />

Chapter 6. <strong>IBM</strong> <strong>Informix</strong> with Hibernate . . . . . . . . . . . . . . . . . . . . . . . . . . 189<br />

6.1 Hibernate for Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190<br />

6.1.1 Overview of Hibernate. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190<br />

6.1.2 Hibernate concepts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191<br />

6.2 Setup and configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192<br />

6.2.1 Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192<br />

6.2.2 Configuration. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194<br />

6.3 Using Hibernate with an <strong>Informix</strong> database. . . . . . . . . . . . . . . . . . . . . . . 198<br />

6.3.1 Components of a Hibernate application . . . . . . . . . . . . . . . . . . . . . 198<br />

6.3.2 Working with a Hibernate object . . . . . . . . . . . . . . . . . . . . . . . . . . . 203<br />

6.3.3 Using annotations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211<br />

Chapter 7. Working with <strong>IBM</strong> <strong>Informix</strong> OLE DB Provider. . . . . . . . . . . . . 215<br />

7.1 <strong>IBM</strong> <strong>Informix</strong> OLE DB Provider . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216<br />

7.2 Setup and configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216<br />

7.2.1 Installation and setup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216<br />

7.2.2 Verifying connectivity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217<br />

7.3 Developing an OLE DB application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219<br />

7.3.1 Supported interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220<br />

7.3.2 Connecting to database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221<br />

7.3.3 Type mapping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 222<br />

7.3.4 Cursors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224<br />

7.3.5 Typical database operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225<br />

7.4 Visual Basic, ADO.NET, and SQL Server . . . . . . . . . . . . . . . . . . . . . . . . 237<br />

7.4.1 OLE DB with Visual Basic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 238<br />

7.4.2 ADO.NET and the OLEDB bridge . . . . . . . . . . . . . . . . . . . . . . . . . . 240<br />

7.4.3 SQL Server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 242<br />

7.5 Troubleshooting and tracing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 245<br />

7.5.1 Typical errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 245<br />

7.5.2 Tracing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 248<br />

Chapter 8. Working with .NET data providers. . . . . . . . . . . . . . . . . . . . . . 253<br />

8.1 <strong>Informix</strong> and .NET data providers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254<br />

8.2 Setup and configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254<br />

8.2.1 <strong>IBM</strong> <strong>Informix</strong> .Net Provider . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254<br />

8.2.2 <strong>IBM</strong> Data Server Provider for .NET. . . . . . . . . . . . . . . . . . . . . . . . . 255<br />

8.2.3 Verifying connectivity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 256<br />

8.3 Developing a .NET application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 259<br />

Contents v


8.3.1 Connecting to the database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 259<br />

8.3.2 Data type mapping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 262<br />

8.3.3 Performing database operations . . . . . . . . . . . . . . . . . . . . . . . . . . . 264<br />

8.3.4 Handling <strong>Informix</strong> specific data types . . . . . . . . . . . . . . . . . . . . . . . 276<br />

8.3.5 Troubleshooting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 290<br />

8.3.6 Tracing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291<br />

8.4 Visual Studio Add-In for Visual Studio. . . . . . . . . . . . . . . . . . . . . . . . . . . 293<br />

Chapter 9. Working with PHP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 295<br />

9.1 <strong>Informix</strong> and PHP extensions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 296<br />

9.2 Setup and configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 297<br />

9.2.1 Installing OAT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 297<br />

9.2.2 Verifying the PDO_INFORMIX setup . . . . . . . . . . . . . . . . . . . . . . . 299<br />

9.2.3 Verifying the PDO setup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 299<br />

9.2.4 Verifying connectivity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 300<br />

9.3 Developing a PHP application. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 301<br />

9.3.1 Connecting to a database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 302<br />

9.3.2 Performing database operations . . . . . . . . . . . . . . . . . . . . . . . . . . . 304<br />

9.3.3 Handling complex data types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 310<br />

9.3.4 Working with PHP extensions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 319<br />

9.3.5 Exception handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 324<br />

9.3.6 Troubleshooting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 328<br />

Chapter 10. User-defined routines. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 329<br />

10.1 An overview of UDRs and database extensions . . . . . . . . . . . . . . . . . . 330<br />

10.1.1 Considerations for UDRs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 331<br />

10.1.2 About UDRs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 332<br />

10.1.3 Considerations for extending data types. . . . . . . . . . . . . . . . . . . . 334<br />

10.2 Developing UDRs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336<br />

10.2.1 UDR examples in SQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336<br />

10.2.2 UDRs in Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 340<br />

10.2.3 UDRs in C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 348<br />

10.3 DataBlades and bladelets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 352<br />

10.3.1 Configuration. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 353<br />

10.3.2 <strong>IBM</strong> <strong>Informix</strong> provided DataBlades . . . . . . . . . . . . . . . . . . . . . . . . 357<br />

10.3.3 Developing a bladelet routine . . . . . . . . . . . . . . . . . . . . . . . . . . . . 359<br />

Chapter 11. Working with Ruby on Rails. . . . . . . . . . . . . . . . . . . . . . . . . . 361<br />

11.1 A brief overview of Ruby on Rails . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 362<br />

11.1.1 Architecture of Ruby on Rails . . . . . . . . . . . . . . . . . . . . . . . . . . . . 363<br />

11.1.2 Ruby Driver and Rails Adapter . . . . . . . . . . . . . . . . . . . . . . . . . . . 363<br />

11.2 Setup and configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 364<br />

11.2.1 Ruby <strong>Informix</strong> driver . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 364<br />

11.2.2 Data Server Ruby driver . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 367<br />

vi <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


11.2.3 Rails adapters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 369<br />

11.3 Database operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 373<br />

11.4 Using the Rails Adapter with Ruby <strong>Informix</strong> . . . . . . . . . . . . . . . . . . . . . 384<br />

11.4.1 Creating database objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 384<br />

11.4.2 Creating the Rails application . . . . . . . . . . . . . . . . . . . . . . . . . . . . 385<br />

11.4.3 Modifying the database configuration file . . . . . . . . . . . . . . . . . . . 386<br />

11.4.4 Creating the Rails model and controllers . . . . . . . . . . . . . . . . . . . 387<br />

11.4.5 Starting the Rails web server . . . . . . . . . . . . . . . . . . . . . . . . . . . . 389<br />

11.4.6 Demonstrating website application . . . . . . . . . . . . . . . . . . . . . . . . 389<br />

11.5 Using the Rails Adapter with <strong>IBM</strong>_DB. . . . . . . . . . . . . . . . . . . . . . . . . . 391<br />

11.5.1 Creating the Rails application . . . . . . . . . . . . . . . . . . . . . . . . . . . . 392<br />

11.5.2 Modifying the database configuration file . . . . . . . . . . . . . . . . . . . 392<br />

11.5.3 Creating model, control, and view. . . . . . . . . . . . . . . . . . . . . . . . . 393<br />

11.5.4 Migrating the model. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 394<br />

11.5.5 Starting the Rails web server . . . . . . . . . . . . . . . . . . . . . . . . . . . . 396<br />

11.5.6 Checking the application from website . . . . . . . . . . . . . . . . . . . . . 396<br />

Chapter 12. <strong>Informix</strong> 4GL Web Services . . . . . . . . . . . . . . . . . . . . . . . . . . 399<br />

12.1 Basic concepts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 400<br />

12.1.1 <strong>IBM</strong> <strong>Informix</strong> 4GL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 400<br />

12.1.2 Service-oriented architecture and Web Services . . . . . . . . . . . . . 400<br />

12.1.3 Web Services development . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 400<br />

12.1.4 <strong>Informix</strong> 4GL and Web Services . . . . . . . . . . . . . . . . . . . . . . . . . . 401<br />

12.1.5 Components . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 401<br />

12.2 Setup and configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 402<br />

12.2.1 Prerequisites and supported platforms . . . . . . . . . . . . . . . . . . . . . 402<br />

12.2.2 Environment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 403<br />

12.3 <strong>Informix</strong> 4GL Web Services tools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 404<br />

12.3.1 The w4glc Web Services compiler . . . . . . . . . . . . . . . . . . . . . . . . 404<br />

12.3.2 The w4gl utility . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 406<br />

12.3.3 Web Services Description Language Parser (wsdl_parser) . . . . . 407<br />

12.3.4 I4GL Web Services process . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 409<br />

12.4 Developing a web service with I4GL . . . . . . . . . . . . . . . . . . . . . . . . . . . 409<br />

12.4.1 Example I4GL function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410<br />

12.4.2 Host and application details . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 411<br />

12.4.3 Definition of the web service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 412<br />

12.4.4 Generate the configuration file . . . . . . . . . . . . . . . . . . . . . . . . . . . 416<br />

12.4.5 Deployment of the web service . . . . . . . . . . . . . . . . . . . . . . . . . . . 420<br />

12.4.6 Packaging of the web service . . . . . . . . . . . . . . . . . . . . . . . . . . . . 421<br />

12.4.7 Starting the Axis2 application server. . . . . . . . . . . . . . . . . . . . . . . 422<br />

12.4.8 Consuming the I4GL web service . . . . . . . . . . . . . . . . . . . . . . . . . 422<br />

12.5 Consuming a web service with I4GL . . . . . . . . . . . . . . . . . . . . . . . . . . . 425<br />

12.5.1 Web service to consume. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 425<br />

Contents vii


12.5.2 Compiling the wrapper code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 427<br />

12.5.3 Using the web service from an I4GL application. . . . . . . . . . . . . . 428<br />

12.6 Troubleshooting. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 429<br />

12.6.1 Typical problems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 429<br />

12.6.2 Tracing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 434<br />

Chapter 13. Application development considerations. . . . . . . . . . . . . . . 437<br />

13.1 Concurrency and locking. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 438<br />

13.1.1 Types of locks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 438<br />

13.1.2 Lock duration. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 440<br />

13.1.3 Lock granularity. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 440<br />

13.2 Locking issues and performance. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 445<br />

13.2.1 Deadlocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 446<br />

13.3 Isolation levels. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 447<br />

13.4 Configuration options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 449<br />

13.4.1 Server identification. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 449<br />

13.4.2 Storage space identifiers. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 450<br />

13.4.3 Limiters and limits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 452<br />

13.4.4 Java configuration parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . 457<br />

13.5 Working with your database administrator . . . . . . . . . . . . . . . . . . . . . . 458<br />

13.5.1 Parameters for negotiation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 461<br />

13.5.2 Monitoring isolation levels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 462<br />

13.5.3 Monitoring locks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 463<br />

13.5.4 Monitoring user threads . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 464<br />

Appendix A. Parameters in the onconfig file . . . . . . . . . . . . . . . . . . . . . . 467<br />

Appendix B. Accommodating distributed transactions . . . . . . . . . . . . . 469<br />

B.1 Distributed transactions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 470<br />

B.2 TP/XA Transaction Manager XA Interface Library . . . . . . . . . . . . . . . . . 470<br />

B.3 XA_TOOL ESQL/C sample. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 471<br />

Related publications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 479<br />

<strong>IBM</strong> <strong>Redbooks</strong> publications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 479<br />

Other publications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 479<br />

Online resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 480<br />

How to get <strong>IBM</strong> <strong>Redbooks</strong> publications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 480<br />

Help from <strong>IBM</strong> . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 480<br />

Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 481<br />

viii <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Notices<br />

This information was developed for products and services offered in the U.S.A.<br />

<strong>IBM</strong> may not offer the products, services, or features discussed in this document in other countries. Consult<br />

your local <strong>IBM</strong> representative for information on the products and services currently available in your area.<br />

Any reference to an <strong>IBM</strong> product, program, or service is not intended to state or imply that only that <strong>IBM</strong><br />

product, program, or service may be used. Any functionally equivalent product, program, or service that<br />

does not infringe any <strong>IBM</strong> intellectual property right may be used instead. However, it is the user's<br />

responsibility to evaluate and verify the operation of any non-<strong>IBM</strong> product, program, or service.<br />

<strong>IBM</strong> may have patents or pending patent applications covering subject matter described in this document.<br />

The furnishing of this document does not give you any license to these patents. You can send license<br />

inquiries, in writing, to:<br />

<strong>IBM</strong> Director of Licensing, <strong>IBM</strong> Corporation, North Castle Drive, Armonk, NY 10504-1785 U.S.A.<br />

The following paragraph does not apply to the United Kingdom or any other country where such<br />

provisions are inconsistent with local law: INTERNATIONAL BUSINESS MACHINES CORPORATION<br />

PROVIDES THIS PUBLICATION "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR<br />

IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF NON-INFRINGEMENT,<br />

MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Some states do not allow disclaimer<br />

of express or implied warranties in certain transactions, therefore, this statement may not apply to you.<br />

This information could include technical inaccuracies or typographical errors. Changes are periodically made<br />

to the information herein; these changes will be incorporated in new editions of the publication. <strong>IBM</strong> may<br />

make improvements and/or changes in the product(s) and/or the program(s) described in this publication at<br />

any time without notice.<br />

Any references in this information to non-<strong>IBM</strong> websites are provided for convenience only and do not in any<br />

manner serve as an endorsement of those websites. The materials at those websites are not part of the<br />

materials for this <strong>IBM</strong> product and use of those websites is at your own risk.<br />

<strong>IBM</strong> may use or distribute any of the information you supply in any way it believes appropriate without<br />

incurring any obligation to you.<br />

Information concerning non-<strong>IBM</strong> products was obtained from the suppliers of those products, their published<br />

announcements or other publicly available sources. <strong>IBM</strong> has not tested those products and cannot confirm<br />

the accuracy of performance, compatibility or any other claims related to non-<strong>IBM</strong> products. Questions on<br />

the capabilities of non-<strong>IBM</strong> products should be addressed to the suppliers of those products.<br />

This information contains examples of data and reports used in daily business operations. To illustrate them<br />

as completely as possible, the examples include the names of individuals, companies, brands, and products.<br />

All of these names are fictitious and any similarity to the names and addresses used by an actual business<br />

enterprise is entirely coincidental.<br />

COPYRIGHT LICENSE:<br />

This information contains sample application programs in source language, which illustrate programming<br />

techniques on various operating platforms. You may copy, modify, and distribute these sample programs in<br />

any form without payment to <strong>IBM</strong>, for the purposes of developing, using, marketing or distributing application<br />

programs conforming to the application programming interface for the operating platform for which the<br />

sample programs are written. These examples have not been thoroughly tested under all conditions. <strong>IBM</strong>,<br />

therefore, cannot guarantee or imply reliability, serviceability, or function of these programs.<br />

© Copyright <strong>IBM</strong> Corp. 2010. All rights reserved. ix


Trademarks<br />

<strong>IBM</strong>, the <strong>IBM</strong> logo, and ibm.com are trademarks or registered trademarks of International Business<br />

Machines Corporation in the United States, other countries, or both. These and other <strong>IBM</strong> trademarked<br />

terms are marked on their first occurrence in this information with the appropriate symbol (® or ),<br />

indicating US registered or common law trademarks owned by <strong>IBM</strong> at the time this information was<br />

published. Such trademarks may also be registered or common law trademarks in other countries. A current<br />

list of <strong>IBM</strong> trademarks is available on the Web at http://www.ibm.com/legal/copytrade.shtml<br />

The following terms are trademarks of the International Business Machines Corporation in the United States,<br />

other countries, or both:<br />

AIX®<br />

DataBlade®<br />

DB2 Universal Database<br />

DB2®<br />

developerWorks®<br />

x <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong><br />

Distributed Relational Database<br />

Architecture<br />

DRDA®<br />

<strong>IBM</strong>®<br />

<strong>Informix</strong>®<br />

MQSeries®<br />

The following terms are trademarks of other companies:<br />

Rational®<br />

<strong>Redbooks</strong>®<br />

Redpaper<br />

<strong>Redbooks</strong> (logo) ®<br />

UC2<br />

WebSphere®<br />

Java, and all Java-based trademarks are trademarks of Sun Microsystems, Inc. in the United States, other<br />

countries, or both.<br />

Microsoft, Windows, and the Windows logo are trademarks of Microsoft Corporation in the United States,<br />

other countries, or both.<br />

UNIX is a registered trademark of The Open Group in the United States and other countries.<br />

Linux is a trademark of Linus Torvalds in the United States, other countries, or both.<br />

Other company, product, or service names may be trademarks or service marks of others.


Preface<br />

<strong>IBM</strong>® <strong>Informix</strong>® is a low-administration, easy-to-use, and embeddable database<br />

that is ideal for application development. It supports a wide range of development<br />

platforms, such as Java, .NET, PHP, and web services, enabling developers to<br />

build database applications in the language of their choice. <strong>Informix</strong> is designed<br />

to handle RDBMS data and XML without modification and can be extended<br />

easily to handle new data sets.<br />

This <strong>IBM</strong> <strong>Redbooks</strong>® publication provides fundamentals of <strong>Informix</strong> application<br />

development. It covers the <strong>Informix</strong> Client installation and configuration for<br />

application development environments. It discusses the skills and techniques for<br />

building <strong>Informix</strong> applications with Java, ESQL/C, OLE DB, .NET, PHP, Ruby on<br />

Rails, DataBlade®, and Hibernate.<br />

The book uses code examples to demonstrate how to develop an <strong>Informix</strong><br />

application with various drivers, APIs, and interfaces. It also provides application<br />

development troubleshooting and considerations for performance.<br />

This book is intended for developers who use <strong>IBM</strong> <strong>Informix</strong> for application<br />

development. Although some of the topics that we discuss are highly technical,<br />

the information in the book might also be helpful for managers or database<br />

administrators who are looking to better understand their <strong>Informix</strong> development<br />

environment.<br />

The team who wrote this book<br />

This book was produced by a team of specialists from around the world working<br />

at the International Technical Support Organization, Rochester Center.<br />

Whei-Jen Chen is a Project Leader at the International Technical Support<br />

Organization, San Jose Center. She has extensive experience in application<br />

development, database design and modeling, and DB2® system administration.<br />

Whei-Jen is an <strong>IBM</strong> Certified Solutions Expert in Database Administration and<br />

Application Development, and an <strong>IBM</strong> Certified IT Specialist<br />

© Copyright <strong>IBM</strong> Corp. 2010. All rights reserved. xi


Krishna Doddi (also known as Prasad) has been with <strong>IBM</strong><br />

<strong>Informix</strong> since 1996. He worked in <strong>Informix</strong> Advanced Support<br />

for Client Products. The main products he supported were<br />

<strong>Informix</strong> Client Software Development Kit (Client SDK), mostly<br />

on the Microsoft Windows® platform. After the <strong>IBM</strong> acquisition<br />

in 2001, he moved to DB2 Advanced Support, again in the<br />

Client Products division. After five years in DB2, he moved to<br />

<strong>Informix</strong> QA for <strong>Informix</strong> Client products, including JCC<br />

Common Client and PureQuery. He is currently the contact for <strong>Informix</strong><br />

Integration projects.<br />

xii <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong><br />

Manoj Ghogale is a Tech Lead in the <strong>Informix</strong> team at ISL<br />

India. Manoj has 9 years of industry experience and has been<br />

with <strong>IBM</strong> for 5 years. He has worked on numerous automation<br />

projects and new features of <strong>Informix</strong> Server. He holds a<br />

Bachelor's degree in Engineering from National Institute of<br />

Engineering, Mysore, India.<br />

David Jay is a Staff Software Engineer in the <strong>IBM</strong> North<br />

Americas Technical Support Team, providing advanced<br />

technical support, defect discovery, and support training for<br />

<strong>Informix</strong> products and SolidDB. David joined the <strong>Informix</strong><br />

Support team in September 1996, and has served in various<br />

software and support roles since the 1980’s. He has a<br />

Bachelor of Science from Pennsylvania State University, and<br />

enjoys public speaking assignments whenever he gets them<br />

through Toastmasters and <strong>IBM</strong>.<br />

Javier Sagrera is a software engineer on the Common Client<br />

Technologies (CCT) group. He joined the <strong>Informix</strong> team in 2000<br />

and has over 15 years experience in application development<br />

for <strong>Informix</strong> database servers and <strong>Informix</strong> clients. Currently<br />

based on the <strong>IBM</strong> UK Bedfont Lab in London, he has extensive<br />

knowledge on all the Microsoft® technologies and is<br />

considered as a subject matter expert worldwide on all the<br />

<strong>Informix</strong> development tools.


Acknowledgements<br />

Thanks to the following people for their contributions to this project:<br />

Jacques Roy<br />

Ted Wasserman<br />

Rakeshkumar Naik<br />

Jonathan Leffler<br />

Robert Uleman<br />

Richard Snoke<br />

Guy Bowerman<br />

<strong>IBM</strong> Software Group<br />

Greg Holmes<br />

Alberto Bortolan<br />

Adam Hattrell<br />

<strong>IBM</strong> Bedfont Laboratory<br />

Emma Jacobs<br />

International Technical Support Organization, Rochester Center<br />

Now you can become a published author, too!<br />

Here’s an opportunity to spotlight your skills, grow your career, and become a<br />

published author—all at the same time! Join an ITSO residency project and help<br />

write a book in your area of expertise, while honing your experience using<br />

leading-edge technologies. Your efforts will help to increase product acceptance<br />

and customer satisfaction, as you expand your network of technical contacts and<br />

relationships. Residencies run from two to six weeks, and you can participate<br />

either in person or as a remote resident working from your home base.<br />

Find out more about the residency program, browse the residency index, and<br />

apply online at:<br />

ibm.com/redbooks/residencies.html<br />

Preface xiii


Comments welcome<br />

Your comments are important to us!<br />

We want our books to be as helpful as possible. Send us your comments about<br />

this book or other <strong>IBM</strong> <strong>Redbooks</strong> publications in one of the following ways:<br />

► Use the online Contact us review <strong>Redbooks</strong> form found at:<br />

ibm.com/redbooks<br />

► Send your comments in an email to:<br />

redbooks@us.ibm.com<br />

► Mail your comments to:<br />

<strong>IBM</strong> Corporation, International Technical Support Organization<br />

Dept. HYTD Mail Station P099<br />

2455 South Road<br />

Poughkeepsie, NY 12601-5400<br />

Stay connected to <strong>IBM</strong> <strong>Redbooks</strong><br />

► Find us on Facebook:<br />

http://www.facebook.com/<strong>IBM</strong><strong>Redbooks</strong><br />

► Follow us on Twitter:<br />

http://twitter.com/ibmredbooks<br />

► Look for us on LinkedIn:<br />

http://www.linkedin.com/groups?home=&gid=2130806<br />

► Explore new <strong>Redbooks</strong> publications, residencies, and workshops with the<br />

<strong>IBM</strong> <strong>Redbooks</strong> weekly newsletter:<br />

https://www.redbooks.ibm.com/<strong>Redbooks</strong>.nsf/subscribe?OpenForm<br />

► Stay current on recent <strong>Redbooks</strong> publications with RSS Feeds:<br />

http://www.redbooks.ibm.com/rss.html<br />

xiv <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


1<br />

Chapter 1. Introduction to <strong>IBM</strong> <strong>Informix</strong><br />

We live in a business world that requires a variety of software components to fully<br />

handle the scope of business needs. When considered as a group, the products<br />

have to work together, and they must scale well to cover the demands of<br />

business to assure continued growth. Frequently, a significant criteria list might<br />

be needed to specify all the facets that are encountered in daily, monthly, and<br />

yearly periods of business operations. Developers must be sensitive to how the<br />

database engine functions, what server-side capabilities can be brought into<br />

play, and what development tasks need to occur on the client or application side.<br />

In this chapter, we provide an overview of <strong>Informix</strong> products and capabilities. Our<br />

approach is somewhat reference oriented. In addition to the overview of <strong>Informix</strong><br />

products, we also provide an awareness of the architecture of <strong>IBM</strong> <strong>Informix</strong> from<br />

both the server-side and the client-side, to better acquaint the developer with<br />

perspectives that you might need to know.<br />

We also discuss the capabilities of the products in the <strong>Informix</strong> suite. The <strong>IBM</strong><br />

<strong>Informix</strong> products that we describe demonstrate how to manage business<br />

performance, handle all types of business applications, minimize administration<br />

through various self-automated and self-monitored options and, at all times,<br />

optimize the setup to help minimize costs for maintenance and resource<br />

allocations.<br />

© Copyright <strong>IBM</strong> Corp. 2010. All rights reserved. 1


1.1 Server options<br />

There are a number of options for <strong>IBM</strong> <strong>Informix</strong> servers that are designed to meet<br />

the needs of business enterprises that range in size from a small group with a<br />

few employees up to several thousand people. The database needs to meet a<br />

variety of requirements of a diverse group. This section includes a brief<br />

discussion of each of the server possibilities and how they are generally used.<br />

With the wealth of different server types available, unless otherwise noted, each<br />

comes with the opportunity to use the <strong>IBM</strong> <strong>Informix</strong> Client Software Development<br />

Kit (Client SDK) for development of applications. Prior to renaming the brand<br />

editions in May 2010, <strong>IBM</strong> <strong>Informix</strong> had several versions. You can expect that<br />

each version is backward and forward compatible, beginning with 7.2x and<br />

moving forward through 7.3x, 9.2x, 9.30, 9.40, and 10.00. The Cheetah series<br />

began with <strong>Informix</strong> Dynamic Server 11.10 and quickly advanced into the 11.50<br />

family. At this writing, the <strong>IBM</strong> <strong>Informix</strong> Ultimate series is now available, which<br />

begins with 11.50.xC7 and following.<br />

It is helpful to be aware of version numbering conventions:<br />

► The letters UC or UD at the end of a version number indicate 32-bit UNIX®.<br />

► The letters TC indicate a 32-bit Windows version.<br />

► The letters FC indicate a 64-bit version (UNIX or Windows).<br />

1.1.1 <strong>Informix</strong> servers<br />

These naming conventions become important in application and memory<br />

addressability. A 32-bit application works with a 64-bit server, but the application<br />

can access only 32-bit memory.<br />

Several options are available for <strong>IBM</strong> <strong>Informix</strong> servers. Each option is designed to<br />

address specific needs in business. This section discusses these different<br />

options.<br />

No-charge editions<br />

The following no-charge editions are available as separate offerings subject to<br />

the <strong>IBM</strong> International License Agreement for Non-Warranted Programs (ILAN):<br />

► <strong>Informix</strong> Developer Edition<br />

► <strong>Informix</strong> Innovator-C Edition<br />

2 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


<strong>Informix</strong> Developer Edition<br />

The <strong>Informix</strong> Developer Edition provides all the features of <strong>Informix</strong> at no cost,<br />

when used solely for application development and testing. It can be used for<br />

application development and prototyping with no time limits. Support is available<br />

by way of the <strong>Informix</strong> user community through Internet forums.<br />

<strong>Informix</strong> Developer Edition offers the following application development choices:<br />

► C<br />

► C++<br />

► .NET<br />

► Java<br />

► Ruby on Rails<br />

► Perl<br />

► Python<br />

► PHP<br />

► 4GL<br />

<strong>Informix</strong> Developer Edition supports the following operating systems:<br />

► AIX®<br />

► HP<br />

► UNIX<br />

► Linux®<br />

► Macintosh<br />

► Sun Solaris<br />

► Windows<br />

This <strong>Informix</strong> edition is limited to 1 CPU, 1 GB memory, and 8 GB storage.<br />

<strong>Informix</strong> Developer Edition includes the following bundle:<br />

► <strong>Informix</strong> Client Software Development Kit<br />

► <strong>Informix</strong> DataBlade Developers Kit<br />

► <strong>Informix</strong> Spatial Datablade<br />

<strong>Informix</strong> Innovator-C Edition<br />

The Innovator-C Edition provides a robust and powerful environment that is<br />

designed to support small production workloads. It features the most widely used<br />

data processing functionality, including limited Enterprise Replication and high<br />

availability clustering.<br />

Chapter 1. Introduction to <strong>IBM</strong> <strong>Informix</strong> 3


This edition offers the following application development choices:<br />

► C<br />

► C++<br />

► .NET<br />

► Java<br />

► Ruby on Rails<br />

► Perl<br />

► 4GL<br />

Innovator-C Edition supports the following operating systems:<br />

► AIX<br />

► HP<br />

► UNIX<br />

► Linux<br />

► Macintosh<br />

► Sun Solaris<br />

► Windows<br />

This edition is limited to one socket with no more than four cores and with a total<br />

of 2 GB of RAM that are operating from the same installation.<br />

Note: Innovator-C Edition is an offering to be used for development, test, and<br />

user production workloads without a license fee. This edition can be used only<br />

by user organizations. It cannot be redistributed without signing a<br />

redistribution contract. Support is community-based though an optional<br />

for-charge service and support package is available.<br />

Licensed versions<br />

In a business enterprise that demands constant uptime and consistent delivery<br />

requirements, it helps to have a license and professional, timely support to cover<br />

every need. There are several licensing options available.<br />

In this section, we discuss the <strong>Informix</strong> Server versions that are licensed<br />

subscriptions. Table 1-1 describes the terms and abbreviations for these editions.<br />

The criteria might be subject to change over time. Consult with a sales<br />

representative for the most accurate definitions.<br />

4 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Table 1-1 <strong>Informix</strong> licensed versions<br />

Licensing term Defined<br />

Processor Value Unit<br />

(PVU)<br />

(also known as processor-based<br />

pricing)<br />

Authorized User<br />

Single Install<br />

Calculated using the number of processor cores in the physical server<br />

multiplied by the corresponding value units based on processor<br />

architecture. An unlimited user or connection license and is usually<br />

the optimal choice when the user or session load cannot be controlled<br />

or counted.<br />

A single named user or specific individual accessing one installation<br />

of <strong>Informix</strong> on each physical or virtual server. That authorized user can<br />

establish multiple connections to an <strong>Informix</strong> instance on the server.<br />

Each connection is for the exclusive use of that one authorized user<br />

from a single client device.<br />

Concurrent Session A single logical connection from a client device to an <strong>Informix</strong> instance<br />

on each physical or logical server. Each connection, whether active or<br />

not, requires a license, regardless of whether it comes from one client<br />

device with multiple users or from a single user establishing multiple<br />

connections. The number of concurrent sessions is counted from the<br />

client device, rather than at the server level, regardless of whether the<br />

connection is directly to the <strong>Informix</strong> instance or indirectly or whether<br />

it is through application servers, persistent connectivity layers,<br />

connection multiplexers or concentrators, or any other technology<br />

inserted between the actual user and the <strong>Informix</strong> instance.<br />

Limited Use Socket<br />

(LU Socket)<br />

Available only on <strong>Informix</strong> Growth Edition, this license allows for<br />

licensing on a physical socket potentially containing multiple cores. A<br />

LU Socket license is required for each active processor socket. This<br />

licensing metric can be used only on a physical server with no more<br />

than four physical sockets. You can purchase licenses for up to four<br />

physical sockets and use up to 16 cores.<br />

Install An “Install” is an installed copy of an <strong>Informix</strong> product on a physical<br />

server (or partition thereof) or in a virtual machine image. For<br />

example, if a physical server is segmented into partitions, whether<br />

logical (also know as LPARs) or physical, each partition containing<br />

<strong>Informix</strong> is considered a separate <strong>IBM</strong> <strong>Informix</strong> “Install” for licensing<br />

purposes and restrictions. The concept of an “Install” applies to the<br />

licensing limits specified for all <strong>Informix</strong> Editions.<br />

<strong>Informix</strong> Choice Edition<br />

<strong>Informix</strong> Choice Edition is ideal for small to medium size business. This edition is<br />

available for both Microsoft Windows and Apple Macintosh operating systems.<br />

This edition is limited to a total of eight cores over a maximum of two sockets and<br />

8 GB of RAM operating. The <strong>Informix</strong> Choice Edition includes limited Enterprise<br />

Replication (ER) clustering with 2-root nodes to send or receive data updates<br />

within the cluster. This edition also provides limited high availability (HA) cluster<br />

functionality. Along with the primary server, you can have one secondary node,<br />

Chapter 1. Introduction to <strong>IBM</strong> <strong>Informix</strong> 5


either an HDR secondary or RSS secondary. The HA cluster secondary node<br />

can be used for SQL operations. This edition does not support use of the Shared<br />

Disk secondary (SD secondary) node type.<br />

<strong>Informix</strong> Growth Edition<br />

The <strong>Informix</strong> Growth Edition is available on all platforms (Linux, UNIX, Windows,<br />

and Apple Macintosh). The Growth Edition is ideal for mid-sized companies or<br />

departmental servers in an enterprise deployment. It can be deployed on up to<br />

16 cores over a maximum of four sockets and 16 GB of RAM operating from the<br />

same Install. License options include Authorized User Single Install, Concurrent<br />

Session, PVU, and LU Socket metrics. LU Socket enables licensing by physical<br />

processor socket and is limited to physical servers with no more than four<br />

physical processor sockets.<br />

<strong>Informix</strong> Growth Edition gives you additional database functionality, including<br />

unlimited ER cluster nodes of any type for sending or receiving data updates<br />

within the cluster. From a licensing perspective, because ER nodes are<br />

stand-alone, each ER node must be fully licensed. <strong>Informix</strong> Growth edition<br />

supports up to two HA cluster secondary nodes of any type. As long as the<br />

secondary node or nodes are functioning only as a backup secondary, they can<br />

be deployed without charge. However, if you use a secondary node for SQL<br />

operations (read or write), the secondary node must be fully licensed.<br />

<strong>Informix</strong> Ultimate Edition<br />

The <strong>IBM</strong> <strong>Informix</strong> Ultimate Edition includes nearly all the <strong>Informix</strong> features and<br />

functionality with unlimited scalability required for the highest OLTP and<br />

warehousing performance.<br />

<strong>Informix</strong> Ultimate Edition supports the following operating systems:<br />

► AIX<br />

► HP<br />

► UNIX<br />

► Linux<br />

► Macintosh<br />

► Sun Solaris<br />

► Windows<br />

This edition can be licensed by PVU, Concurrent Session, or Authorized User<br />

Single Install metrics.<br />

With this edition, full HA cluster and ER functionality is available, including<br />

unlimited ER nodes and all HA cluster secondary instance types. From a<br />

licensing perspective, because ER nodes are stand-alone, each ER node must<br />

be fully licensed, but HA secondary nodes can be deployed without charge if they<br />

6 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


are functioning only as a backup secondary. If you use any secondary node for<br />

SQL operations (read or write), the secondary node must be fully licensed.<br />

This edition offers the Geodetic and Excalibur DataBlades add-on.<br />

The Storage Optimization Feature was released with <strong>Informix</strong> version11.5 xC4<br />

and following. The Storage Optimization Feature provides data compression to<br />

dramatically reduce data storage and backup/recovery costs and administration.<br />

The reduced data footprint also provides a significant increase in performance for<br />

data retrieval.<br />

Extended Parallel Server<br />

The <strong>IBM</strong> <strong>Informix</strong> Extended Parallel Server is a high-end database that is<br />

typically used for scalable data warehousing with fast data loading and<br />

comprehensive data management. It is designed for a broad range of enterprises<br />

that require complex, query-intensive analytical applications.<br />

<strong>IBM</strong> <strong>Informix</strong> Extended Parallel Server uses the following examples:<br />

► Reliable data manipulation<br />

► Ad hoc queries from data warehouses<br />

► A combined data warehouse and data mart<br />

► Rapid and concurrent data loading and query execution<br />

<strong>IBM</strong> <strong>Informix</strong> Extended Parallel Server provides full parallel query processing,<br />

while being able to use hardware resources to deliver mainframe-caliber<br />

scalability, manageability, and performance with minimal OS and administrative<br />

overhead. For more information, see Database Strategies: Using <strong>Informix</strong> XPS<br />

and DB2 Universal Database, SG24-6437.<br />

<strong>Informix</strong> OnLine<br />

<strong>IBM</strong> <strong>Informix</strong> OnLine is an easy to use, embeddable relational database server<br />

for low-to-medium workloads.<br />

It has less features and functionality than the <strong>Informix</strong> Ultimate Server, but it<br />

scales well while providing online transaction processing support and the<br />

assurance of data integrity. <strong>Informix</strong> OnLine has rich multimedia data<br />

management capabilities, supporting the storage of a wide range of media such<br />

as documents, images, and audio by way of text and byte columns. Also, it is not<br />

designed to handle extended data types or replication.<br />

This server supports a wide variety of application development tools, along with a<br />

large number of other third-party tools, through support for the ODBC and JDBC<br />

industry standards for client connectivity.<br />

Chapter 1. Introduction to <strong>IBM</strong> <strong>Informix</strong> 7


There are three edition options for this server:<br />

► <strong>Informix</strong> OnLine Extended Edition 5.20<br />

This edition option is a full-featured, easy-to-use SQL database with low<br />

administrative overhead. It contains two popular <strong>Informix</strong> products, <strong>Informix</strong><br />

OnLine and <strong>Informix</strong> STAR, and provides distributed computing with a proven<br />

database server. It allows the Rapid Application Development tools to use<br />

pipes to communicate with OnLine Extended Edition 5.20 servers running on<br />

the same system, instead of having to use a TCP/IP loopback connection with<br />

<strong>Informix</strong> Star or <strong>Informix</strong> Net. It supports greater than 2 GB chunk offsets, to<br />

use the entire capacity of the disk drive without partitioning it into smaller<br />

logical devices and employing logical volume managers.<br />

The operating systems this edition supports include AIX, HP UNIX, and Sun<br />

Solaris.<br />

► <strong>Informix</strong> OnLine Extended Edition for Linux<br />

This edition is same as the <strong>Informix</strong> OnLine Extended Edition 5.20 but is but<br />

only available for Linux.<br />

► <strong>Informix</strong> OnLine Personal Edition<br />

This is the single-user product version, available only on Linux. It provides the<br />

same functionality as <strong>IBM</strong> <strong>Informix</strong> OnLine Extended Edition, at an<br />

economical cost. It enables you to quickly become familiar with the<br />

ease-of-use and multimedia capability of this proven relational database<br />

management system.<br />

Standard Engine<br />

<strong>IBM</strong> <strong>Informix</strong> Standard Engine is an embeddable database server that runs on<br />

UNIX, Linux and Windows. It provides an ideal solution for developing small to<br />

medium-sized applications that need the power of SQL without database<br />

administration requirements (low-maintenance, high-reliability). For limited scale<br />

databases, it delivers excellent performance, adheres to data consistency<br />

standards, and still provides client/server capabilities. It can be seamlessly<br />

integrated with <strong>Informix</strong> application development tools and third-party<br />

development tools compliant with the ODBC and JDBC standards.<br />

This edition supports the following operating systems:<br />

► AIX<br />

► HP UNIX<br />

► Linux<br />

► Sun Solaris<br />

► Windows<br />

8 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


1.2 <strong>Informix</strong> tools for developers<br />

There is a significant list of tools available from <strong>Informix</strong> for developers. We focus<br />

on the available application programming interface (API) options and language<br />

possibilities. There are also other utilities and tools that are provided with the<br />

engine that promote further ease of use.<br />

The 4GL developer’s edition includes the ACE Report Writer, which can be used<br />

to generate forms and reports quickly. The High Performance Loader, onload,<br />

onunload, and External table are bulk load and unload utilities that provide fast<br />

flat file movements. Other tools include I-Spy for auditing, MaxConnect, and the<br />

OpenAdmin Tool (OAT) for remote server administration and SQL.<br />

For more information about these or other tools, consult with a sales<br />

representative or visit the <strong>Informix</strong> support website at:<br />

http://www-947.ibm.com/support/entry/portal/Overview/Software/Information_Manag<br />

ement/<strong>Informix</strong>_Product_Family<br />

1.2.1 <strong>Informix</strong> Connect<br />

<strong>Informix</strong> Connect is the run time version of Client SDK that comes with the server<br />

engine. You use Client SDK and related tools to develop your application. When<br />

it is ready for use in production, <strong>Informix</strong> Connect is the tool used to deploy the<br />

application. It is supplied with the server engine software and provides the<br />

connectivity and runtime libraries which permit interaction between the engine<br />

and the application. While some <strong>Informix</strong> Connect development can be done<br />

without Client SDK, the great majority should be handled through the Client SDK<br />

API.<br />

1.2.2 <strong>Informix</strong> Client Software Development Kit<br />

Client SDK is a package of several APIs that are optimized for developing<br />

applications for <strong>IBM</strong> <strong>Informix</strong> servers. Client SDK allows developers to write<br />

applications in the language they prefer and to build applications that can access<br />

multiple <strong>IBM</strong> <strong>Informix</strong> databases. In this section, we discuss the API packages<br />

that are included in Client SDK.<br />

Open Database Connectivity<br />

Open Database Connectivity (ODBC) is a specification for a database API. It is<br />

based on the Call Level Interface specifications from X/Open and the<br />

International Standards Organization and International Electromechanical<br />

Commission (ISO/IEC). ODBC supports SQL statements with a library of C<br />

Chapter 1. Introduction to <strong>IBM</strong> <strong>Informix</strong> 9


functions. An application calls these functions to implement ODBC functionality.<br />

ODBC applications can perform the following operations:<br />

► Connect to and disconnect from data sources.<br />

► Retrieve information about data sources.<br />

► Retrieve information about the <strong>IBM</strong> <strong>Informix</strong> ODBC Driver.<br />

► Set and retrieve <strong>IBM</strong> <strong>Informix</strong> ODBC Driver options.<br />

► Prepare and send SQL statements.<br />

► Retrieve SQL results and process the results dynamically.<br />

► Retrieve information about SQL results and process the information<br />

dynamically.<br />

ODBC lets you allocate storage before or after the SQL results are available.This<br />

feature lets you determine the results and the action to take without the<br />

limitations that predefined data structures impose. ODBC does not require a<br />

preprocessor to compile an application program. ODBC supports Secure<br />

Sockets Layer (SSL) connections. For information about using the SSL protocol,<br />

see <strong>IBM</strong> <strong>Informix</strong> Version 11.5 Security Guide, SC23-7754.<br />

<strong>Informix</strong> ODBC supports the following additional features and capabilities:<br />

► Microsoft Transaction Server (MTS) environment. For more information about<br />

MTS, see the MTS sections in <strong>IBM</strong> <strong>Informix</strong> ODBC Driver Programmers<br />

Manual, SC23-9423.<br />

► ODBC can handle extended data types such as:<br />

– Collection (LIST, MULTISET, and SET)<br />

– Distinct<br />

– Opaque (fixed, unnamed)<br />

– Row (named, unnamed)<br />

– Smart large objects (BLOB and CLOB)<br />

– Client functions that support extended data types<br />

► Long identifiers<br />

► Global Language Support (GLS) data types (NCHAR,NVARCHAR).<br />

► Support for Unicode and XA.<br />

► IPv6 internet protocol.<br />

10 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


ODBC with the <strong>IBM</strong> <strong>Informix</strong> ODBC Driver can include the following<br />

components:<br />

► Driver manager<br />

An application can link to a driver manager that links to the driver specified by<br />

the data source. The driver manager also checks parameters and transitions.<br />

You can purchase the ODBC Driver Manager from a third-party vendor for<br />

most UNIX platforms. On Microsoft Windows platforms, the ODBC Driver<br />

Manager is a part of the Operating System.<br />

► <strong>IBM</strong> <strong>Informix</strong> ODBC Driver<br />

This driver provides an interface to the <strong>Informix</strong> database server. Applications<br />

can use the driver in the following configurations:<br />

– To link to the ODBC driver manager<br />

– To link to the Driver Manager Replacement and the driver<br />

– To link to the driver directly<br />

► Data sources<br />

The driver provides access to the following data sources:<br />

– Database management systems (DBMS) and database servers<br />

– Databases<br />

– Operating systems and network software required for accessing the<br />

database<br />

JDBC and SQLJ<br />

JDBC is an application programming interface (API) that Java applications use to<br />

access relational databases. <strong>IBM</strong> <strong>Informix</strong> database systems can be supported<br />

by one of two APIs for client applications and applets written in Java:<br />

► <strong>IBM</strong> Data Server Driver<br />

You can use the <strong>IBM</strong> Data Server Driver (also known as the <strong>IBM</strong> common<br />

client driver) with either DB2 or <strong>Informix</strong>. This JDBC driver lets you write Java<br />

applications to access a local <strong>Informix</strong> Server, DB2 data, or any remote<br />

relational data on a server that supports DRDA®. Using this API, you can<br />

access these database systems using JDBC, SQLJ or pureQuery. SQLJ<br />

provides support for embedded static SQL in Java applications.<br />

Note: The <strong>IBM</strong> Data Server Driver is introduced with Client SDK beginning<br />

with Client SDK 3.50.XC7. At this writing, the Client SDK distributed with<br />

<strong>Informix</strong> database server is one (1) version less than the server version. As<br />

an example, Client SDK 3.50.XC6 is the version distributed with Server<br />

edition 11.50.XC7.<br />

Chapter 1. Introduction to <strong>IBM</strong> <strong>Informix</strong> 11


The <strong>IBM</strong> Data Server Driver for JDBC and SQLJ is a single driver that<br />

includes JDBC Type 2 and JDBC Type 4 behavior. For connections to <strong>IBM</strong><br />

<strong>Informix</strong> databases, only Type 4 behavior is supported. <strong>IBM</strong> Data Server<br />

Driver for JDBC and SQLJ Type 4 driver behavior is also referred to as <strong>IBM</strong><br />

Data Server Driver for JDBC and SQLJ type 4 connectivity. For more<br />

information about these APIs, see the Java discussions at:<br />

http://publib.boulder.ibm.com/infocenter/db2luw/v9r5/index.jsp?topic=/com.i<br />

bm.db2.luw.apdv.java.doc/doc/rjvjdb2o.html<br />

► <strong>IBM</strong> <strong>Informix</strong> JDBC Driver<br />

<strong>IBM</strong> <strong>Informix</strong> JDBC Driver is a native-protocol, pure- Java driver (JDBC type<br />

4). Thus, when you use <strong>IBM</strong> <strong>Informix</strong> JDBC Driver in a Java program that<br />

uses the JDBC API to connect to an <strong>IBM</strong> <strong>Informix</strong> database, your session<br />

connects directly to the database or database server, without a middle tier.<br />

When deciding which JDBC interface to use, it is important to understand the<br />

differences between these two APIs. If you need to work with extended data<br />

types and features that are unique to <strong>IBM</strong> <strong>Informix</strong> databases, use <strong>IBM</strong> <strong>Informix</strong><br />

JDBC Driver.<br />

To support DataSource objects, connection pooling, and distributed transactions,<br />

<strong>IBM</strong> <strong>Informix</strong> JDBC Driver provides classes that implement interfaces and<br />

classes described in the JDBC 3.0 API from Sun Microsystems.<br />

<strong>Informix</strong> classes implementing Java interfaces<br />

Table 1-2 lists the Java interfaces and classes and the <strong>Informix</strong> classes that<br />

implement them.<br />

Table 1-2 Java interfaces and classes<br />

JDBC interface class <strong>Informix</strong> class<br />

java.io.Serializable com.informix.jdbcx.IfxCoreDataSource<br />

java.sql.Connection com.informix.jdbc.IfmxConnection<br />

javax.sql.ConnectionEventListener com.informix.jdbcx.IfxConnectionEvent-<br />

Listener<br />

javax.sql.ConnectionPoolDataSource com.informix.jdbcx.IfxConnectionPoolData-<br />

Source<br />

javax.sql.DataSource com.informix.jdbcx.IfxDataSource<br />

javax.sql.PooledConnection com.informix.jdbcx.IfxPooledConnection<br />

javax.sql.XADataSource com.informix.jdbcx.IfxXADataSource<br />

java.sql.ParameterMetaData com.informix.jdbc.IfxParameterMetaData<br />

12 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


<strong>IBM</strong> <strong>Informix</strong> JDBC Driver, Version 3.0, and later implements the updateXXX()<br />

methods defined in the ResultSet interface by the JDBC 3.0 specification. These<br />

methods, such as updateClob, are further defined in the J2SDK 1.4.x API (and<br />

later versions) and require that the ResultSet object can be updated. The<br />

updateXXX methods allow rows to be updated using Java variables and objects<br />

and extend to include additional JDBC types. These methods update JDBC<br />

types implemented with locators, not the data that is designated by the locators.<br />

<strong>Informix</strong> classes Java specification<br />

To support the <strong>Informix</strong> implementation of SQL statements and data types, <strong>IBM</strong><br />

<strong>Informix</strong> JDBC Driver provides classes that extend the JDBC 3.0 API. For<br />

information about the Java classes and the <strong>Informix</strong> classes that application<br />

programs can use to extend them, see <strong>IBM</strong> <strong>Informix</strong> JDBC Driver Programmer's<br />

Guide, v3.50, SC23-9421.<br />

Because <strong>IBM</strong> <strong>Informix</strong> has extended functionality, extra data types, and smart<br />

large objects, several <strong>Informix</strong> classes provide support for functionality that is not<br />

present in the JDBC 3.0 specification. Table 1-3 lists these classes.<br />

Table 1-3 <strong>Informix</strong> classes beyond the Java Specification<br />

JDBC interface or class <strong>Informix</strong> class Provides support for<br />

java.lang.object UDTManager Deploying opaque data types in the<br />

database server<br />

java.lang.object UDTMetaData Deploying opaque data types in the<br />

database server<br />

java.lang.object UDRManager Deploying user-defined routines in<br />

the database server<br />

java.lang.object UDRMetaData Deploying user-defined routines in<br />

the database server<br />

In releases prior to JDK Version 1.4, the UDTManager and UDRManager helper<br />

classes included in ifxtools.jar were not accessible from a packaged class. As<br />

of <strong>IBM</strong> <strong>Informix</strong> JDBC Driver 2.21.JC3, all these classes are in the udtudrmgr<br />

package. For backwards compatibility, unpackaged versions of these classes are<br />

also included. To access a packaged class, use the following import statements<br />

in your program:<br />

► Import udtudrmgr.UDTManager;<br />

► Import udtudrmgr.UDRManager;<br />

Chapter 1. Introduction to <strong>IBM</strong> <strong>Informix</strong> 13


OLEDB<br />

Microsoft OLE DB is a specification for a set of data access interfaces that are<br />

designed to enable a variety of data stores to work together seamlessly. OLE DB<br />

includes the following components:<br />

► Data providers<br />

► Data consumers<br />

► Service components<br />

Each data provider makes data available to consumers in a tabular form through<br />

virtual tables. Data consumers use the OLE DB interfaces to access data. You<br />

can use the <strong>IBM</strong> <strong>Informix</strong> OLE DB Provider to enable client applications, such as<br />

ActiveX Data Object (ADO) applications and web pages, to access data on an<br />

<strong>Informix</strong> server.<br />

You can find detailed information about the characteristics of the <strong>IBM</strong> <strong>Informix</strong><br />

OLE DB Provider in <strong>IBM</strong> <strong>Informix</strong> OLE DB Provider Programmer's Guide,<br />

Version 3.50, SC23-9424. The <strong>IBM</strong> OLEDB provider works with any <strong>IBM</strong> <strong>Informix</strong><br />

Server version greater than or equal to 7.3 (7.3, 8.x, 9.x,10.x or 11.x). For<br />

information about OLE DB architecture and programming, go to the Microsoft<br />

website and search for “Introduction to OLE DB” topic:<br />

http://www.microsoft.com<br />

ESQL/C<br />

<strong>Informix</strong> ESQL/C is an API that enables you to embed SQL statements directly<br />

into a C program by means of the <strong>Informix</strong> ESQL/C preprocessor, esql. The<br />

preprocessor converts each SQL statement and <strong>IBM</strong> <strong>Informix</strong>-specific code to<br />

C-language source code and then invokes the C compiler to compile it.<br />

<strong>Informix</strong> ESQL/C includes the following components:<br />

► The <strong>Informix</strong> ESQL/C libraries of C functions, which provide access to the<br />

database server, and all the <strong>Informix</strong> data types<br />

► The <strong>Informix</strong> ESQL/C header files, which define the data structures,<br />

constants, and macros useful to an <strong>Informix</strong> ESQL/C program<br />

► The esql command, which processes the <strong>Informix</strong> ESQL/C source code to<br />

create a C source file that it passes to the C compiler<br />

► The finderr utility on the UNIX system and the <strong>Informix</strong> Error Messages<br />

Windows-based utility that provides information about <strong>IBM</strong> <strong>Informix</strong> specific<br />

error messages<br />

► GLS locale and code set conversion files for locale specific information<br />

14 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


1.2.3 4GL<br />

1.2.4 Ruby on Rails<br />

<strong>IBM</strong> <strong>Informix</strong> 4GL is a fourth-generation application development and production<br />

environment that provides power and flexibility without the need for<br />

third-generation languages such as C. The following package options are<br />

available for all UNIX and Linux operating systems:<br />

► <strong>Informix</strong> 4GL Rapid Development System and <strong>Informix</strong> 4GL Interactive<br />

Debugger provide a pseudo-compiled development environment for<br />

applications.<br />

► <strong>Informix</strong> 4GL C Compiler provides the components needed to develop and<br />

compile a high-performance application for a production environment.<br />

<strong>IBM</strong> <strong>Informix</strong> supports database access for client applications written in the<br />

popular and dynamic open source programming language called Ruby. To<br />

accomplish this, the developer must use a Ruby Driver and a Rails Adapter for<br />

the standard Ruby framework Rails. <strong>IBM</strong> <strong>Informix</strong> offers the following methods for<br />

using Ruby and Ruby on Rails:<br />

► The Ruby driver and Rails Adapter for <strong>IBM</strong> Data Servers is supported on<br />

<strong>Informix</strong>, Version 11.10 or later, using the DRDA protocol. This option requires<br />

the <strong>IBM</strong> Data Server Driver for ODBC and the call level interface (CLI) which<br />

are available as part of the <strong>Informix</strong> Client SDK.<br />

► Ruby/<strong>Informix</strong> and Rails <strong>Informix</strong>_adapter are specific for <strong>Informix</strong> database<br />

server and work with <strong>Informix</strong> database connections. Support all versions of<br />

the <strong>IBM</strong> <strong>Informix</strong> database servers and require the Client SDK libraries for the<br />

communication with the database server.<br />

You can download the both packages from the Rubyforge website at:<br />

http://rubyforge.org/projects/ruby-informix/<br />

1.2.5 <strong>Informix</strong> DataBlade Developers Kit<br />

The <strong>IBM</strong> <strong>Informix</strong> DataBlade Developers Kit (DBDK) is an aid for developing<br />

DataBlade modules. The kit runs on Microsoft Windows and generates much of<br />

the code you need for a DataBlade. DataBlades can be developed without a<br />

DBDK on operating systems other than Windows; however, it is noteworthy that<br />

the procedures for setting up the development environment on a UNIX system<br />

are complex without help from DBDK.<br />

Chapter 1. Introduction to <strong>IBM</strong> <strong>Informix</strong> 15


The DataBlade Developers Kit provides several graphical user interfaces for<br />

creating and working with <strong>Informix</strong> DataBlade modules.:<br />

► BladeSmith: A tool for organizing a DataBlade module development project.<br />

You can use BladeSmith to create a project and define the objects, such as<br />

data types and routines, that belong to the DataBlade module. BladeSmith<br />

generates source files, header files, make files, functional test files, SQL<br />

scripts, messages files, and packaging files.<br />

► DBDK Visual C++ Add-In and IfxQuery: Tools for debugging a DataBlade<br />

module using Microsoft Visual C++ on Windows. The add-in automates many<br />

of the debugging tasks and calls the IfxQuery tool to run unit tests for<br />

DataBlade module routines.<br />

► BladePack: A tool for creating a DataBlade module package. BladePack can<br />

create a simple directory tree containing files to be installed or an installation<br />

that includes an interactive user interface.<br />

► BladeManager: A command line tool on UNIX (or Windows) that comes with<br />

the <strong>Informix</strong> Server. It is a utility that is needed for registering and<br />

unregistering DataBlade modules in <strong>Informix</strong> databases.<br />

1.2.6 <strong>Informix</strong> Spatial DataBlade<br />

Many of the <strong>IBM</strong> <strong>Informix</strong> database servers support DataBlades. Of these<br />

DataBlades, a couple of blades are fairly popular because of their usefulness and<br />

flexibility. We introduce one of these blades here to open your interest into an<br />

area that you might not have considered. Location based data is one of several<br />

features and benefits that can be found in the <strong>IBM</strong> <strong>Informix</strong> Spatial DataBlade.<br />

The Spatial DataBlade can transform both traditional and location-based data<br />

into essential information through the following functions:<br />

► Expands <strong>IBM</strong> <strong>Informix</strong> Server to provide SQL-based spatial data types and<br />

functions that can be used directly through standard SQL queries or with<br />

client-side Geographic Information Systems (GIS) software.<br />

► Delivers innovative spatial technology through a convenient no-charge<br />

download.<br />

► Generates vital business intelligence for a competitive edge.<br />

► Maximizes spatial data capabilities to enable critical business decisions.<br />

► Works in an enterprise replication environment which includes spatial data<br />

types.<br />

► Enables organizations to manage complex geospatial information alongside<br />

traditional data, without sacrificing the efficiency of the relational database<br />

model.<br />

16 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


1.2.7 PHP on <strong>Informix</strong><br />

► Includes R-tree indexing.<br />

R-tree is built into the database kernel and works directly with extended data<br />

types to enable proper geospatial data management. Unlike standard indices,<br />

the R-tree does not divide space into a full coverage of non- overlapping,<br />

adjacent cells. Instead, it uses data partitioning, where each object is<br />

automatically represented by a bounding box that is entirely determined by its<br />

own shape. These bounding boxes might overlap and do not need to cover<br />

the entire space. As a result there is no need to know the spatial extent of the<br />

data in advance.<br />

PHP, the powerful and popular server-side scripting language for creating web<br />

content, has become an important platform for <strong>Informix</strong> development. The<br />

<strong>Informix</strong> OpenAdmin Tool (OAT), which provides the ability to administer multiple<br />

<strong>Informix</strong> instances from a single location, is written entirely in the PHP language.<br />

<strong>Informix</strong> supports database access for client applications written in the PHP<br />

programming language by using a PDO (PHP Data Object) extension that<br />

functions as a database extraction layer. The primary PHP driver available for<br />

<strong>Informix</strong> is called PDO_<strong>IBM</strong>, and is supported on <strong>Informix</strong> Version 11.10, and<br />

following. The other available PHP driver is PDO_INFORMIX. It is the older of<br />

these two, and is the driver used for the <strong>Informix</strong> OAT. You can find the drivers for<br />

PHP on the PECL for PHP website at:<br />

http://pecl.php.net/package/PDO_<strong>IBM</strong><br />

1.3 <strong>Informix</strong> overview<br />

This section provides a description of the database architecture from a developer<br />

perspective. There are entire manuals to describe server side functions and<br />

administration. In this section, we limit our overview to things that the developer<br />

should consider. For more information about the details of the <strong>IBM</strong> <strong>Informix</strong><br />

Server engine, consult the <strong>IBM</strong> <strong>Informix</strong> Administrators Guide, which is available<br />

at:<br />

http://publib.boulder.ibm.com/infocenter/idshelp/v115/index.jsp?topic=/com.ibm.<br />

adref.doc/adref.htm<br />

Chapter 1. Introduction to <strong>IBM</strong> <strong>Informix</strong> 17


1.3.1 Architecture overview<br />

An understanding of the <strong>Informix</strong> database server architecture is beneficial for<br />

application development.<br />

Client/server architecture<br />

<strong>IBM</strong> <strong>Informix</strong> servers are based on a multi-threaded client/server architecture.<br />

Regardless of the edition that you use, the server can support a large number of<br />

client connections while users are accessing data. A quick overview provides<br />

insights into what aspects influence development and what aspects might need<br />

DBA attention.<br />

The <strong>IBM</strong> <strong>Informix</strong> Server edition environments consist of several parts that are<br />

usually not directly visible to the developer. These parts include shared memory,<br />

disk storage, and virtual processors (VPs). The virtual processors are divided<br />

into VP classes to manage specific tasks, such as SQL query processing (CPU),<br />

physical and logical log processes (PIO and LIO), network connection processes<br />

(NET), engine administration (ADM), miscellaneous (MSC), and disk I/O (AIO<br />

and KAIO) processes. On UNIX and Apple Macintosh systems, VPs are visible<br />

as virtual processes. On Windows environments, the VPs are seen as<br />

threads.The program execution process is visible as oninit. Virtual processes<br />

communicate by way of shared memory structures known as mutexes (mutually<br />

exclusive). Because shared memory is also used to move database data in<br />

buffers, it helps to know that some memory buffers are reserved for engine<br />

processing and some buffers allocated (and managed dynamically) for data<br />

processing.<br />

Network protocols and other connection types<br />

Users can connect to <strong>IBM</strong> <strong>Informix</strong> Server using a network connection, shared<br />

memory, pipes, DRDA, or multiplexed connections. Shared memory and pipe<br />

connections are only available on the same system as the server instance.<br />

Network connections are the most popular, because they can connect different<br />

systems and will use either a TCP/IP or a socket connection, depending on the<br />

operating system. Regardless of the method that you choose, it is important to<br />

minimize the overhead costs associated with opening and closing connections.<br />

Keep sessions open only as long as it is prudent, and re-use connections when<br />

possible.<br />

Authentication and user connections<br />

By default, authentication is determined for users connecting to a database by<br />

the existence of a user name in the operating system environment. Other<br />

authentication methods include lightweight directory access protocol (LDAP), or<br />

single sign-on (SSO) through Kerberos.<br />

18 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


If you need a secured authentication method, <strong>IBM</strong> <strong>Informix</strong> Server also has two<br />

secured connection methods by way of the encrypted Communication Support<br />

Module (CSM) and single password CSM. You can use one or the other, but not<br />

both at the same time. Neither the encrypted CSM not the single password CSM<br />

method work over multiplexed connections. Enterprise Replication (ER) and high<br />

availability (HA) replication support encryption but not with CSM. Secure Sockets<br />

Layer (SSL) communications are an alternative to <strong>Informix</strong>-specific encryption<br />

CSMs. SSL encrypts data end-to-end and secures TCP/IP and Distributed<br />

Relational Database Architecture (DRDA) connections between two points<br />

over a network. For setup information, see the developerWorks® article Protect<br />

your data with Secure Sockets Layer support in <strong>Informix</strong> Dynamic Server, Part 1:<br />

Setting up SSL support in IDS, which is available at:<br />

http://www.ibm.com/developerworks/data/library/techarticle/dm-0912securesockets1<br />

/index.html<br />

Programming and user process considerations<br />

Any SQL or stored procedure call is parsed and optimized when the engine first<br />

receives the statement. Parsing and optimization methods require a little extra<br />

running time. If you can minimize this time, you can speed up query execution.<br />

The following factors can speed up execution time:<br />

► If you cannot optimize the query syntax in advance, have the DBA set the<br />

OPTCOMPIND parameter in the onconfig file to 2 to use distribution data<br />

(determined by Update statistics usage).<br />

► If you can optimize all of your query syntax expressions in advance, you might<br />

want your DBA to consider using OPTCOMPIND 1 or 2.<br />

► If the same statement is executed multiple times, it is placed in a procedure or<br />

dictionary cache. Cache statements run faster.<br />

► If the statement is a prepared statement, the statement can be shared by<br />

multiple users and does not need reparsing or optimizing.<br />

► When a statement execution thread is ready to run, it is scheduled to run on a<br />

CPU VP. On a system with multiple processors where each CPU VP maps to<br />

a physical processor, multiple statements can run concurrently on multiple<br />

CPU VPs. Take advantage of multiple CPUs whenever possible by means of<br />

concurrent queries, parallel subqueries, and the degree of parallelism.<br />

► When a statement runs on the CPU VP, it is given a brief block of time to run.<br />

At the end of the time unit, it is placed into a VP wait cycle, and the next<br />

statement thread gets a time block on the VP queue. This use of a wait cycle<br />

gives all executing processes an opportunity to make progress, regardless of<br />

the number of processes that are running.<br />

Chapter 1. Introduction to <strong>IBM</strong> <strong>Informix</strong> 19


Physical and logical logging<br />

As each of the various CPU processes are running, the database engine keeps<br />

track of a number of operations. When data is retrieved from disk, the data image<br />

is placed in a physical log buffer. Change process information is placed in the<br />

logical log. When image data is affected by SQL processing, the physical image<br />

is modified periodically and written back to disk.<br />

During this process the physical log image and logical log information are also<br />

written into log records. Depending on the commit protocols and isolation levels,<br />

this information is available to the DBA through recovery operations in the event<br />

that the information is needed. The DBA can also use automatic recovery<br />

features that are built in to the engine can if the engine abruptly goes offline due<br />

to a power failure or crash.<br />

Commit protocols<br />

If transactions are made against a database that uses unbuffered logging, the<br />

records in the logical-log buffer are guaranteed to be written to disk during<br />

commit processing. When control returns to the application after the COMMIT<br />

statement (and before the PREPARE statement for distributed transactions), the<br />

logical-log records are on the disk. The database server flushes the records as<br />

soon as any transaction in the buffer is committed (that is, a commit record is<br />

written to the logical-log buffer).<br />

If transactions are made against a database that uses buffered logging, the<br />

records are held (buffered) in the logical-log buffer for as long as possible. They<br />

are not flushed from the logical-log buffer in shared memory to the logical log on<br />

disk until one of the following situations occurs:<br />

► The buffer is full.<br />

► A commit on a database with unbuffered logging flushes the buffer.<br />

► A checkpoint occurs.<br />

► The connection is closed.<br />

If you use buffered logging and a failure occurs, you cannot expect the database<br />

server to recover the transactions that were in the logical-log buffer when the<br />

failure occurred. Thus, you might lose some committed transactions. In return for<br />

this risk of using buffered logging, performance during alterations improves<br />

slightly.<br />

20 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Consider using buffered logging only if the following situations:<br />

► If the database is updated frequently (speed of updating is important).<br />

► If the application that is performing the transaction can continue as it is and if<br />

you decide that the price (in time and effort) of returning the database to a<br />

consistent state by either removing the effects or reapplying the transaction is<br />

too high or you can re-create the updates in the event of failure.<br />

If a transaction failure does occur, you can simply choose to leave the<br />

database in its inconsistent state if the transaction does not significantly affect<br />

database data.<br />

As you consider whether to use a buffered or unbuffered logging method,<br />

remember that no automatic process or utility can perform a rollback of a<br />

committed transaction or can commit part of a transaction that has been rolled<br />

back. Without detailed knowledge of the application, messages are not enough<br />

to determine what has happened. Based on your knowledge of your application<br />

and your system, you might need to help the DBA determine when to roll back or<br />

to follow though on interrupted transactions. For more information about this<br />

topic, see the Guide to SQL: Tutorial section on interrupted modifications, which<br />

is available at:<br />

http://publib.boulder.ibm.com/infocenter/idshelp/v115/index.jsp?topic=/com.ibm.<br />

sqlt.doc/ids_sqt_277.htm<br />

1.3.2 <strong>Informix</strong> developer environment<br />

The environment references that you need have some variations, depending on<br />

whether you use the <strong>IBM</strong> common client API or the native Client SDK and which<br />

operating system you use. The environment settings must include identifying the<br />

following references to the components:<br />

► Setting the INFORMIXDIR environment variable to the installation directory of<br />

the software installation location.<br />

► Setting up <strong>Informix</strong> Server information (INFORMIXSERVER).<br />

► Adding the $INFORMIXDIR/bin to the PATH environment variable.<br />

On Windows, you have to set only the <strong>Informix</strong> database server information with<br />

the setnet32.exe utility. On UNIX-type platforms, you might want to set the<br />

environment variables so that they are set in your user profile at login or use a<br />

setup script. You also need to reference the sqlhosts file to identify <strong>Informix</strong><br />

Server information. In the chapters that follow, we explain how to install the<br />

server and provide specific details for the relevant API environment details.<br />

Chapter 1. Introduction to <strong>IBM</strong> <strong>Informix</strong> 21


Before you select an API or library, be aware that some operating systems are<br />

not available for some of the tools and that server functionality might not be<br />

accessible with some of the APIs. Consider the following information when<br />

making an API selection:<br />

► Client SDK<br />

– Optimized for <strong>IBM</strong> <strong>Informix</strong> database servers.<br />

– Works with PHP.<br />

– Directly interfaces with <strong>Informix</strong> Server; no middle tier required.<br />

– Supports all the <strong>Informix</strong> data types, extended data types, and smart<br />

BLOBs.<br />

► <strong>IBM</strong> Data Server Client<br />

– Optimized for compatibility and easy development with <strong>Informix</strong> and DB2<br />

<strong>IBM</strong> database servers.<br />

– Works with PHP and Ruby.<br />

– No available interface for Apple Mac systems.<br />

– Includes support for C and Fortran development.<br />

– No DataBlade API.<br />

1.3.3 <strong>Informix</strong> capabilities<br />

<strong>IBM</strong> <strong>Informix</strong> database servers provide a broad spectrum of features that allow<br />

resilience in response to fast changing systems and applications in a modern<br />

business environment. If you are aware of what the product can already do<br />

before you begin to develop, it aids and enables you to support applications and<br />

easily grow to meet new demands.<br />

This section provides a brief overview of the capabilities of <strong>Informix</strong>.<br />

Resilient<br />

High availability and fast recovery are standard aspects of an on-demand<br />

environment. <strong>Informix</strong> database server engines have a variety of ways to<br />

configure the instance, so there is little chance of the engine being unavailable at<br />

critical points in time.<br />

Reliable<br />

In addition to availability, there is a need for continuity. <strong>Informix</strong> has options to<br />

protect a server environment, such as backup servers, full independent copies of<br />

the processing environment for failover, and workload balancing at alternate<br />

locations around the world.<br />

22 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Available<br />

There is an <strong>Informix</strong> solution to fit any situation that requires availability:<br />

► Continuous availability feature<br />

► High availability replication with allowance for multiple secondary servers<br />

Secure<br />

<strong>Informix</strong> supports open, industry-standard security mechanisms such as roles,<br />

password-based authentication, and RDBMS schema authorizations. These<br />

open standards ensure flexibility and security with easy validation and<br />

verification. Column-level encryption and Pluggable Authentication Modules<br />

(PAM) are also available. The Advanced Access Control Feature offers cell-,<br />

column-, and row-level label-based access control (LBAC). Thus, access to data<br />

can be controlled down to the individual cell level.<br />

Adaptable<br />

<strong>Informix</strong> is adaptable from the server side and from the client side. The engine<br />

component can be stripped down, embedded, and run with little user<br />

intervention. Using the developer tools that we discuss in this book, a developer<br />

can provide customized deployment by way of client applications and server-side<br />

processes, such as stored procedures, multiple triggers on tables and views,<br />

user-defined functions, and DataBlades<br />

Fast<br />

<strong>Informix</strong> is known for fast OLTP performance. Application performance is helped<br />

by capabilities such as committed isolation level and non-blocking checkpoints,<br />

which provide maximum concurrency. Direct I/O calls to file systems can result in<br />

performance similar to raw device I/O. SQL performance can be improved<br />

through techniques or configuration options that redirect or focus the engine’s<br />

optimizer decisions by way of optimizer directives in the SQL or by way of<br />

automated update statistics collection that inform the method used for running<br />

the query. When the DBA and the developer both focus on performance, it<br />

enables things to run more smoothly and reduces infrastructure costs.<br />

Flexible<br />

There are a number of APIs that are available, both as specific programming<br />

language supplements and as interfaces that extend the architecture of the<br />

server instance. In <strong>Informix</strong> 11 and following, the Web Feature Service API<br />

allows developers to use location-based services or location-enabled IT services.<br />

It is implemented in the Open GeoSpatial Consortium Web Feature Service<br />

(OGC WFS) API. This API also interacts with location-based data provided by<br />

the <strong>IBM</strong> <strong>Informix</strong> Spatial and Geodetic DataBlade modules. There is a significant<br />

amount of extensibility when using DataBlade technology.<br />

Chapter 1. Introduction to <strong>IBM</strong> <strong>Informix</strong> 23


Hidden, behind-the- scenes tasking<br />

Business systems and applications need to work with minimum invasions into the<br />

operations of a business environment. From the server side, applications can run<br />

in an automated mode and perform self-maintenance. From an application<br />

perspective, database administrative tasks can be controlled and run from inside<br />

an application. The SQL Administration API allows you to do tasks such as space<br />

management, monitoring and manipulating memory, running scheduled tasks,<br />

and monitoring user sessions without developer intervention after they are setup<br />

and running.<br />

Customizable install footprint<br />

The installation of <strong>Informix</strong> can be automated, and the installation footprint can<br />

be customized using the Deployment Wizard so that you can limit the installation<br />

to only the data server functionality that you need and can reduce the size and<br />

costs of a solution for your software deployment.<br />

Affordable, reduced complexity<br />

When <strong>IBM</strong> or the developer adds features, the first impression is that the<br />

application will be more complex. With the features described up to this point, it is<br />

a surprise to discover that administration can actually be reduced by means of an<br />

application or one of the APIs and GUIs that we explain in this book.<br />

24 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Chapter 2. Setting up an <strong>Informix</strong><br />

development environment<br />

2<br />

This chapter describes how to set up an environment for <strong>Informix</strong> application<br />

development, including the installation and configuration of <strong>Informix</strong> Server and<br />

<strong>Informix</strong> Client. We focus our discussion on <strong>Informix</strong> Client products selection,<br />

installation, and configuration. Reading this chapter can help you understand<br />

how to complete the following tasks:<br />

► Decide which <strong>Informix</strong> Client product is suitable for your application.<br />

► Install and configure all <strong>Informix</strong> Client products that can connect to <strong>Informix</strong>.<br />

► Know any special consideration for each <strong>Informix</strong> Client in terms of<br />

connectivity.<br />

Note: In this chapter, we use the terms <strong>Informix</strong> database server, <strong>Informix</strong><br />

Server, and <strong>Informix</strong> interchangeably. In addition, we also use the terms<br />

Client products, Client, and <strong>Informix</strong> Client interchangeably.<br />

© Copyright <strong>IBM</strong> Corp. 2010. All rights reserved. 25


2.1 Server setup<br />

In this section, we describe the various methods of installing <strong>Informix</strong> Server. We<br />

discuss how you can plan for the installation depending upon your specific<br />

requirement. We focus the discussion on the configuration that is required at the<br />

database server side to enable <strong>Informix</strong> Client connectivity.<br />

2.1.1 Planning for the installation<br />

In general, an application developer is not involved in the <strong>Informix</strong> Server product<br />

planning and installation. However, you need to communicate the application<br />

requirements to the DBA, who plans, installs, and configures the <strong>Informix</strong><br />

database server for you. For example, the DBA needs to know if you need a<br />

smart blob space or a reduced footprint of the server or DataBlades. The<br />

<strong>Informix</strong> installer provides options to install only a small footprint of the server<br />

where you can add or remove the features as needed. For more information<br />

about DataBlades, see 10.3, “DataBlades and bladelets” on page 352.<br />

2.1.2 Installing <strong>Informix</strong> Server<br />

<strong>IBM</strong> provides the <strong>Informix</strong> Server editions, described in 1.1, “Server options” on<br />

page 2, in .zip, .tar, or .dmg format, depending on the platform on which<br />

<strong>Informix</strong> Server is installed. You can install <strong>Informix</strong> Server using several<br />

methods. The common installation methods include using the console, a GUI, or<br />

silent mode.<br />

Because we focus on <strong>Informix</strong> Client products for application development in this<br />

book, we describe only the silent mode of <strong>Informix</strong> Server installation on a UNIX<br />

platform. For other methods and platforms, refer to the individual installation PDF<br />

file that comes with the product.<br />

To perform a silent installation on UNIX, use the following steps:<br />

1. Extract the compressed .tar file into any directory using the following<br />

command:<br />

tar -xvpf IIF.11.50.tar<br />

26 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


2. Create the installation .ini file that specifies the installation options. You can<br />

use the sample installation .ini file, server.ini, as a template. The<br />

server.ini file is located in the directory that is used to extract the server<br />

media package. Edit the following information in the server.ini file, and save<br />

the file with a new name, for example myserver.ini:<br />

– Change -P installLocation="/opt/<strong>IBM</strong>/informix" to the location of<br />

directory where you want to install the product.<br />

– Change -G licenseAccepted= option to true to accept the software<br />

license. Otherwise, the installation process stops:<br />

3. Start the silent installation with the following command:<br />

./ids_install -silent -options myserver.ini<br />

Performing these steps installs <strong>Informix</strong> Server in your specified directory along<br />

with a demonstration instance by the name demo_on.<br />

For more information about <strong>Informix</strong> installation and creating new instances, refer<br />

to the installation guide PDF that comes with the media file.<br />

2.1.3 Configuring <strong>Informix</strong> Server<br />

The connectivity information allows a client application to connect to any <strong>IBM</strong><br />

<strong>Informix</strong> database server in the network. The connectivity data for a particular<br />

database server includes the following connectivity data and information is<br />

required:<br />

► The host name of the computer or node on which the database server runs<br />

► The type of connection that an application can use to connect to the server<br />

► The service name or port number used by the database server<br />

► The database instance (also called the database server name)<br />

Even if the client application and the database server are on the same computer<br />

or node, you might need to specify connectivity information for your client<br />

application.<br />

Connectivity on UNIX<br />

On UNIX, the sqlhosts file contains the connectivity information. By default, this<br />

file resides in the $INFORMIXDIR/etc directory. You can use the<br />

INFORMIXSQLHOSTS environment variable to specify an alternative location for<br />

the connectivity information. Edit this file according to the protocol that you are<br />

using or the port number to which your client application will connect.<br />

Chapter 2. Setting up an <strong>Informix</strong> development environment 27


A typical sqlhosts file contains the following fields:<br />

Server Protocol Hostname Service/Port Options<br />

Here is an example:<br />

demo_on onipcshm on_hostname on_servername k=0<br />

demo_se seipcpip se_hostname sqlexec<br />

Each line in the sqlhosts file defines the following information about an <strong>Informix</strong><br />

database server:<br />

► Server<br />

Specifies the name of the <strong>IBM</strong> <strong>Informix</strong> database server. This value normally<br />

correspond to the value in the INFORMIXSERVER environment variable.<br />

► Protocol<br />

Specifies the protocol that is used for the communication with the database<br />

server. It must be the same protocol that the database server uses.<br />

► Hostname<br />

Specifies the system where the <strong>Informix</strong> database server is running.<br />

► Service/Port<br />

Specifies the TCP port or service name, which must be defined in the<br />

/etc/services file, that is used by the <strong>Informix</strong> database server to accept<br />

incoming connections.<br />

► Options<br />

Specifies additional options for the communication, such as buffer size or<br />

connection redirection rules.<br />

APIs such as ESQL/C or ODBC rely on the sqlhosts file to obtain the<br />

connection parameters for the database server.<br />

Example 2-1 shows how a ESQL/C application connects to an <strong>Informix</strong> database<br />

server.<br />

Example 2-1 UNIX connection example<br />

informix@kodiak:/work$ cat $INFORMIXDIR/etc/sqlhosts<br />

#server protocol hostname service/port<br />

demo_on onsoctcp kodiak demo_on_tcp<br />

informix@kodiak:/work$ grep demo_on_tcp /etc/services<br />

demo_on_tcp 9089/tcp # Service for demo_on IDS server<br />

informix@kodiak:/work$ cat connect.ec<br />

#include <br />

int main()<br />

28 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


{<br />

EXEC SQL CONNECT TO 'stores_demo@demo_on';<br />

printf("Connected\n");<br />

}<br />

informix@kodiak:/work$ esql connect.ec -o connect<br />

informix@kodiak:/work$ ./connect<br />

Connected<br />

informix@kodiak:/work$<br />

The definition for the demo_on <strong>Informix</strong> Server specifies the communication<br />

protocol that is used as onsoctcp. The system where the database server is<br />

running is kodiak, and the TCP port that the server uses is demo_on_tcp. The<br />

service name is defined as port 9089 in the /etc/services configuration file.<br />

The ESQL/C example connects to the server and opens the stores_demo<br />

database using the following instruction:<br />

EXEC SQL CONNECT TO 'stores_demo@demo_on';<br />

For more information about the sqlhosts file, refer to the <strong>IBM</strong> <strong>Informix</strong> Dynamic<br />

Server (IDS) Information Center topic:<br />

http://publib.boulder.ibm.com/infocenter/idshelp/v115/index.jsp?topic=/com.ibm.<br />

admin.doc/ids_admin_0158.htm<br />

Connectivity on a Windows system<br />

You can set the connectivity on a Windows system using the setnet32.exe utility<br />

that resides in the $INFORMIXDIR/bin directory. This utility is bundled with <strong>IBM</strong><br />

<strong>Informix</strong> Client Software Development Kit (Client SDK). Use this utility to create<br />

or change the server name, protocol, service name, and host name. You also can<br />

use the setnet32.exe utility to set any environment variable that <strong>Informix</strong><br />

products use.<br />

Chapter 2. Setting up an <strong>Informix</strong> development environment 29


Figure 2-1 shows the Server Information tab of the setnet32.exe utility on a<br />

Windows system. Here, you can specify the server name, host IP address,<br />

network protocol, and service name.<br />

Figure 2-1 The Setnet32 Server Information tab<br />

Note: If you specify the name of the service (for example sqlexec) rather than<br />

the port number, make sure the service name that you use is defined in the<br />

Windows system services file that is located in the<br />

C:\WINDOWS\system32\drivers\etc directory.<br />

Enabling DRDA support<br />

Since version 11.x, <strong>Informix</strong> supports the DRDA protocol. If you plan to use the<br />

Data Server driver packages to connect to an <strong>Informix</strong> database server, you must<br />

enable DRDA support as described in this section.<br />

30 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Windows systems<br />

Use the setnet32 utility to configure an <strong>Informix</strong> instance to use DRDA protocol:<br />

1. Start the setnet32 utility from any command window.<br />

2. Go to Server Information tab (Figure 2-2).<br />

a. Select the required instance from the <strong>IBM</strong> <strong>Informix</strong> Server field. Our<br />

example is demo_my.<br />

b. Change the name of the <strong>Informix</strong> server, and specify a new name for the<br />

DRDA alias, for example demo_my_drda.<br />

c. The HostName field is pre-filled. If it is not, enter your host name or IP<br />

address.<br />

d. Change the Protocolname field from olsoctcp to drsoctcp to make it<br />

DRDA compliant.<br />

e. Change the Service Name field to specify the service name or port<br />

number that the DRDA alias will use.<br />

Figure 2-2 Configuring DRDA support<br />

3. Click Apply, and then click OK.<br />

After adding all the connection details for the DRDA alias, the configuration file<br />

for the <strong>Informix</strong> database server must be updated to link the new server definition<br />

Chapter 2. Setting up an <strong>Informix</strong> development environment 31


with the existing <strong>Informix</strong> instance. In our example, we use demo_my for the<br />

<strong>Informix</strong> database server and demo_my_drda for the DRDA instance.<br />

You can use the DBSERVERALIASES parameter in the onconfig file to specify<br />

an alias for a database server, as shown in Example 2-2.<br />

Example 2-2 Using the DBSERVERALIASES parameter<br />

...<br />

DBSERVERNAME demo_my # Name of default Dynamic Server<br />

# DBSERVERNAME or DBSERVERALIASES that uses a<br />

# DBSERVERALIASES - The list of up to 32 alternative UDRs,<br />

DBSERVERALIASES demo_my_drda # List of alternate dbserver names<br />

# DBSERVERNAME or DBSERVERALIASES that uses ...<br />

...<br />

The database configuration file is located in etc directory of your <strong>Informix</strong><br />

database server. You can use the ONCONFIG environment variable to specify<br />

the name of this file. The complete path using environment variables for the<br />

database configuration file is:<br />

► On a UNIX platform, $INFORMIXDIR\etc\$ONCONFIG<br />

► On a Windows platform, %INFORMIXDIR%\etc\%ONCONFIG%<br />

You must restart the <strong>Informix</strong> database engine for the changes to take effect.<br />

After you complete these steps, the instance is now ready to accept connections<br />

as a DRDA compliant server.<br />

32 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


On a Windows system, you can enable the DRDA support for the demonstration<br />

instance during the installation if you use the Custom installation option.<br />

Figure 2-3 shows the installation panel where you enable the DRDA support.<br />

Figure 2-3 Enable DRDA support for the default instance<br />

Linux and UNIX systems<br />

On Linux and UNIX systems, you can enable the DRDA support by editing the<br />

following <strong>Informix</strong> configuration files:<br />

► Edit the sqlhosts file specified in the $INFORMIXSQLHOSTS environment<br />

variable, and add the following line:<br />

drsoctcp <br />

where:<br />

– is the name for the DRDA alias<br />

– drsoctcp is the protocol used by the new alias<br />

– the name or IP address of the system that is running <strong>Informix</strong><br />

Server<br />

– is the name of the TCP service or port number for<br />

the DRDA instance<br />

Chapter 2. Setting up an <strong>Informix</strong> development environment 33


2.2 Client setup<br />

► Edit the <strong>Informix</strong> Server configuration file located in the etc directory of your<br />

<strong>Informix</strong> Server directory to include the new database definition as an alias for<br />

the existing <strong>Informix</strong> Server.<br />

You can use the environment variables to access this file, for example<br />

$INFORMIXDIR/etc/$ONCONFIG. This file is the file that contains a list of<br />

configuration parameters for <strong>Informix</strong> Server. Example 2-3 shows the<br />

configuration file that we used in our database server.<br />

Example 2-3 Linux onconfig file sample<br />

informix@irk:/usr3/11.50$ grep DBSERV $INFORMIXDIR/etc/$ONCONFIG<br />

# DBSERVERNAME - The name of the default database server<br />

# DBSERVERALIASES - The list of up to 32 alternative UDRs,<br />

# DBSERVERNAME or DBSERVERALIASES that uses a<br />

DBSERVERNAME demo_my<br />

DBSERVERALIASES demo_my_drda<br />

You must restart <strong>Informix</strong> Server for these changes to take effect.<br />

You can find additional information about the sqlhosts file at:<br />

http://publib.boulder.ibm.com/infocenter/idshelp/v115/topic/com.ibm.admin.doc/i<br />

ds_admin_0158.htm<br />

<strong>Informix</strong> is a low-administration, easy-to-use, and embeddable database that<br />

supports various application development languages and technologies, such as<br />

Java, .NET, PHP, and Web Services. <strong>Informix</strong> can handle XML data easily and<br />

can be extended to handle new data sets using DataBlades.<br />

In this section, we describe how to install and configure <strong>Informix</strong> Client products<br />

to support the application development that you need.<br />

2.2.1 <strong>Informix</strong> Client options<br />

<strong>IBM</strong> offers the following <strong>Informix</strong> Client products that you can use to develop and<br />

use an <strong>IBM</strong> <strong>Informix</strong> database server:<br />

► <strong>IBM</strong> <strong>Informix</strong> Client Software Development Kit (Client SDK) includes several<br />

APIs that are designed for developing with an <strong>Informix</strong> database.<br />

► <strong>IBM</strong> <strong>Informix</strong> Connect is a runtime version of Client SDK.<br />

34 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


► <strong>IBM</strong> <strong>Informix</strong> JDBC Driver is Java driver that is optimized for <strong>Informix</strong><br />

databases.<br />

► <strong>IBM</strong> Data Server Client includes the API tools that are needed for<br />

development with <strong>IBM</strong> databases such as DB2 and <strong>Informix</strong>, plus functionality<br />

for database administration and client/server configuration.<br />

► <strong>IBM</strong> Data Server Runtime Client is the runtime version of the <strong>IBM</strong> Data Server<br />

Client.<br />

► <strong>IBM</strong> Data Server Driver Package is a lightweight version of the <strong>IBM</strong> Data<br />

Server Runtime that includes only the interfaces and drivers.<br />

► <strong>IBM</strong> Data Server Driver for JDBC and SQLJ is a Java driver for <strong>IBM</strong> Data<br />

Servers.<br />

Client SDK and <strong>Informix</strong> Connect have distinct functions:<br />

► Client SDK contains a group of application-programming interfaces (APIs)<br />

that developers can use to write applications for <strong>Informix</strong>, plus other client<br />

components. Client SDK must be installed on computers that application<br />

programmers will use to write applications.<br />

► <strong>Informix</strong> Connect contains runtime libraries of the Client SDK APIs, plus other<br />

client components. Install <strong>Informix</strong> Connect on computers that users use to<br />

connect to <strong>Informix</strong> database servers.<br />

The same rule applies to <strong>IBM</strong> Data Server products. Do not use packages that<br />

are designed for development, such as <strong>IBM</strong> Data Server Client, to deploy an<br />

application. Some components, such as <strong>Informix</strong> JDBC Driver, do not have a<br />

specific runtime version, so you can use the same product in both cases.<br />

In addition to these products, you can use open source drivers, such as PHP or<br />

Ruby, to develop with an <strong>IBM</strong> <strong>Informix</strong> database.<br />

Chapter 2. Setting up an <strong>Informix</strong> development environment 35


Figure 2-4 illustrates the options that are available to develop with an <strong>IBM</strong><br />

<strong>Informix</strong> database.<br />

Figure 2-4 Available <strong>Informix</strong> Client products for application development<br />

2.2.2 Installing and setting up Client SDK<br />

<strong>IBM</strong> <strong>Informix</strong> Client Software Development Kit (Client SDK) is a collection of<br />

components for developing and running client applications that connect to the<br />

<strong>Informix</strong> database server. Client SDK bundles with the following components and<br />

utilities:<br />

► ESQL/C with XA support<br />

► <strong>IBM</strong> <strong>Informix</strong> Object Interface for C++<br />

► <strong>IBM</strong> <strong>Informix</strong> OLE DB Provider (Windows only)<br />

► <strong>IBM</strong> <strong>Informix</strong> ODBC Driver with MTS support<br />

► <strong>IBM</strong> <strong>Informix</strong> .NET Provider (Windows only)<br />

► <strong>IBM</strong> <strong>Informix</strong> GLS<br />

► The Global Security Kit (GSKit)<br />

► Password Communication Support Modules (CSM)<br />

► Documentation Viewer<br />

36 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


► The finderr utility on UNIX systems and the <strong>Informix</strong> Error Messages utility<br />

on Windows systems<br />

► The iLogin utility (Windows only)<br />

Starting from version 3.50.xC5, the <strong>IBM</strong> Data Server Driver Package is also<br />

bundled with the Windows system version of Client SDK and <strong>Informix</strong> Connect.<br />

Client SDK provides access to all the <strong>Informix</strong> database servers. Table 2-1 lists<br />

the <strong>Informix</strong> database servers that supports Client SDK.<br />

Table 2-1 Supported database servers<br />

Database server Versions<br />

<strong>IBM</strong> <strong>Informix</strong> 7.x, 9.x,10.x and 11.50<br />

<strong>IBM</strong> <strong>Informix</strong> Extended Parallel Server 8.50 and higher<br />

<strong>IBM</strong> <strong>Informix</strong> Standard Engine 7.25<br />

<strong>IBM</strong> <strong>Informix</strong> Online 5.20 and higher<br />

Some components, such as <strong>Informix</strong> OLE DB Provider, do not allow a connection<br />

to an <strong>IBM</strong> <strong>Informix</strong> Standard Engine server. Refer to the component release<br />

notes for more information:<br />

http://publib.boulder.ibm.com/infocenter/idshelp/v115/topic/com.ibm.relnotes.do<br />

c/relnotes_ClientSDK350xc7.html<br />

Completing the preliminary tasks<br />

Before you install Client SDK, perform the following preliminary tasks:<br />

1. Determine the following locations:<br />

– Media location: This directory is the directory where all the media files<br />

reside.<br />

– Installation location: This directory is the location where the installer<br />

places all the binaries and the configuration files. This directory is<br />

represented by the environment variable $INFORMIXDIR. If<br />

$INFORMIXDIR is set, the defined location is the default installation<br />

location.<br />

– Java location: The script that is used during the installation process<br />

requires the use of a Java virtual machine (JVM). A JVM is bundled<br />

together with Client SDK. However, if required, it is possible to specify a<br />

different JVM for the installation process. The minimum version is Sun<br />

JRE 1.4.2.<br />

Chapter 2. Setting up an <strong>Informix</strong> development environment 37


2. Prepare the environment.<br />

You need to check if you have the informix user and the informix group on<br />

your computer. If you do not, create them. For additional information, refer to:<br />

http://publib.boulder.ibm.com/infocenter/idshelp/v115/topic/com.ibm.igul.do<br />

c/ids_in_005x.htm<br />

Installing the Client SDK<br />

<strong>Informix</strong> provides various methods for installing Client SDK. In this section, we<br />

demonstrate using the GUI to install in both UNIX and Windows environments.<br />

Installing Client SDK on UNIX using the GUI<br />

To install Client SDK in GUI mode:<br />

1. Start the installation GUI with the following command from the root user:<br />

./installclientsdk -gui<br />

Remember to set the DISPLAY environment variable to the window that you<br />

want to project the installation. Figure 2-5 shows the Welcome panel.<br />

Click Next.<br />

38 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong><br />

Figure 2-5 Installation of Client SDK on UNIX Welcome panel<br />

2. On the license agreement panel, select I accept the terms and the license<br />

agreement and click Next.


3. Specify the directory where you want to install <strong>Informix</strong> Client (Figure 2-6).<br />

Enter the full path name. Click Next.<br />

Figure 2-6 Specify the installation directory<br />

4. Select Typical or Custom (Figure 2-7). A Custom installation allows you to<br />

select the features to install. Click Next.<br />

Figure 2-7 Select the type of installation<br />

Chapter 2. Setting up an <strong>Informix</strong> development environment 39


5. If you selected a Custom installation, you next need to select the features that<br />

you want to install and click Next (Figure 2-8). If you want to install whatever<br />

the installer offers, select a Typical installation.<br />

Figure 2-8 Custom options to choose<br />

40 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


6. The installer presents the summary of available space and the components<br />

that you have chosen for installation, as shown in Figure 2-9. If needed, you<br />

can go back and change the installation selections. Click Next to start the<br />

installation.<br />

Figure 2-9 Installation summary<br />

7. Figure 2-10 shows that the installation is complete without any errors.<br />

Figure 2-10 Installation complete without any errors<br />

Chapter 2. Setting up an <strong>Informix</strong> development environment 41


At this stage, the Client SDK installation is complete. If the <strong>Informix</strong> database<br />

server is located on a different system, you might need to set up the connection<br />

information and modify the sqlhosts file, using the details of your <strong>Informix</strong><br />

Server.<br />

Installing Client SDK on a Windows system<br />

Installation on a Windows system for the Client SDK is similar to UNIX the<br />

installation except that the Windows system installation has the option to install<br />

<strong>IBM</strong> Data Server Driver Package. If you select the option to install these drivers,<br />

refer to “Installing the <strong>IBM</strong> Data Server Driver package” on page 44 for<br />

Installation details.<br />

Configuration utility<br />

On Windows systems, the Client SDK comes bundled with the setnet32.exe<br />

utility for configuring the Client SDK. The Client SDK has default values set and<br />

is ready to use unless you want to change the protocol, server information, or any<br />

environment variable under which the client application runs.<br />

The setnet32.exe utility sets environment variables and network parameters that<br />

<strong>IBM</strong> <strong>Informix</strong> products use at run time. The environment variables and<br />

connectivity parameters are stored in the Windows system registry and are valid<br />

for every <strong>Informix</strong> Client product that you install, except <strong>Informix</strong> JDBC Driver.<br />

The setnet32.exe utility has the following tabs:<br />

► The Environment tab allows you to set environment variables.<br />

► The Server Information tab allows you to set database server network<br />

information.<br />

► The Host Information tab allows you to set your host computer and login<br />

information.<br />

► The About Setnet32 tab provides information about the setnet32.exe utility.<br />

For more information about these tabs, refer to the Client SDK installation PDF<br />

file that comes with Client SDK.<br />

Special consideration for 32- and 64-bit products<br />

Beginning with version 3.50.FC4, you can install both 32-bit and 64-bit Client<br />

SDK on the same Windows system.<br />

Before installing the version 3.50.FC4 product, you must uninstall the existing<br />

version 3.50.FC3 or earlier Client SDK from your system.<br />

42 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


To uninstall your existing products, use one of the following methods:<br />

► Use the Add/Remove program.<br />

► Run the setup.exe program from the installed product media. When the<br />

Maintenance Menu displays, select Remove.<br />

You must install the new 32-bit and 64-bit products in separate directories.<br />

The 32-bit Client SDK installs in the following directory by default:<br />

C:\Program Files (x86)\<strong>IBM</strong>\<strong>Informix</strong>\Client-SDK<br />

The 64-bit Client SDK installs in the following directory by default:<br />

C:\Program Files\<strong>IBM</strong>\<strong>Informix</strong>\Client-SDK<br />

The 64-bit product installation adds a suffix to the Program group folder and the<br />

Add/Remove entry. This suffix provides an easy identification between the 32-bit<br />

(no suffix) and 64-bit (suffix) product installations. For more information, refer to<br />

the release notes.<br />

2.2.3 Setting up <strong>IBM</strong> Data Server drivers<br />

Several types of <strong>IBM</strong> Data Server Clients and Drivers are available.<br />

The following <strong>IBM</strong> Data Server Clients are available:<br />

► <strong>IBM</strong> Data Server Client, contains all the APIs and tools that are needed for<br />

development against DB2 and <strong>Informix</strong> databases, including tools for remote<br />

administration.<br />

► <strong>IBM</strong> Data Server Runtime Client, contains all the APIs but only the minimum<br />

number of utilities for setup and configure the development environment.<br />

► <strong>IBM</strong> Data Server Driver Package, contains only the APIs and drivers without<br />

any additional tools.<br />

The client products contain the APIs and drivers plus additional tools that are<br />

designed for remote database administration and configuration of the client<br />

environment.<br />

The following <strong>IBM</strong> Data Server Drivers are available:<br />

► <strong>IBM</strong> Data Server Driver for JDBC and SQLJ<br />

► <strong>IBM</strong> Data Server Driver for ODBC and CLI<br />

► <strong>IBM</strong> Data Server Driver for .NET<br />

► <strong>IBM</strong> Data Server open source drivers such as PHP or Ruby<br />

Chapter 2. Setting up an <strong>Informix</strong> development environment 43


You can download some of these components and install them as separate<br />

products.<br />

Each <strong>IBM</strong> Data Server Client and driver provides a particular type of support:<br />

► For Java applications only, use <strong>IBM</strong> Data Server Driver for JDBC and SQLJ.<br />

► For applications using ODBC or CLI only, use <strong>IBM</strong> Data Server Driver for<br />

ODBC and CLI<br />

► For applications using ODBC, CLI, .NET, OLE DB, PHP, Ruby, JDBC, or<br />

SQLJ, use <strong>IBM</strong> Data Server Driver Package.<br />

► <strong>IBM</strong> Data Server Runtime Client and <strong>IBM</strong> Data Server Client includes all of<br />

above drivers and some functions of DB2.<br />

In this section, we discuss the installation and configuration of the following<br />

drivers for UNIX and Windows platforms:<br />

► <strong>IBM</strong> Data Server Driver for JDBC and SQLJ<br />

► <strong>IBM</strong> Data Server Driver for ODBC and CLI<br />

► <strong>IBM</strong> Data Server Driver Package<br />

For the installation and configuration of <strong>IBM</strong> Data Server Runtime Client and <strong>IBM</strong><br />

Data Server Client, refer to:<br />

http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/index.jsp?topic=/com.ibm.s<br />

wg.im.dbclient.install.doc/doc/c0022615.html<br />

Installing the <strong>IBM</strong> Data Server Driver package<br />

The <strong>IBM</strong> Data Server Driver package is a lightweight solution and the<br />

recommended package for user code deployment. It provides robust runtime<br />

support for applications using ODBC, CLI, .NET, OLE DB, PHP, Ruby, JDBC, or<br />

SQLJ without the need of installing Data Server Runtime Client or Data Server<br />

Client. Here we discuss the installation of the drivers presented under the <strong>IBM</strong><br />

Data Server Driver Package.<br />

Installing the driver package on UNIX and Linux<br />

You can download the <strong>IBM</strong> Data Server Driver Package and individual drivers<br />

such as <strong>IBM</strong> Data Server Driver for JDBC and SQLJ from the <strong>IBM</strong> Support and<br />

downloads website at:<br />

http://www.ibm.com/support/docview.wss?rs=4020&uid=swg21385217<br />

Extract <strong>IBM</strong> Data Server Drivers Package to an empty directory after you<br />

download it.<br />

If you want to install the complete <strong>IBM</strong> Data Server Driver Package, run the<br />

installIDSDriver command. This driver package includes database drivers for<br />

44 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Java, ODBC/CLI, PHP, and Ruby on Rails, each of which is stored in its own<br />

subdirectory. The Java and ODBC/CLI drivers are compressed.<br />

If you want to install individual drivers that are contained in the driver package,<br />

follow these steps (first two steps are common for all drivers):<br />

1. Extract the Data Server Driver Package archive onto the target system.<br />

2. For the Java and ODBC/CLI drivers, extract the driver file into the chosen<br />

installation directory.<br />

3. Install the driver that you need:<br />

– Java<br />

This driver provides support for client applications written in Java using<br />

JDBC. The path and file name of the Java driver are<br />

Path: jdbc_sqlj_driver/platform<br />

File name: db2_db2driver_for_jdbc_sqlj.zip<br />

For additional information, refer to “Installing <strong>IBM</strong> Data Server Driver for<br />

JDBC and SQLJ” on page 51.<br />

– ODBC and CLI<br />

The open source drivers included in the <strong>IBM</strong> Data Server Driver Package,<br />

such as PHP or Ruby driver, require the use of the Data Server CLI driver<br />

for connection to the database engine. If you plan to use any of these<br />

drivers, you need to install the ODBC driver.<br />

Path: odbc_cli_driver/platform<br />

File name: ibm_data_server_driver_for_odbc_cli.tar.Z<br />

For additional information, refer to “Installing <strong>IBM</strong> Data Server Driver for<br />

ODBC and CLI” on page 52.<br />

– PHP<br />

The <strong>IBM</strong>_DB2 and PDO_<strong>IBM</strong> are the PHP extensions for <strong>IBM</strong> Data<br />

Servers including <strong>Informix</strong>. Installing the <strong>IBM</strong>_DB2 or PDO_<strong>IBM</strong><br />

extensions enables any application in the PHP environment to interact with<br />

<strong>Informix</strong> database servers. The extensions included with the <strong>IBM</strong> Data<br />

Server Driver Package might be of a lower version as compared to the one<br />

available on the PHP repository.<br />

Download the latest extension from PHP repository page because it might<br />

contain important fixes and new features:<br />

For <strong>IBM</strong>_DB2<br />

http://pecl.php.net/package/ibm_db2<br />

For PDO_<strong>IBM</strong><br />

http://pecl.php.net/package/pdo_ibm<br />

Chapter 2. Setting up an <strong>Informix</strong> development environment 45


46 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong><br />

The PHP driver path and file names in the <strong>IBM</strong> Data Server Driver<br />

Packages are as follows:<br />

Path<br />

php_driver/platform/php32 or php_driver/platform/php64<br />

Files<br />

ibm_db2_n.n.n.so and pdo_ibm_n.n.n.so<br />

where n represents the version of the extension.<br />

Consider the following information before you install the PHP driver:<br />

Prerequisite: The PHP drivers require the ODBC/CLI driver that is also<br />

included in the <strong>IBM</strong> Data Server Driver Package to be installed.<br />

Installation instructions: The following online information explains how<br />

to install PECL extensions.<br />

Through the source code:<br />

http://www.php.net/manual/en/install.pecl.phpize.php<br />

Through the PECL command:<br />

http://www.php.net/manual/en/install.pecl.pear.php<br />

Installing the <strong>IBM</strong>_DB2 extension:<br />

http://www.php.net/manual/en/ibm-db2.installation.php<br />

Installing the PDO_<strong>IBM</strong> extension:<br />

http://www.php.net/pdo_ibm<br />

– Ruby on Rails<br />

The <strong>IBM</strong>_DB adapter and driver as a gem enables any application in the<br />

Ruby environment, including Rails, to interact with <strong>IBM</strong> data servers. The<br />

path, file name, and installation information for Ruby on Rails Driver is as<br />

follows:<br />

Path<br />

ruby_driver/platform<br />

File<br />

ibm_db-0.10.0.gem


Consider the following information before you install the Ruby on Rails<br />

Driver:<br />

Prerequisite: The Ruby on Rails Driver requires the ODBC/CLI driver<br />

that is also included in the <strong>IBM</strong> Data Server Driver Package to be<br />

installed.<br />

To install the Ruby on Rails Driver, from the location of the gem file, run<br />

the following command:<br />

gem install ibm_db-0.10.0.gem<br />

You are now ready to use any of these drivers on UNIX or Linux.<br />

Installing the driver package on Windows<br />

You can obtain the Data Server Driver Package for windows from the same site<br />

as the package for UNIX:<br />

http://www.ibm.com/support/fixcentral/<br />

The file for Windows is an .exe file, which is the installation file for the driver<br />

package.<br />

To install the driver package:<br />

1. Start the installation by executing the .exe file. The welcome window opens,<br />

as shown in Figure 2-11. Click Next.<br />

Figure 2-11 Welcome panel for Data Server Driver Package<br />

Chapter 2. Setting up an <strong>Informix</strong> development environment 47


2. On the Software License Agreement panel, accept the license agreement,<br />

and click Next.<br />

3. Specify the installation directory in the Custom Setup panel (Figure 2-12). You<br />

can change the installation directory to a location other then the default. Click<br />

Next.<br />

Figure 2-12 Change the installation directory<br />

48 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


4. The <strong>IBM</strong> data server driver copy name is used to identify a location where<br />

<strong>IBM</strong> Data Server Driver Package is installed on the computer. Enter the copy<br />

name for the location that you have chosen, the default is IBDBCL1<br />

(Figure 2-13). Click Next.<br />

Figure 2-13 Set the <strong>IBM</strong> data server driver copy name<br />

Chapter 2. Setting up an <strong>Informix</strong> development environment 49


5. Verify the installation selections on the summary panel (Figure 2-14). If<br />

everything is correct, begin the installation by clicking Install.<br />

Figure 2-14 Summary of the installation<br />

50 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


6. When the installation completes, the complete panel opens as shown in<br />

Figure 2-15. Click Finish. The installation of Data Server Driver for <strong>Informix</strong> is<br />

complete.<br />

Figure 2-15 Installation complete<br />

Note: The Windows installer of the <strong>IBM</strong> Data Server Driver Package does not<br />

provide any option to install individual components. All the drivers and<br />

interfaces that are included in the package are installed by default.<br />

Installing <strong>IBM</strong> Data Server Driver for JDBC and SQLJ<br />

To install <strong>IBM</strong> Data Server Driver for JDBC and SQLJ:<br />

1. Obtain Java SDK.<br />

Before you install the <strong>IBM</strong> Data Server Driver for JDBC and SQLJ, you must<br />

have an SDK for Java installed on your computer:<br />

– For JDBC 3.0 functions, you need Java SDK 1.4.2 or later.<br />

– For JDBC 4.0 functions, you need Java SDK 6 or later.<br />

2. Download the .zip file for the latest version of the <strong>IBM</strong> Data Server Driver for<br />

JDBC and SQLJ at:<br />

http://www.ibm.com/software/data/support/data-server-clients/download.html<br />

Chapter 2. Setting up an <strong>Informix</strong> development environment 51


3. Extract the <strong>IBM</strong> Data Server Driver for JDBC and SQLJ compressed file to the<br />

installation location. The compressed file contains the following files:<br />

– db2jcc.jar<br />

– db2jcc4.jar<br />

– sqlj.zip<br />

– sqlj4.zip<br />

4. Modify the CLASSPATH environment variable to include the appropriate files,<br />

You can set the CLASSPATH using the following command:<br />

java -classpath \.jar<br />

– For JDBC:<br />

Include the db2jcc.jar file in the CLASSPATH if you plan to use the<br />

version of the <strong>IBM</strong> Data Server Driver for JDBC and SQLJ that includes<br />

only JDBC 3.0 and earlier functions.<br />

Include the db2jcc4.jar file in the CLASSPATH if you plan to use the<br />

version of the <strong>IBM</strong> Data Server Driver for JDBC and SQLJ that includes<br />

JDBC 4.0 and earlier functions.<br />

– For SQLJ<br />

The steps are similar to the JDBC except that the files to be included in<br />

CLASSPATH are sqlj.zip and sqlj4.zip.<br />

For more information regarding configuration and customizing of the <strong>IBM</strong> Data<br />

Server Driver for JDBC and SQLJ, refer to:<br />

http://publib.boulder.ibm.com/infocenter/idshelp/v115/topic/com.ibm.jccids.doc/<br />

ids_jcc_0008.htm<br />

Installing <strong>IBM</strong> Data Server Driver for ODBC and CLI<br />

The <strong>IBM</strong> Data Server Driver for ODBC and CLI solution is designed mainly for<br />

independent software vendor (ISV) deployments.To install the <strong>IBM</strong> Data Server<br />

Driver for ODBC and CLI:<br />

1. Depending on your operating system, download the compressed file that is<br />

available at:<br />

https://www14.software.ibm.com/webapp/iwm/web/preLogin.do?land=en_US&source<br />

=swg-informixfpd<br />

2. Extract the file to an installation directory of your choice.<br />

52 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong><br />

Important: Include either the db2jcc.jar or the db2jcc4.jar files in the<br />

CLASSPATH. Do not include both files.


3. On Mac OS X, set the DYLD_LIBRARY_PATH environment variable to the<br />

clidriver/lib directory path.<br />

For specific information about the setup and configuration of the ODBC, refer to<br />

3.2, “Setup and configuration” on page 58.<br />

2.2.4 Setting up <strong>Informix</strong> JDBC<br />

<strong>Informix</strong> JDBC is a platform independent, industry-standard driver that provides<br />

enhanced support for distributed transactions. It consists of a set of interfaces<br />

and classes written in the Java programming language which can run on AIX,<br />

HP-UX, Linux, Solaris, Windows, and all other platforms that support Java. It also<br />

supports extensibility with a user-defined type (UDT) routine manager that<br />

simplifies the creation and use of UDTs.<br />

JCC support is available through the <strong>IBM</strong> Data Server Driver package that has a<br />

driver to run Java application using JCC.<br />

This section describes how to install <strong>Informix</strong> JDBC Driver, which is bundled with<br />

the <strong>Informix</strong> database server. There is a separate JDBC directory with a .jar file<br />

inside when you extract the <strong>Informix</strong> database server from the installation media.<br />

<strong>Informix</strong> JDBC Driver, Version 3.50, strives to be compliant with the Sun<br />

Microsystems JDBC 3.0 specification. Nearly all the features that are required for<br />

the Sun Microsystems JDBC 3.0 specification have the specified behavior. For<br />

the Sun Microsystems JDBC 3.0 driver optional features, if the feature is<br />

supported by <strong>IBM</strong> <strong>Informix</strong> Version 11.50, then it is supported by <strong>Informix</strong> JDBC<br />

Driver, Version 3.50.<br />

<strong>Informix</strong> JDBC Driver is a native-protocol, pure-Java driver (Type 4). Thus, when<br />

you use <strong>Informix</strong> JDBC Driver in a Java program that uses the JDBC API to<br />

connect to an <strong>Informix</strong> database, your session connects directly to the database<br />

or database server without a middle tier<br />

Installing the JDBC driver<br />

The JDBC driver installation procedure is same for both Windows and UNIX<br />

platforms.<br />

To install the JDBC driver in console mode, use the following command:<br />

java -cp dir/setup.jar run -console<br />

Chapter 2. Setting up an <strong>Informix</strong> development environment 53


For a silent installation on both Windows and UNIX, run the following command<br />

from a command prompt:<br />

java -cp /setup.jar run -silent -P<br />

product.installLocation=<br />

where:<br />

► is the location of the setup.jar file<br />

► is the directory where you want to install the JDBC driver<br />

The installation is complete when the command finishes executing. If you want to<br />

log information during the installation, specify the -log parameter.<br />

To install <strong>Informix</strong> JDBC Driver in GUI mode on Windows:<br />

1. Start the GUI mode installation with the following command:<br />

java -cp dir/setup.jar run<br />

The Welcome panel opens (Figure 2-16). Click Next.<br />

54 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong><br />

Figure 2-16 Starting panel for JDBC informix installation<br />

2. Accept the license agreement, and click Next.


3. Specify the installation directory or use the default location as shown in<br />

Figure 2-17, and click Next.<br />

Figure 2-17 Specify the installation directory<br />

4. Review the summary information that displays (Figure 2-18), and click Next<br />

complete the installation.<br />

Figure 2-18 Summary window<br />

Chapter 2. Setting up an <strong>Informix</strong> development environment 55


Configuring the JDBC driver<br />

To use JDBC driver in an application, you must set the CLASSPATH environment<br />

variable to point to the driver files. The CLASSPATH environment variable tells<br />

the JVM and other applications where to find the Java class libraries that are<br />

used in a Java program-log parameter.<br />

UNIX<br />

Use one of the following methods to set the CLASSPATH environment variable<br />

on a UNIX system:<br />

► Add the full path name of the ifxjdbc.jar file to CLASSPATH:<br />

56 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong><br />

setenv CLASSPATH /jdbcdriv/lib/ifxjdbc.jar:$CLASSPATH<br />

► Extract the ifxjdbc.jar file, and add its directory to CLASSPATH:<br />

cd /jdbcdriv/lib<br />

jar xvf ifxjdbc.jar<br />

setenv CLASSPATH /jdbcdriv/lib:$CLASSPATH<br />

Windows system<br />

Use one of the following methods to set the CLASSPATH environment variable<br />

on a Windows system:<br />

► Add the full path name of the ifxjdbc.jar file to CLASSPATH:<br />

set CLASSPATH=c:\jdbcdriv\lib\ifxjdbc.jar;%CLASSPATH%<br />

► Extract the ifxjdbc.jar file, and add its directory to CLASSPATH:<br />

cd c:\jdbcdriv\lib<br />

jar xvf ifxjdbc.jar<br />

set CLASSPATH=c:\jdbcdriv\lib;%CLASSPATH%<br />

You are now ready to develop a Java application using JDBC.


Chapter 3. Working with the ODBC<br />

driver<br />

This chapter discusses the configuration and development of applications using<br />

Open Database Connectivity (ODBC) interfaces to access an <strong>Informix</strong> database<br />

server.<br />

This chapter includes the following topics:<br />

► ODBC and <strong>Informix</strong><br />

► Setup and configuration<br />

► Developing an ODBC application<br />

3<br />

© Copyright <strong>IBM</strong> Corp. 2010. All rights reserved. 57


3.1 ODBC and <strong>Informix</strong><br />

ODBC is a software API method based on the X/Open Call Level Interface to<br />

access data from a database management system. ODBC allows developers to<br />

write database applications without having to know a proprietary interface for a<br />

specific database. In an ODBC environment, the ODBC driver is the component<br />

that directly communicates with the database server. It receives calls from the<br />

application or the ODBC Driver Manager and converts those calls into messages<br />

that the database server can understand.<br />

The following ODBC drivers for <strong>Informix</strong> are available:<br />

► <strong>IBM</strong> <strong>Informix</strong> ODBC Driver<br />

► <strong>IBM</strong> Data Server Driver for ODBC and CLI (CLI Driver)<br />

3.2 Setup and configuration<br />

In this section, we discuss the setup and configuration parameters of the ODBC<br />

driver.<br />

3.2.1 <strong>IBM</strong> <strong>Informix</strong> ODBC Driver<br />

The <strong>Informix</strong> ODBC Driver is installed by default as part of <strong>Informix</strong> Client<br />

Software Development Kit (Client SDK). It is based on the Microsoft Open<br />

Database Connectivity (ODBC) Version 3.0 standard.<br />

Table 3-1 lists the <strong>Informix</strong> database server that support <strong>Informix</strong> ODBC.<br />

Table 3-1 Supported databases<br />

Database server Versions<br />

<strong>IBM</strong> <strong>Informix</strong> 10.0,11.10,11.50<br />

<strong>IBM</strong> <strong>Informix</strong> Extended Parallel Server 8.50 and higher<br />

<strong>IBM</strong> <strong>Informix</strong> Standard Engine 7.25<br />

<strong>IBM</strong> <strong>Informix</strong> Online 5.20 and higher<br />

Windows system configuration<br />

On a Windows system, the ODBC drivers is registered automatically within the<br />

system during the <strong>Informix</strong> installation process.<br />

58 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


The following directory is the default installation directory:<br />

C:\Program Files\<strong>IBM</strong>\<strong>Informix</strong>\Client-SDK<br />

The INFORMIXDIR environment variable points to the directory where the<br />

product was installed.<br />

Note: If you install a 32-bit version of Client SDK on a Windows x64, the<br />

default directory is C:\Program Files (x86)\<strong>IBM</strong>\<strong>Informix</strong>\Client-SDK.<br />

The ODBC driver requires that additional libraries are loaded. These libraries are<br />

located in the %INFORMIXDIR%\bin directory. Make sure that this directory is part<br />

of your PATH variable.<br />

The name of the ODBC driver depends on the version:<br />

► <strong>IBM</strong> <strong>Informix</strong> ODBC Driver: For the Windows 32-bit driver, see Figure 3-1.<br />

Figure 3-1 Windows x86 ODBC driver administrator<br />

Chapter 3. Working with the ODBC driver 59


► <strong>IBM</strong> <strong>Informix</strong> ODBC Driver (64-bit): for the Windows 64-bit driver. See<br />

Figure 3-2.<br />

60 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong><br />

Figure 3-2 Windows x64 ODBC driver administrator<br />

To create an <strong>Informix</strong> ODBC Data Source (DSN), open the ODBC Administrator,<br />

choose a DSN type, and select the <strong>Informix</strong> ODBC driver, the DSN-configuration<br />

parameters are common to both drivers (32-bit and 64-bit).<br />

Note: The default ODBC Data Source Administrator on a Windows x64<br />

system is the 64-bit version. If you want to create a 32-bit ODBC DSN you<br />

must use the 32-bit version<br />

C:\WINDOWS\SysWOW64\odbcad32.exe


Figure 3-3 shows the <strong>Informix</strong> ODBC Connection tab.<br />

Figure 3-3 Connection parameters<br />

Table 3-2 lists the required DSN parameters. If you have already defined an<br />

<strong>Informix</strong> server using the setnet32.exe utility, which is a component of Client<br />

SDK, most of these values are updated automatically when selecting an <strong>Informix</strong><br />

server from the drop-down box.<br />

Table 3-2 Required DSN values<br />

Parameter Description<br />

Data source name Name of the DSN<br />

Server name Name of the <strong>Informix</strong> database server<br />

Host name Name or IP address of the computer where the database server<br />

runs<br />

Service Name or value of the tcp service used by the database server<br />

Protocol Communication Protocol used by the database server<br />

Database Name of the database to which the DSN connects by default<br />

Chapter 3. Working with the ODBC driver 61


You can set optional configuration parameters in the Environment and Advanced<br />

tabs (Figure 3-4).<br />

Figure 3-4 Environment parameters<br />

Table 3-3 describe the parameters for the Environment tab.<br />

Table 3-3 Environment parameters<br />

Parameter Description<br />

Client Locale Locale for the client machine<br />

Database Locale Locale used when the database was created<br />

Use Server Database Locale Using this option the Database Locale is automatically<br />

retrieved from the database<br />

Translation Library Code set conversion library<br />

Translation Option Options for a third-party conversion library<br />

Cursor Behavior Close or preserve a cursor when a transaction is<br />

resolved<br />

VMB Character How to report the length for Varying Multi byte<br />

characters<br />

Fetch Buffer Size Size of the communication data package<br />

Isolation Level Default Isolation Level for the connection<br />

62 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Note: The code set value for the Client Locale parameter is determined by the<br />

code set used in the application, which in most cases is the same as the<br />

operating system. The default code set on a Windows system is CP1252.<br />

The default code set for an <strong>Informix</strong> database is en_us.8859-1 (ISO 8859-1).<br />

Some versions of the <strong>IBM</strong> <strong>Informix</strong> database server (for example, Version 9.40<br />

and Version 10.00) allow a connection from a client with a mismatched<br />

DB_LOCALE value. This option is no longer available. A client application<br />

must set the Database Locale parameter (DB_LOCALE) to the same value as<br />

the locale of the database (locale used at creation time).<br />

The typical syntax for an <strong>Informix</strong> locale is language_territory@codeset.<br />

Figure 3-5 shows the Advanced tab configuration parameters.<br />

Figure 3-5 Advanced parameters<br />

Table 3-4 describes the parameters for the Advanced tab.<br />

Table 3-4 Advanced parameters<br />

Parameter Description<br />

Auto Commit Optimization Optimize client-server communication deferring<br />

the commit work after all the cursors are close.<br />

Open-Fetch-Close Optimization Optimize client-server communication<br />

automatically closing the cursor after all the<br />

rows have been retrieved.<br />

Chapter 3. Working with the ODBC driver 63


Parameter Description<br />

Insert Cursors Buffers all the rows send by an insert cursor<br />

and uses only one package to send the data to<br />

the server.<br />

Scrollable Cursors Enable scrollable cursors.<br />

Report KeySet Cursors Report support for KeySet-driver cursors.<br />

Report Standard ODBC Types Only Report standard ODBC types Only. Extended<br />

types are mapped to standard ODBC types.<br />

Describe Decimal Floating Point as<br />

SQL_REAL / SQL_DOUBLE<br />

64 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong><br />

Decimal columns without a scale are reported<br />

as SQL_REAL or SQL_DOUBLE.<br />

Do Not Use Lvarchar Do not report Lvarchar columns when using<br />

SQL_VARCHAR.<br />

Report Char columns as Wide Char<br />

columns<br />

length in Chars for<br />

SQLGetDiagRecW<br />

Char columns described by SQLDescribeCol<br />

are reported as Wide char columns<br />

(SQLWCHAR)<br />

Returns the number of characters rather than<br />

the number of bytes.


For more information about each one of these parameters, place the cursor over<br />

a parameter, and press F1 (Figure 3-6).<br />

Figure 3-6 ODBC DSN Help<br />

UNIX configuration<br />

On UNIX platforms, the default installation directory for Client SDK is the<br />

/opt/<strong>IBM</strong>/informix directory.<br />

The INFORMIXDIR environment variable should point to the directory where the<br />

product was installed.<br />

On UNIX platforms, an ODBC driver manager is not normally supplied as part of<br />

the operating system. Client SDK does not include an ODBC driver manager<br />

library, however, the Client SDK does have a Driver Manager Replacement<br />

(DMR) library which provides most of the features of an ODBC driver manager.<br />

If the application does not use an ODBC driver manager, such as unixODBC or<br />

Data Direct Driver Manager, the application must be linked directly to the <strong>Informix</strong><br />

ODBC libraries. The ODBC libraries are located in the $INFORMIXDIR/lib/cli<br />

directory.<br />

Chapter 3. Working with the ODBC driver 65


Table 3-5 shows the ODBC libraries that are included with Client SDK.<br />

Table 3-5 UNIX ODBC libraries<br />

Library Description<br />

libifcli.a or libcli.a Static version for single (nonthreaded)<br />

libifcli.so or iclis09b.so Shared version for single (nonthreaded)<br />

libthcli.a Static version for multithreaded library<br />

libthcli.so or iclit09b.so Shared version for multithreaded library<br />

libifdrm.so or idmrs09a.so Shared library for DMR (thread safe)<br />

The shared-library path environment variable specifies the library search path.<br />

This variable should contains at least $INFORMIX/lib, $INFORMIXDIR/lib/esql,<br />

and $INFORMIXDIR/lib/cli for the ODBC driver to work.<br />

There are three configuration files for the ODBC driver:<br />

► sqlhosts<br />

► odbc.ini<br />

► odbcinst.ini<br />

Note: The information in the sqlhosts file is also used by all the other Client<br />

SDK components and by the <strong>Informix</strong> database server. Be aware that any<br />

changes in this file can have an impact in other clients and servers.<br />

On a Windows system, instead of using a text file, this information is stored in<br />

the registry through the setnet32.exe utility.<br />

The sqlhosts file<br />

This text file contains most of the information that is required to connect to an<br />

<strong>IBM</strong> <strong>Informix</strong> database server.<br />

The default location for this file is the $INFORMIXDIR/etc/sqlhosts directory. You<br />

can use the INFORMIXSQLHOSTS environment variable to point to a different<br />

location.<br />

Example 3-1 shows a simple sqlhosts file.<br />

Example 3-1 The sqlhosts file<br />

#server protocol hostname service/port<br />

on_demo onsoctcp kodiak 9088<br />

66 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


For more information about the sqlhosts file, refer to the Client/Server<br />

Communications manual at:<br />

http://publib.boulder.ibm.com/infocenter/idshelp/v115/topic/com.ibm.admin.doc/i<br />

ds_admin_0158.htm<br />

The odbcinst.ini file<br />

This file contains a list of installed ODBC drivers on the UNIX system and<br />

specific attributes for each driver, such as the location of the shared library.<br />

The default location of this file is under the home directory as<br />

$HOME/.odbcinst.ini. A sample odbcinst.ini file is located in the<br />

$INFORMIXDIR/etc directory.<br />

Example 3-2 shows a simple odbcinst.ini file.<br />

Example 3-2 The odbcinst.ini file<br />

;---------------------------------------------------------------------------<br />

[ODBC Drivers]<br />

<strong>IBM</strong> INFORMIX ODBC DRIVER=Installed<br />

[<strong>IBM</strong> INFORMIX ODBC DRIVER]<br />

Driver=/extra/informix/lib/cli/iclit09b.so<br />

Setup=/extra/informix/lib/cli/iclit09b.so<br />

APILevel=1<br />

ConnectFunctions=YYY<br />

DriverODBCVer=03.51<br />

FileUsage=0<br />

SQLLevel=1<br />

smProcessPerConnect=Y<br />

The odbinst.ini file has two sections:<br />

► ODBC Drivers: Lists the ODBC drivers installed in the system.<br />

► Driver Properties: Lists the properties for a specific ODBC driver.<br />

Table 3-6 lists the parameters in the Driver Properties section.<br />

Table 3-6 Parameters in the Driver Properties section<br />

Keyword Description<br />

Driver Location of the ODBC library<br />

Setup Location of the Setup library<br />

APILevel ODBC interface conformance level that the driver supports<br />

ConnectFunctions Support for SQLConnect, SQLDriverConnect, and<br />

SQLBrowserConnect<br />

Chapter 3. Working with the ODBC driver 67


Keyword Description<br />

DriverODBCVer Supported version of the ODBC driver<br />

FileUsage How handle File-system DSN<br />

SQLLevel Type of SQL-92 grammar supported<br />

The odbc.ini file<br />

The odbc.ini file is the data source configuration information. The default<br />

location of this file is under the home directory as $HOME/.odbc.ini.<br />

Alternatively, you can use the ODBCINI environment variable to point the<br />

odbc.ini to a different location. A sample odbc.ini file is located in the<br />

$INFORMIXDIR/etc directory.<br />

Example 3-3 shows a simple odbc.ini file.<br />

Example 3-3 The odbc.ini file<br />

[ODBC Data Sources]<br />

Infdrv1=<strong>IBM</strong> INFORMIX ODBC DRIVER<br />

;<br />

[Infdrv1]<br />

Driver=/extra/informix/lib/cli/iclis09b.so<br />

Description=<strong>IBM</strong> INFORMIX ODBC DRIVER<br />

Database=stores_demo<br />

LogonID=odbc<br />

pwd=odbc<br />

Servername=demo_on<br />

CursorBehavior=0<br />

CLIENT_LOCALE=en_us.8859-1<br />

DB_LOCALE=en_us.8859-1<br />

TRANSLATIONDLL=/extra/informix/lib/esql/igo4a304.so<br />

;<br />

[ODBC]<br />

;UNICODE=UCS-4<br />

;<br />

; Trace file Section<br />

;<br />

Trace=0<br />

TraceFile=/tmp/odbctrace.out<br />

InstallDir=/extra/informix<br />

TRACEDLL=idmrs09a.so<br />

68 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


This file contains three sections:<br />

► ODBC Data Sources: DSN name and description of the driver used<br />

► Data Source Specification: Configuration parameters for this particular DSN<br />

► ODBC: Global options such as Unicode mode or Tracing<br />

Table 3-7 lists the available parameters for the odbc.ini configuration file.<br />

Table 3-7 Parameters for the odbc.ini file<br />

Keyword Description<br />

Driver Location of the ODBC shared library<br />

Description DSN description<br />

Database Database name<br />

LogonID User Id<br />

pwd Password<br />

Server Database server<br />

CLIENT_LOCALE Locale used by the client application<br />

DB_LOCALE Locale of the database<br />

TRANSLATIONDLL Location of the code set conversion library<br />

CURSORBEHAVIOR Close or preserve a cursor when a<br />

transaction is resolved<br />

DefaultUDTFetchType Default type for a UDT (SQL_C_BINARY<br />

or SQL_C_CHAR)<br />

ENABLESCROLLABLECURSORS Enable Scrollable cursors<br />

ENABLEINSERTCURSORS Optimize insert cursors process<br />

OPTIMIZEAUTOCOMMIT Defer the commit message after all cursor<br />

are closed<br />

NEEDODBCTYPESONLY Extended types are mapped to standard<br />

ODBC types<br />

OPTOFC Close cursors after all the rows have been<br />

fetched<br />

REPORTKEYSETCURSORS Report support for keyset-driven cursors<br />

FETCHBUFFERSIZE Set the size of the fetch buffer<br />

Chapter 3. Working with the ODBC driver 69


Keyword Description<br />

DESCRIBEDECIMALFLOATPOINT Describe float types as SQL_REAL or<br />

SQL_DOUBLE<br />

USESERVERDBLOCALE Use the server database locale<br />

DONOTUSELVARCHAR Don’t report Lvarchar columns when using<br />

SQL_VARCHAR<br />

REPORTCHARCOLASWIDECHARCOL Char columns described by<br />

SQLDescribeCol are reported as Wide<br />

char columns (SQLWCHAR)<br />

ISOLATIONLEVEL Default isolation level<br />

UNICODE Type of Unicode (UCS-2, UCS-4)<br />

TRACE Trace enable or disable<br />

TRACEFILE Location of the trace file<br />

TRACEDLL Trace library name (idmrs09a.so)<br />

3.2.2 <strong>IBM</strong> Data Server Driver for ODBC and CLI<br />

The <strong>IBM</strong> Data Server Driver for ODBC and CLI (CLI Driver) is installed as part of<br />

the <strong>IBM</strong> Data Server Driver Package or as a separate product. The <strong>IBM</strong> Data<br />

Server Package is bundle with Client SDK. It allows you to connect to <strong>IBM</strong><br />

<strong>Informix</strong> and <strong>IBM</strong> DB2 databases with the same set of libraries.<br />

The communication protocol used is DRDA instead of the native <strong>Informix</strong> SQLI.<br />

This driver is supported against <strong>Informix</strong> Version 11.10 and Version 11.50.<br />

Windows system configuration<br />

The <strong>IBM</strong> Data Server Driver installs in the following directory by default:<br />

C:\Program Files\<strong>IBM</strong>\<strong>IBM</strong> DATA SERVER DRIVER<br />

The ODBC driver is registered in the Windows system during the installation of<br />

the <strong>IBM</strong> Data Server Driver package. The name of the ODBC driver is <strong>IBM</strong> DB2<br />

ODBC Driver.<br />

70 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Figure 3-7 shows the Drivers tab of the ODBC Data Source Administrator, which<br />

lists both ODBC drivers:<br />

► <strong>IBM</strong> DB2 ODBC DRIVER<br />

► <strong>IBM</strong> INFORMIX ODBC DRIVER<br />

Figure 3-7 ODBC Data Source Administrator<br />

To create an ODBC Data Source (DSN) using the <strong>IBM</strong> Data Server Driver, open<br />

the ODBC Administrator, choose a DSN type, and select the <strong>IBM</strong> DB2 ODBC<br />

Driver.<br />

Figure 3-8 shows the Add dialog box.<br />

Figure 3-8 DSN Add dialog box<br />

Chapter 3. Working with the ODBC driver 71


If there is no database alias defined, you must add one with the connection<br />

details of your <strong>IBM</strong> <strong>Informix</strong> database server (Figure 3-9).<br />

Figure 3-9 DSN Settings dialog box<br />

Figure 3-10 shows the Advanced Settings tab.<br />

Figure 3-10 DSN Advanced Settings dialog box<br />

72 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Table 3-8 lists the minimum required parameters to connect to an <strong>Informix</strong> server.<br />

Table 3-8 CLI parameters<br />

CLI parameter Description<br />

Hostname Name of the system where the <strong>Informix</strong> server is running<br />

Port TCP Port used by the DRDA <strong>Informix</strong> alias<br />

Protocol Transport protocol (TCP/IP)<br />

Database Database server<br />

The configuration settings are stored as a File-DSN (a text file that contains all<br />

the information that is required to connect to the database) in the<br />

%USERPROFILE%\db2cli.ini file. Example 3-4 shows a db2cli.ini file.<br />

Example 3-4 The db2cli.ini file<br />

[test]<br />

Database=stores_demo<br />

Protocol=TCPIP<br />

Port=9089<br />

Hostname=kodiak<br />

For a complete description of all the CLI parameters, refer to the DB2 Information<br />

Center at:<br />

http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/index.jsp?topic=/com.ibm.d<br />

b2.luw.apdv.cli.doc/doc/r0007964.html<br />

UNIX configuration<br />

On UNIX platforms, the default installation directory for <strong>IBM</strong> Data Server Client<br />

package is /opt/<strong>IBM</strong>/db2/V9.7. The library for the ODBC driver is libdb2.a,<br />

which is located in the lib directory of your Data Server installation.<br />

Similar to the installation on a Windows system, the ODBC configuration is<br />

stored in the db2cli.ini file, which by default is included in the cfg directory of<br />

your Data Server installation or is defined by the DB2CLIINI environment variable<br />

Chapter 3. Working with the ODBC driver 73


Example 3-5 shows a simple db2cli.ini file.<br />

Example 3-5 The db2cli.ini file<br />

[test]<br />

Database=stores_demo<br />

Protocol=TCPIP<br />

Port=9089<br />

Hostname=kodiak<br />

For more information about the db2cli.ini file, refer to:<br />

http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/index.jsp?topic=/com.ibm.d<br />

b2.luw.apdv.cli.doc/doc/c0007882.html<br />

3.2.3 Verifying connectivity<br />

On a Windows system, you can use the ODBC Data Source Administrator to<br />

verify the connection with the <strong>Informix</strong> database server.<br />

When using the <strong>IBM</strong> <strong>Informix</strong> ODBC driver, you can verify the connection using<br />

the Apply & Test Connection option, as shown in Figure 3-11.<br />

Figure 3-11 <strong>Informix</strong> ODBC connection test<br />

74 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


With the <strong>IBM</strong> Data Server Driver for ODBC, you can perform the connection test<br />

using the Connect option, as shown in Figure 3-12.<br />

Figure 3-12 <strong>IBM</strong> Data Server Driver connection test<br />

Client SDK on UNIX does not include any tool to test an ODBC DSN. You can<br />

use the C samples in $INFORMIXDIR\demo\cli to check whether the ODBC DSN<br />

is working.<br />

3.3 Developing an ODBC application<br />

In this section, we describe how to connect to a database server, type mapping<br />

between standard ODBC and <strong>IBM</strong> <strong>Informix</strong>, and how to perform basic operations<br />

with the ODBC driver.<br />

3.3.1 Connecting to the database<br />

Typically, an ODBC application performs the following steps:<br />

1. Connects to the database.<br />

To connect to the database, the application must pass the connection details<br />

to the ODBC driver. These details can be included directly in the connection<br />

string or stored as a Data Source Name (DSN).<br />

2. Processes SQL statements.<br />

Chapter 3. Working with the ODBC driver 75


The application sends SQL request to the ODBC driver to perform database<br />

operations (insert, select, delete, update, and so on).<br />

3. Resolves any open transaction.<br />

If the application is using a transaction, it resolves (commits or rolls back) any<br />

open transactions.<br />

4. Terminates the connection, and frees the allocated resources.<br />

These steps are done using the ODBC API functions. Figure 3-13 shows a<br />

typical sequence of calls. The labels inside the gray boxes correspond with the<br />

ODBC API functions that are used.<br />

Figure 3-13 Typical ODBC calls used by applications<br />

Example 3-6 shows a simple C program that connects to an ODBC DSN.<br />

76 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Example 3-6 A test_connect.c sample<br />

#include <br />

#include <br />

#include <br />

#ifdef WIN32<br />

#include <br />

#include <br />

#include <br />

#endif<br />

#include "infxcli.h"<br />

int main (long argc, char* argv[])<br />

{<br />

SQLHDBC hdbc;<br />

SQLHENV henv;<br />

SQLRETURN rc = 0;<br />

SQLCHAR connStrIn[1000];<br />

SQLCHAR connStrOut[1000];<br />

SQLSMALLINT connStrOutLen;<br />

if (argc != 2)<br />

{<br />

fprintf (stdout, "Please specify the name of a DSN!\n");<br />

return(1);<br />

}<br />

else<br />

{<br />

if (strstr (argv[1],"DRIVER")==NULL)<br />

sprintf((char *) connStrIn, "DSN=%s;", (char *)argv[1]);<br />

else<br />

sprintf((char *) connStrIn, "%s;", (char *)argv[1]);<br />

}<br />

rc = SQLAllocHandle (SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);<br />

if (rc != SQL_SUCCESS)<br />

{<br />

fprintf (stdout, "Environment Handle Allocation failed!\n");<br />

return (1);<br />

}<br />

rc = SQLSetEnvAttr (henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) SQL_OV_ODBC3, 0);<br />

if (rc != SQL_SUCCESS)<br />

{<br />

fprintf (stdout, "SQLSetEnvAttr failed!\n");<br />

return (1);<br />

}<br />

rc = SQLAllocHandle (SQL_HANDLE_DBC, henv, &hdbc);<br />

if (rc != SQL_SUCCESS)<br />

{<br />

Chapter 3. Working with the ODBC driver 77


}<br />

78 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong><br />

}<br />

fprintf (stdout, "Connection Handle Allocation failed!\n");<br />

return (1);<br />

rc = SQLDriverConnect (hdbc, NULL, connStrIn, SQL_NTS, connStrOut, 1000,<br />

&connStrOutLen, SQL_DRIVER_NOPROMPT);<br />

if (rc != SQL_SUCCESS)<br />

{<br />

fprintf (stdout, "Connectedion failed!\n");<br />

return (1);<br />

}<br />

fprintf (stdout, "Connected\n");<br />

SQLDisconnect (hdbc);<br />

SQLFreeHandle (SQL_HANDLE_DBC, hdbc);<br />

SQLFreeHandle (SQL_HANDLE_ENV, henv);<br />

return (rc);<br />

You can compile this code on a Windows system using the following command:<br />

cl /DWIN32 -I%INFORMIXDIR%\incl\cli odbc32.lib test_connect.c<br />

Example 3-7 shows how to compile and run the sample.<br />

Example 3-7 The test_connec.c sample output<br />

c:\work>cl /DWIN32 /D_CRT_SECURE_NO_DEPRECATE -I%INFORMIXDIR%\incl\cli<br />

odbc32.lib /nologo test_connect.c<br />

test_connect.c<br />

D:\work>test_connect<br />

Please specify the name of a DSN!<br />

D:\workt>test_connect dummy_dsn<br />

Connection failed!<br />

D:\work>test_connect test<br />

Connected<br />

D:\work>


3.3.2 Type mapping<br />

You can use the sample C program to perform a DSN-less connection.<br />

Example 3-8 shows the sample C program with a DSN-less connection string<br />

using the <strong>Informix</strong> ODBC driver and the Data Server driver for ODBC.<br />

Example 3-8 A DSN-less connection<br />

C:\work>test_connect "DRIVER={<strong>IBM</strong> INFORMIX ODBC<br />

DRIVER};SERVER=demo_on;DATABASE=stores_demo;HOST=kodiak;PROTOCOL=onsoctcp;SERVI<br />

CE=9088;UID=informix;PWD=password;";<br />

Connected<br />

C:\work>test_connect "driver={<strong>IBM</strong> DB2 ODBC<br />

DRIVER};Database=stores_demo;hostname=kodiak;port=9089;protocol=TCPIP;<br />

uid=informix; pwd=password"<br />

Connected<br />

C:\work><br />

The data types that are used on the database differ from the data types that are<br />

used by your application. This section shows the data type mapping that is<br />

needed when working with specific <strong>Informix</strong> data types with the <strong>Informix</strong> ODBC<br />

driver.<br />

When a query is executed by the application, the data returned by the <strong>Informix</strong><br />

server might be in a different format than what the application uses. The ODBC<br />

driver converts the data that is passed between the application and the database<br />

server. This process is invisible to the application. The only requirement for the<br />

application is to specify the correct data types when calling the ODBC driver<br />

functions.<br />

The application sets ValueType and ParameterType when calling the bind<br />

functions.<br />

Example 3-9 shows the definition for one of the bind functions,<br />

SQLBindParameter(). The ODBC driver converts the data type specified in<br />

ValueType to the data type specified in ParameterType.<br />

Example 3-9 SQLBindParameter definition<br />

SQLBindParameter(<br />

SQLHSTMT StatementHandle, /* hstmt */<br />

SQLUSMALLINT ParameterNumber, /* ipar */<br />

SQLSMALLINT InputOutputType, /* fParamType */<br />

SQLSMALLINT ValueType, /* fCType */<br />

SQLSMALLINT ParameterType, /* fSqlType */<br />

SQLUINTEGER ColumnSize, /* cbColDef */<br />

Chapter 3. Working with the ODBC driver 79


SQLSMALLINT DecimalDigits, /* ibScale */<br />

SQLPOINTER ParameterValuePtr, /* rgbValue */<br />

SQLINTEGER BufferLength, /* cbValueMax */<br />

SQLINTEGER *StrLen_or_IndPtr); /* pcbValue */<br />

Example 3-10shows an SQLBindParameter() call where the application is binding<br />

an SQL_C_BINARY parameter with an SQL_INFX_UDT_FIXED value.<br />

Example 3-10 Using an SQLBindParameter() call<br />

SQLBindParameter (<br />

hstmt,<br />

1,<br />

SQL_PARAM_INPUT,<br />

SQL_C_BINARY,<br />

SQL_INFX_UDT_FIXED,<br />

loptr_size,<br />

0,<br />

loptr_buffer,<br />

loptr_size,<br />

&loptr_valsize);<br />

Table 3-9 shows the <strong>Informix</strong>-specific data type mapping that is used with the<br />

<strong>Informix</strong> ODBC driver.<br />

Table 3-9 Mapping for specific <strong>Informix</strong> data types<br />

<strong>Informix</strong> SQL <strong>Informix</strong> ODBC driver<br />

BIGINT SQL_INFX_BIGINT<br />

BIGSERIAL SQL_INFX_BIGINT<br />

BLOB SQL_IFMX_UDT_BLOB<br />

BOOLEAN SQL_BIT<br />

BYTE SQL_LONGVARBINARY<br />

CLOB SQL_IFMX_UDT_CLOB<br />

DATETIME SQL_TIMESTAMP<br />

DISTINCT Any<br />

IDSSECURITYLABEL Built-in DISTINCT OF VARCHAR(128)<br />

INT8 SQL_BIGINT<br />

INTERVAL DAY SQL_INTERVAL_DAY<br />

80 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


<strong>Informix</strong> SQL <strong>Informix</strong> ODBC driver<br />

INTERVAL DAY TO HOUR SQL_INTERVAL_DAY_TO_HOUR<br />

INTERVAL DAY TO MINUTE SQL_INTERVAL_DAY_TO_MINUTE<br />

INTERVAL DAY TO SECOND SQL_INTERVAL_DAY_TO_SECOND<br />

INTERVAL HOUR SQL_INTERVAL_HOUR<br />

INTERVAL HOUR TO MINUTE SQL_INTERVAL_HOUR_TO_MINUTE<br />

INTERVAL HOUR TO SECOND SQL_INTERVAL_HOUR_TO_SECOND<br />

INTERVAL MINUTE SQL_INTERVAL_MINUTE<br />

INTERVAL MINUTE TO SECOND SQL_INTERVAL_MINUTE _TO_SECOND<br />

INTERVAL MONTH SQL_INTERVAL_MONTH<br />

INTERVAL SECOND SQL_INTERVAL_SECOND<br />

INTERVAL YEAR SQL_INTERVAL_YEAR<br />

INTERVAL YEAR TO MONTH SQL_INTERVAL_YEAR_TO_MONTH<br />

LIST, MULTISET, SET Any<br />

LVARCHAR SQL_VARCHAR<br />

MONEY SQL_DECIMAL<br />

NCHAR SQL_CHAR<br />

NVARCHAR SQL_VARCHAR<br />

OPAQUE (fixed) SQL_INFX_UDT_FIXED<br />

OPAQUE (varying) SQL_INFX_UDT_VARYING<br />

ROW Any<br />

SERIAL SQL_INTEGER<br />

SERIAL8 SQL_BIGINT<br />

TEXT SQL_LONGVARCHAR<br />

For a complete list of Data Type mapping, refer to the <strong>IBM</strong> <strong>Informix</strong> ODBC Driver<br />

Programmer’s Manual, which is available at:<br />

http://publib.boulder.ibm.com/infocenter/idshelp/v115/topic/com.ibm.odbc.doc/si<br />

i04979050.htm#sii04979050<br />

Chapter 3. Working with the ODBC driver 81


If your application requires only Standard ODBC data types, you can enable the<br />

Report Standard ODBC Types option in your DSN or connection string. When<br />

this option is enabled, the ODBC driver handles smart large objects (BLOB and<br />

CLOB) as though they were simple large objects (byte and text). The driver<br />

generates the smart-large-object calls (ifx_lo_open, ifx_lo_write, and so on)<br />

automatically.<br />

This option changes the mapping for user define types (including MULTISET,<br />

SET, ROW, and LIST) to SQL_C_CHAR.<br />

These options are also available as the following ODBC attributes:<br />

► SQL_INFX_ATTR_ODBC_TYPES_ONLY<br />

► SQL_INFX_ATTR_LO_AUTOMATIC<br />

► SQL_INFX_ATTR_DEFAULT_UDT_FETCH_TYPE<br />

3.3.3 Performing database operations<br />

In this section, we show samples of how to use the ODBC driver to perform basic<br />

operations with an <strong>Informix</strong> database. Most of these tasks are common to any<br />

ODBC application, so we do not explain them in detail.<br />

This section includes the following topics:<br />

► Simple SQL statements<br />

► Fetching data<br />

► Using parameters<br />

► Calling SQL routines<br />

► Local transactions<br />

► Distributed transactions<br />

Simple SQL statements<br />

You can run SQL statements directly using the SQLExecDirect() function. This<br />

function is commonly used when there is no need to run the SQL statement more<br />

than once. The ODBC driver prepares the statement, executes it, and frees the<br />

resources in one operation.<br />

Example 3-11 shows a sample of using the SQLExecDirect() function to set the<br />

LOCK WAIT time out.<br />

Example 3-11 SQLExecDirect() sample, Simple_sql.c<br />

#include <br />

#include <br />

#include <br />

#ifdef WIN32<br />

82 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


#include <br />

#include <br />

#include <br />

#endif<br />

#include "infxcli.h"<br />

int main (long argc, char* argv[])<br />

{<br />

SQLHDBC hdbc;<br />

SQLHENV henv;<br />

SQLHSTMT hstmt;<br />

SQLRETURN rc = 0;<br />

SQLCHAR connStrIn[1000];<br />

SQLCHAR connStrOut[1000];<br />

SQLSMALLINT connStrOutLen;<br />

int sqllen;<br />

SQLCHAR *sqlstmt;<br />

if (argc != 3)<br />

{<br />

fprintf (stdout, "Please specify the name of a DSN and the SQL Statement to<br />

run!\n");<br />

return(1);<br />

}<br />

else<br />

{<br />

if (strstr (argv[1],"DRIVER")==NULL)<br />

sprintf((char *) connStrIn, "DSN=%s;", (char *)argv[1]);<br />

else<br />

sprintf((char *) connStrIn, "%s;", (char *)argv[1]);<br />

}<br />

sqllen = strlen((char *)argv[2]);<br />

sqlstmt = (SQLCHAR *) malloc (sqllen + sizeof(char));<br />

strcpy((char *)sqlstmt, (char *)argv[2]);<br />

rc = SQLAllocHandle (SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);<br />

if (rc != SQL_SUCCESS)<br />

{<br />

fprintf (stdout, "Environment Handle Allocation failed!\n");<br />

return (1);<br />

}<br />

rc = SQLSetEnvAttr (henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) SQL_OV_ODBC3, 0);<br />

if (rc != SQL_SUCCESS)<br />

{<br />

fprintf (stdout, "SQLSetEnvAttr failed!\n");<br />

return (1);<br />

}<br />

Chapter 3. Working with the ODBC driver 83


84 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong><br />

rc = SQLAllocHandle (SQL_HANDLE_DBC, henv, &hdbc);<br />

if (rc != SQL_SUCCESS)<br />

{<br />

fprintf (stdout, "Connection Handle Allocation failed!\n");<br />

return (1);<br />

}<br />

rc = SQLDriverConnect (hdbc, NULL, connStrIn, SQL_NTS, connStrOut, 1000,<br />

&connStrOutLen, SQL_DRIVER_NOPROMPT);<br />

if (rc != SQL_SUCCESS)<br />

{<br />

fprintf (stdout, "Connection failed!\n");<br />

return (1);<br />

}<br />

}<br />

fprintf (stdout, "Connected\n");<br />

rc = SQLAllocHandle (SQL_HANDLE_STMT, hdbc, &hstmt );<br />

if (rc != SQL_SUCCESS)<br />

{<br />

fprintf (stdout, "Statement Handle Allocation failed!\n");<br />

return (1);<br />

}<br />

rc = SQLExecDirect (hstmt, sqlstmt, SQL_NTS);<br />

if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO)<br />

{<br />

fprintf (stdout, "SQLExecDirectW() failed!\n");<br />

return (1);<br />

}<br />

fprintf (stdout, "Executed SQL Statement:\n%s\n",sqlstmt);<br />

SQLDisconnect (hdbc);<br />

SQLFreeHandle (SQL_HANDLE_DBC, hdbc);<br />

SQLFreeHandle (SQL_HANDLE_ENV, henv);<br />

return (rc);<br />

Example 3-12 shows the result of running the sample program with different SQL<br />

statements. In this example, we input the SQL statement directly from the<br />

command line. In a real application, the SQL is normally constructed based on<br />

customer input.<br />

In this simple example, we also did not provide error information if the execution<br />

fails. You can obtain error information using the SQLGetDiagRec() function, which<br />

we discuss in 3.3.5, “Error handling” on page 112.


Example 3-12 Output of SQLDirectExec sample<br />

c:\work>cl /DWIN32 /D_CRT_SECURE_NO_DEPRECATE -I%INFORMIXDIR%\incl\cli<br />

odbc32.lib /nologo simple_sql.c<br />

simplesql.c<br />

c:\work>simples_sql.exe test "set lock mode to wait 10"<br />

Connected<br />

Executed SQL Statement:<br />

set lock mode to wait 10<br />

c:\work>simple_sql.exe test "create temp table temp1(c1 int)"<br />

Connected<br />

Executed SQL Statement:<br />

create temp table temp1(c1 int)<br />

c:\work>simple_sql.exe test "invalid_SQL"<br />

Connected<br />

SQLExecDirectW() failed!<br />

c:\work><br />

Fetching data<br />

Example 3-13 demonstrates how to run a SELECT statement to retrieve data<br />

from the server. To make the code clear, we have removed all the error handling.<br />

Example 3-13 Select.c sample<br />

#include <br />

#include <br />

#include <br />

#ifdef WIN32<br />

#include <br />

#include <br />

#include <br />

#endif<br />

#include "infxcli.h"<br />

int main (long argc, char* argv[])<br />

{<br />

SQLHDBC hdbc;<br />

SQLHENV henv;<br />

SQLHSTMT hstmt;<br />

SQLRETURN rc = 0;<br />

SQLCHAR connStrIn[1000];<br />

SQLCHAR connStrOut[1000];<br />

SQLSMALLINT connStrOutLen;<br />

SQLCHAR sqlstmt[100];<br />

SQLCHAR code[2+1];<br />

Chapter 3. Working with the ODBC driver 85


}<br />

SQLCHAR sname[15+1];<br />

SQLLEN lcode=0;<br />

SQLLEN lsname=0;<br />

86 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong><br />

sprintf((char *) connStrIn, "DSN=demo_on");<br />

sprintf((char *) sqlstmt, "SELECT code, sname FROM state where code


Using parameters<br />

In most of the cases, an application runs the same SQL statement several times,<br />

so it makes sense if the SQL statement is prepared and then used with different<br />

values.<br />

Example 3-15 demonstrates how to run a simple SQL SELECT statement using<br />

an input parameter. The SQL statement is prepared and then executed with one<br />

parameter.<br />

Example 3-15 Example of a parametrized query, Select_param.c<br />

#include <br />

#include <br />

#include <br />

#ifdef WIN32<br />

#include <br />

#include <br />

#include <br />

#endif<br />

#include "infxcli.h"<br />

int main (long argc, char* argv[])<br />

{<br />

SQLHDBC hdbc;<br />

SQLHENV henv;<br />

SQLHSTMT hstmt;<br />

SQLRETURN rc = 0;<br />

SQLCHAR connStrIn[1000];<br />

SQLCHAR connStrOut[1000];<br />

SQLSMALLINT connStrOutLen;<br />

SQLCHAR sqlstmt[100];<br />

SQLCHAR inputcode[2+1];<br />

SQLCHAR code[2+1];<br />

SQLCHAR sname[15+1];<br />

SQLLEN lcode = 0;<br />

SQLLEN lsname = 0;<br />

SQLSMALLINT datatype, decimaldigits, nullable;<br />

SQLUINTEGER paramsize;<br />

sprintf((char *) connStrIn, "DSN=demo_on");<br />

sprintf((char *) sqlstmt, "SELECT code, sname FROM state where code < ?");<br />

sprintf((char *) inputcode, "CA");<br />

SQLAllocHandle (SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);<br />

SQLSetEnvAttr (henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) SQL_OV_ODBC3, 0);<br />

SQLAllocHandle (SQL_HANDLE_DBC, henv, &hdbc);<br />

SQLDriverConnect (hdbc, NULL, connStrIn, SQL_NTS, connStrOut, sizeof(connStrOut),<br />

&connStrOutLen, SQL_DRIVER_NOPROMPT);<br />

Chapter 3. Working with the ODBC driver 87


fprintf (stdout, "Connected\n");<br />

88 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong><br />

SQLAllocHandle (SQL_HANDLE_STMT, hdbc, &hstmt );<br />

SQLPrepare (hstmt, sqlstmt, strlen(sqlstmt));<br />

SQLDescribeParam(hstmt, 1, &datatype, &paramsize, &decimaldigits, &nullable);<br />

SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, datatype, paramsize,<br />

decimaldigits, inputcode, 0, NULL);<br />

}<br />

SQLExecute (hstmt);<br />

fprintf (stdout, "Executed SQL Statement:\n%s\nUsing: '%s'\n",sqlstmt,inputcode);<br />

SQLBindCol (hstmt, 1, SQL_C_CHAR, &code, sizeof(code), &lcode);<br />

SQLBindCol (hstmt, 2, SQL_C_CHAR, &sname, sizeof(sname), &lsname);<br />

while ((rc = SQLFetch(hstmt))!=SQL_NO_DATA_FOUND)<br />

fprintf (stdout, "Fetched: %s, %s\n",code, sname);<br />

SQLCloseCursor(hstmt);<br />

SQLDisconnect (hdbc);<br />

SQLFreeHandle (SQL_HANDLE_DBC, hdbc);<br />

SQLFreeHandle (SQL_HANDLE_ENV, henv);<br />

return (rc);<br />

Example 3-16 shows the SQL statement that the program prepares and the<br />

parameter that is used for the placeholder.<br />

Example 3-16 Output for Select_param.c<br />

C:\work>cl /DWIN32 /D_CRT_SECURE_NO_DEPRECATE -ID:\infx\csdk350tc7\incl\cli<br />

odbc32.lib /nologo select_param.c<br />

select_param.c<br />

C:\work>select_param<br />

Connected<br />

Executed SQL Statement:<br />

SELECT code, sname FROM state where code < ?<br />

Using: 'CA'<br />

Fetched: AK, Alaska<br />

Fetched: AL, Alabama<br />

Fetched: AR, Arkansas<br />

Fetched: AZ, Arizona<br />

C:\work>


Calling SQL routines<br />

In this section, we demonstrate how to call an SQL routine from an ODBC<br />

application. The following example is a simple stored procedure that returns the<br />

user name and session ID:<br />

create procedure get_sid(user char(20)) returning char(100);<br />

return 'user= '||trim(user)|| ' session= '||dbinfo('sessionid');<br />

end procedure;<br />

We use the following ODBC standard syntax for calling a database routine:<br />

{? = call client_routine(?, ?,...)}<br />

The first placeholder (?) is used only when the first parameter of the routine is an<br />

output parameter. If the first parameter is not an output parameter, you can run<br />

the routine (stored procedure or SQL function) using the following syntax:<br />

{call client_routine(?, ?, ?, ?)}<br />

Example 3-17 illustrates how to call the get_sid() SQL function.<br />

Example 3-17 SPL function sample, Function.c<br />

#include <br />

#include <br />

#include <br />

#ifdef WIN32<br />

#include <br />

#include <br />

#include <br />

#endif<br />

#include "infxcli.h"<br />

int main (long argc, char* argv[])<br />

{<br />

SQLHDBC hdbc;<br />

SQLHENV henv;<br />

SQLHSTMT hstmt;<br />

SQLRETURN rc = 0;<br />

SQLCHAR connStrIn[1000];<br />

SQLCHAR connStrOut[1000];<br />

SQLSMALLINT connStrOutLen;<br />

SQLCHAR sqlstmt[100];<br />

SQLCHAR errorn[20+1];<br />

SQLCHAR result[100+1];<br />

SQLLEN lresult = 0;<br />

sprintf((char *) connStrIn, "DSN=demo_on");<br />

sprintf((char *) sqlstmt, "{? = call get_sid(?)}");<br />

sprintf((char *) errorn, "informix");<br />

Chapter 3. Working with the ODBC driver 89


SQLAllocHandle (SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);<br />

SQLSetEnvAttr (henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) SQL_OV_ODBC3, 0);<br />

SQLAllocHandle (SQL_HANDLE_DBC, henv, &hdbc);<br />

SQLDriverConnect (hdbc, NULL, connStrIn, SQL_NTS, connStrOut, sizeof(connStrOut),<br />

&connStrOutLen, SQL_DRIVER_NOPROMPT);<br />

fprintf (stdout, "Connected\n");<br />

90 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong><br />

SQLAllocHandle (SQL_HANDLE_STMT, hdbc, &hstmt );<br />

SQLBindParameter(hstmt, 1, SQL_PARAM_OUTPUT, SQL_C_CHAR, SQL_CHAR,sizeof(result),0,<br />

result, sizeof(result), &lresult);<br />

SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(errorn),0,<br />

errorn, 0, NULL);<br />

}<br />

SQLExecDirect (hstmt, sqlstmt, SQL_NTS);<br />

SQLFetch(hstmt);<br />

fprintf (stdout, "Executed SQL Statement:\n%s\nUsing: '%s'\n",sqlstmt,errorn);<br />

fprintf (stdout, "Value returned: %s\n",result);<br />

SQLCloseCursor(hstmt);<br />

SQLDisconnect (hdbc);<br />

SQLFreeHandle (SQL_HANDLE_DBC, hdbc);<br />

SQLFreeHandle (SQL_HANDLE_ENV, henv);<br />

return (rc);<br />

Example 3-18 shows the input parameter passed to the get_sid() procedure<br />

and the return values.<br />

Example 3-18 Output of Function.c<br />

C:\work>cl /DWIN32 /D_CRT_SECURE_NO_DEPRECATE -ID:\infx\csdk350tc7\incl\cli<br />

odbc32.lib /nologo function.c<br />

function.c<br />

C:\work>function<br />

Connected<br />

Executed SQL Statement:<br />

{? = call get_sid(?)}<br />

Using: 'informix'<br />

Value returned: user: informix session: 213<br />

C:\work><br />

Local transactions<br />

The default transaction mode for the <strong>Informix</strong> ODBC driver is auto-commit. The<br />

transaction is committed automatically if the SQL statement runs successfully.


You can switch to manual-commit by setting the SQL_AUTOCOMMIT_OFF<br />

attribute using the SQLSetConnectAttr() function. When an application sets<br />

SQL_AUTOCOMMIT_OFF, the next SQL statement automatically starts a<br />

transaction that remains open until the application calls SQLEndTran().<br />

In manual mode, all the statements executed by the application are committed or<br />

rolled back when the application calls SQLEndTran().<br />

Having auto-commit set might be more convenient when running simple SQL<br />

statements because there are less tasks to care about in the application code.<br />

However, auto-commit gives less control to the developer than using the<br />

manual-commit mode. When using auto-commit, there is no option to roll back a<br />

particular change in the database or to insert a multiple rows as a batch<br />

operation, which might improve the performance of the application.<br />

Example 3-19 illustrates how to run a local transaction in manual mode.<br />

Example 3-19 Transaction.c<br />

#include <br />

#include <br />

#include <br />

#ifdef WIN32<br />

#include <br />

#include <br />

#include <br />

#endif<br />

#include "infxcli.h"<br />

int main (long argc, char* argv[])<br />

{<br />

SQLHDBC hdbc;<br />

SQLHENV henv;<br />

SQLHSTMT hstmt;<br />

SQLRETURN rc = 0;<br />

SQLCHAR connStrIn[1000];<br />

SQLCHAR connStrOut[1000];<br />

SQLSMALLINT connStrOutLen;<br />

SQLCHAR sqlstmt[100];<br />

SQLINTEGER cnum = 101;<br />

SQLSMALLINT datatype, decimaldigits, nullable;<br />

SQLUINTEGER paramsize;<br />

sprintf((char *) connStrIn, "DSN=demo_on");<br />

sprintf((char *) sqlstmt, "INSERT INTO orders(order_num,order_date,customer_num)<br />

VALUES (0,current,?)");<br />

Chapter 3. Working with the ODBC driver 91


SQLAllocHandle (SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);<br />

SQLSetEnvAttr (henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) SQL_OV_ODBC3, 0);<br />

SQLAllocHandle (SQL_HANDLE_DBC, henv, &hdbc);<br />

SQLDriverConnect (hdbc, NULL, connStrIn, SQL_NTS, connStrOut, sizeof(connStrOut),<br />

&connStrOutLen, SQL_DRIVER_NOPROMPT);<br />

fprintf (stdout, "Connected\n");<br />

92 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong><br />

SQLAllocHandle (SQL_HANDLE_STMT, hdbc, &hstmt );<br />

SQLSetConnectAttr (hdbc, SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF, (SQLINTEGER)<br />

NULL);<br />

SQLPrepare (hstmt, sqlstmt, strlen(sqlstmt));<br />

SQLDescribeParam(hstmt, 1, &datatype, &paramsize, &decimaldigits, &nullable);<br />

SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_SHORT, datatype, paramsize,<br />

decimaldigits, &cnum, 0, NULL);<br />

}<br />

while (cnumcl /DWIN32 /D_CRT_SECURE_NO_DEPRECATE -ID:\infx\csdk350tc7\incl\cli<br />

odbc32.lib /nologo transact.c<br />

transact.c<br />

C:\work>del pp*<br />

C:\work>transact.exe<br />

Connected<br />

Executed SQL Statement:<br />

INSERT INTO orders(order_num,order_date,customer_num) VALUES (0,current,?)<br />

Using: '101'<br />

Executed SQL Statement:


INSERT INTO orders(order_num,order_date,customer_num) VALUES (0,current,?)<br />

Using: '102'<br />

Executed SQL Statement:<br />

INSERT INTO orders(order_num,order_date,customer_num) VALUES (0,current,?)<br />

Using: '103'<br />

Executed SQL Statement:<br />

INSERT INTO orders(order_num,order_date,customer_num) VALUES (0,current,?)<br />

Using: '104'<br />

Transaction Rolled back<br />

C:\work><br />

Distributed transactions<br />

On a Windows system, you can run a distributed transaction using the Microsoft<br />

Distributed Transaction Coordinator (MSDTC) service.<br />

Example 3-21 demonstrates how to run a distributed transaction. The example<br />

opens two connections to two different database servers and enlists both<br />

connections into the same distributed transaction.<br />

Example 3-21 Transaction_dtc.cpp<br />

#include <br />

#include <br />

#include <br />

#ifdef WIN32<br />

#include <br />

#include <br />

#include <br />

#include <br />

#include <br />

#endif<br />

#include "infxcli.h"<br />

int main (long argc, char* argv[])<br />

{<br />

SQLHDBC hdbc, hdbc2;<br />

SQLHENV henv;<br />

SQLHSTMT hstmt, hstmt2;<br />

SQLRETURN rc = 0;<br />

SQLCHAR connStrIn[100],connStrIn2[100];<br />

SQLCHAR connStrOut[1000];<br />

SQLSMALLINT connStrOutLen;<br />

SQLCHAR sqlstmt[100];<br />

SQLINTEGER cnum = 101;<br />

SQLSMALLINT datatype, decimaldigits, nullable;<br />

SQLUINTEGER paramsize;<br />

Chapter 3. Working with the ODBC driver 93


94 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong><br />

ITransactionDispenser *pTransactionDispenser = NULL;<br />

ITransaction * pITransaction;<br />

sprintf((char *) connStrIn , "DSN=server_1");<br />

sprintf((char *) connStrIn2, "DSN=server_2");<br />

sprintf((char *) sqlstmt, "INSERT INTO orders(order_num,order_date,customer_num)<br />

VALUES (0,current,101)");<br />

SQLAllocHandle (SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);<br />

SQLSetEnvAttr (henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) SQL_OV_ODBC3, 0);<br />

SQLAllocHandle (SQL_HANDLE_DBC, henv, &hdbc);<br />

SQLAllocHandle (SQL_HANDLE_DBC, henv, &hdbc2);<br />

// Get DTC<br />

DtcGetTransactionManager(NULL, NULL,IID_ITransactionDispenser, 0, 0, NULL, (void**)<br />

&pTransactionDispenser);<br />

SQLDriverConnect (hdbc, NULL, connStrIn, SQL_NTS, connStrOut, sizeof(connStrOut),<br />

&connStrOutLen, SQL_DRIVER_NOPROMPT);<br />

fprintf (stdout, "Connected to %s\n",connStrIn);<br />

SQLDriverConnect (hdbc2, NULL, connStrIn2, SQL_NTS, connStrOut, sizeof(connStrOut),<br />

&connStrOutLen, SQL_DRIVER_NOPROMPT);<br />

fprintf (stdout, "Connected to %s\n",connStrIn2);<br />

//Start the transaction on DTC<br />

pTransactionDispenser->BeginTransaction<br />

(NULL,ISOLATIONLEVEL_READCOMMITTED,0,NULL,&pITransaction);<br />

//Enlist the connections in distributed transaction<br />

SQLSetConnectAttr(hdbc, SQL_ATTR_ENLIST_IN_DTC,<br />

(SQLPOINTER)pITransaction,SQL_IS_INTEGER);<br />

SQLSetConnectAttr(hdbc2, SQL_ATTR_ENLIST_IN_DTC,<br />

(SQLPOINTER)pITransaction,SQL_IS_INTEGER);<br />

SQLAllocHandle (SQL_HANDLE_STMT, hdbc, &hstmt );<br />

SQLExecDirect (hstmt, sqlstmt, SQL_NTS);<br />

fprintf (stdout, "Executed SQL Statement:\n%s\nUsing: '%d'\n",sqlstmt,cnum);<br />

SQLAllocHandle (SQL_HANDLE_STMT, hdbc2, &hstmt2 );<br />

if (SQLExecDirect (hstmt2, sqlstmt, SQL_NTS)!=SQL_SUCCESS)<br />

{<br />

fprintf(stdout, "Rolling back global transaction\n");<br />

pITransaction->Abort(NULL,FALSE,FALSE);<br />

}<br />

else<br />

{<br />

pITransaction->Commit( 0, XACTTC_SYNC_PHASEONE, 0 );<br />

pITransaction->Release();<br />

fprintf(stdout, "Transaction Committed\n");<br />

}


}<br />

SQLFreeHandle(SQL_HANDLE_STMT,hstmt2);<br />

SQLFreeHandle(SQL_HANDLE_STMT,hstmt);<br />

SQLDisconnect (hdbc2);<br />

SQLDisconnect (hdbc);<br />

SQLFreeHandle (SQL_HANDLE_DBC, hdbc2);<br />

SQLFreeHandle (SQL_HANDLE_DBC, hdbc);<br />

SQLFreeHandle (SQL_HANDLE_ENV, henv);<br />

return (rc);<br />

Example 3-22 shows how to compile the sample and the output of the program.<br />

Example 3-22 Output of Transact_dtc.cpp<br />

C:\work>cl /DWIN32 /D_CRT_SECURE_NO_DEPRECATE -I%INFORMIXDIR%\incl\cli<br />

odbc32.lib xoleHlp.lib /nologo transaction_dtc.cpp<br />

transaction_dtc.cpp<br />

C:\work>transaction_dtc<br />

Connected to DSN=server_1<br />

Connected to DSN=server_2<br />

Executed SQL Statement:<br />

INSERT INTO orders(order_num,order_date,customer_num) VALUES (0,current,101)<br />

Using: '101'<br />

Transaction Committed<br />

C:\work><br />

Note: Remember that the DSN must be accessible to the MSDTC service. In<br />

Example 3-21 on page 93, test_1 and test_2 are both created as<br />

System-DSN.<br />

3.3.4 Handling special data types<br />

This section describes how to work with the <strong>Informix</strong> specific data types, such as<br />

smart large objects and complex data types.<br />

Smart large objects<br />

Smart large objects are a type of large objects supported by <strong>Informix</strong>. Smart<br />

large objects are logically stored in a table column but physically stored in a<br />

specific type of dbspaces called smart blob space (sbspace).<br />

The information stored in the table column is structure that contains information<br />

about the large object, such as the pointer to the location in the sbspace that<br />

Chapter 3. Working with the ODBC driver 95


contains the data or special attributes. <strong>Informix</strong> has two types of smart large<br />

objects.<br />

► BLOB: Stores binary data<br />

► CLOB: Stores character data<br />

A client application uses these data structures to perform random I/O operations<br />

on the large data, such as open, read, or write operations. There are two options<br />

for accessing smart large objects from an ODBC application:<br />

► Use the smart-large-object ODBC API.<br />

If the application requires random access to the large data, it must use the<br />

smart large object functions. These functions give the application a greater<br />

control over the smart-large-object data in terms of object properties,<br />

concurrency access, and logging.<br />

► Use smart-large-object automation.<br />

The ODBC driver automatically uses the ODBC API for handling large<br />

objects. The application can access smart large objects as standard ODBC<br />

data types (SQL_LONGVARBINARY and SQL_LONGVARCHAR).<br />

To enable smart-large-object automation use the “Report Standard ODBC<br />

Types Only DSN” option under the DSN Advanced tab or set the<br />

SQL_INFX_ATTR_LO_AUTOMATIC connection attribute.<br />

Data structures for smart large objects<br />

Table 3-10 describes the data structures used by the smart-large-object<br />

functions.<br />

Table 3-10 Smart large object data structures<br />

Data structure Name Description<br />

lofd file descriptor Defines the file descriptor to access<br />

smart-large-object data.<br />

loptr pointer structure Contains the security information and<br />

pointer for a smart large object. This is the<br />

data stored with the table columns.<br />

lospec specification structure Contains the storage characteristics for a<br />

smart large object.<br />

lostat status structure Contains the status information for a smart<br />

large object.<br />

96 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Client functions to access smart large objects<br />

Table 3-11 lists the SQL functions that you can use in your ODBC program to<br />

access the <strong>Informix</strong> smart large objects.<br />

Table 3-11 Smart large object client functions<br />

Function Description<br />

ifx_lo_alter(loptr, lospec) Alters the storage attributes like Logging or<br />

Last-access<br />

ifx_lo_close(lofd) Closes a smart large object<br />

ifx_lo_col_info(colname, lospec) Updates column-level storage characteristics<br />

ifx_lo_create(lospec, flags, loptr, lofd) Creates and opens a new smart large object<br />

ifx_lo_def_create_spec(lospec) Creates a smart-large-object specification<br />

structure<br />

ifx_lo_open(lofd, loptr, flags) Opens a smart large object<br />

ifx_lo_read(lofd, buf) Reads data from a smart large object<br />

ifx_lo_readwithseek(lofd, buf, offset,<br />

whence)<br />

ifx_lo_seek(), ifx_lo_seek(lofd, offset,<br />

whence, seek_pos)<br />

ifx_lo_specget_estbytes(lospec,<br />

estbytes)<br />

Reads starting at a specific location<br />

Sets the file position for the next operation<br />

Returns the estimated size<br />

ifx_lo_specget_extsz(lospec, extsz) Returns the allocation extent size<br />

ifx_lo_specget_flags(lospec, flags) Returns create-time flags<br />

ifx_lo_specget_maxbytes(lospec,<br />

maxbytes)<br />

ifx_lo_specget_sbspace(lospec,<br />

sbspace)<br />

ifx_lo_specset_estbytes(lospec,<br />

estbytes)<br />

Returns the maximum number of bytes<br />

Returns the sbspace name<br />

Sets the estimated number of bytes<br />

ifx_lo_specset_extsz(lospec, extsz) Sets the allocation extent size<br />

ifx_lo_specset_flags(lospec, flags) Sets the create-time flags<br />

ifx_lo_specset_maxbytes(lospec,<br />

maxbytes)<br />

Sets the maximum number of bytes<br />

Chapter 3. Working with the ODBC driver 97


Function Description<br />

ifx_lo_specset_sbspace(lospec,<br />

sbspace)<br />

Calling client functions from ODBC<br />

An application must use the following standard ODBC syntax to call the<br />

smart-large-object functions:<br />

{? = call function_name (?, ?,...)}<br />

The following example calls the ifx_lo_open() function:<br />

{? = call ifx_lo_open(?, ?, ?)}<br />

Creating a smart large object<br />

To create a smart large object, you must create a BLOB descriptor and then<br />

insert the BLOB into the database.<br />

Use the following steps to create a new smart large object:<br />

1. Allocate memory for the specification structure using lospec.<br />

2. Create a lospec using ifx_lo_def_create_spec().<br />

3. Initialize the specification structure using lospec.<br />

4. Allocate memory for the pointer structure using loptr.<br />

5. Create the object using ifx_lo_create().<br />

98 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong><br />

Sets the sbspace name<br />

ifx_lo_stat(lofd, lostat) Initializes a smart-large-object status structure<br />

ifx_lo_stat_atime(lostat, atime) Returns the last-access time<br />

ifx_lo_stat_cspec(lostat, lospec) Returns the specification structure<br />

ifx_lo_stat_ctime(lostat, ctime) Returns the last-time change<br />

ifx_lo_stat_refcnt(lostat, refcount) Returns the number of references<br />

ifx_lo_stat_size(lostat, size) Returns the size<br />

ifx_lo_tell(lofd, seek_pos) Returns the current file position<br />

ifx_lo_truncate(lofd, offset) Truncates a smart large object at a given<br />

position<br />

ifx_lo_write(lofd, buf) Writes data<br />

ifx_lo_writewithseek(lofd, buf, offset,<br />

whence)<br />

Writes data at a specific location


6. Write the data into the object using ifx_lo_write().<br />

7. Perform an SQL operation (INSERT, UPDATE, and so on).<br />

8. Close the smart large object using ifx_lo_close().<br />

Example 3-23 shows how to insert a BLOB into the database.<br />

Example 3-23 Create_lo.c<br />

#include <br />

#include <br />

#include <br />

#ifdef WIN32<br />

#include <br />

#include <br />

#include <br />

#include <br />

#include <br />

#endif<br />

#include "infxcli.h"<br />

int main (long argc, char* argv[])<br />

{<br />

SQLHDBC hdbc;<br />

SQLHENV henv;<br />

SQLHSTMT hstmt;<br />

SQLRETURN rc = 0;<br />

SQLCHAR connStrIn[1000], connStrOut[1000], sqlstmt[100];<br />

SQLSMALLINT connStrOutLen;<br />

SQLINTEGER cnum = 101;<br />

SQLSMALLINT datatype, decimaldigits, nullable;<br />

SQLUINTEGER paramsize;<br />

SQLCHAR colname[25] = "catalog.advert_descr";<br />

SQLINTEGER colname_size = SQL_NTS;<br />

SQLCHAR* file_name = (SQLCHAR *) "create_lo.c";<br />

SQLCHAR* blob_data;<br />

SQLSMALLINT blob_size;<br />

SQLINTEGER blob_wsize, mode = LO_RDWR, cbMode = 0;<br />

int fd=0;<br />

struct stat statbuf;<br />

/* BLOB file descriptor */<br />

SQLINTEGER lofd;<br />

SQLINTEGER lofd_valsize = 0;<br />

/* BLOB pointer structure */<br />

SQLCHAR* loptr_buffer;<br />

SQLSMALLINT loptr_size;<br />

SQLINTEGER loptr_valsize = 0;<br />

/* BLOB specification structure */<br />

SQLCHAR* lospec_buffer;<br />

Chapter 3. Working with the ODBC driver 99


SQLSMALLINT lospec_size;<br />

SQLINTEGER lospec_valsize = 0;<br />

sprintf((char *) connStrIn, "DSN=demo_on");<br />

sprintf((char *) sqlstmt, "INSERT INTO catalog(catalog_num,advert_descr) VALUES<br />

(0,?)");<br />

/* Read the file to insert in the BLOB */<br />

stat(file_name,&statbuf);<br />

blob_size = statbuf.st_size;<br />

blob_data = malloc (blob_size + 1);<br />

fd = _open (file_name, O_RDONLY);<br />

_read (fd, blob_data, blob_size);<br />

_close(fd);<br />

blob_data[blob_size] = '\0';<br />

blob_wsize = blob_size;<br />

SQLAllocHandle (SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);<br />

SQLSetEnvAttr (henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) SQL_OV_ODBC3, 0);<br />

SQLAllocHandle (SQL_HANDLE_DBC, henv, &hdbc);<br />

SQLDriverConnect (hdbc, NULL, connStrIn, SQL_NTS, connStrOut, sizeof(connStrOut),<br />

&connStrOutLen, SQL_DRIVER_NOPROMPT);<br />

SQLAllocHandle (SQL_HANDLE_STMT, hdbc, &hstmt );<br />

/* Obtain the size of the lospec and allocate memory */<br />

SQLGetInfo (hdbc, SQL_INFX_LO_SPEC_LENGTH, &lospec_size, sizeof(lospec_size), NULL);<br />

lospec_buffer = malloc (lospec_size);<br />

/* Call ifx_lo_def_create_spec() to create a lospec */<br />

SQLBindParameter (hstmt, 1, SQL_PARAM_INPUT_OUTPUT, SQL_C_BINARY,<br />

SQL_INFX_UDT_FIXED, (UDWORD)lospec_size, 0, lospec_buffer, lospec_size,<br />

&lospec_valsize);<br />

SQLExecDirect (hstmt, (SQLCHAR *) "{call ifx_lo_def_create_spec(?)}", SQL_NTS);<br />

SQLFreeStmt (hstmt, SQL_RESET_PARAMS);<br />

/* Call ifx_lo_col_info() to initialise the lospec */<br />

SQLBindParameter (hstmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(colname),<br />

0, colname, sizeof(colname), &colname_size);<br />

lospec_valsize = lospec_size;<br />

SQLBindParameter (hstmt, 2, SQL_PARAM_INPUT_OUTPUT, SQL_C_BINARY,<br />

SQL_INFX_UDT_FIXED, (UDWORD)lospec_size, 0, lospec_buffer, lospec_size,<br />

&lospec_valsize);<br />

rc=SQLExecDirect (hstmt, (SQLCHAR *) "{call ifx_lo_col_info(?, ?)}", SQL_NTS);<br />

SQLFreeStmt (hstmt, SQL_RESET_PARAMS);<br />

/* Obtain the size of the smart loptr and allocate memory */<br />

SQLGetInfo (hdbc, SQL_INFX_LO_PTR_LENGTH, &loptr_size, sizeof(loptr_size), NULL);<br />

loptr_buffer = malloc (loptr_size);<br />

/* Call ifx_lo_create() to create the BLOB */<br />

SQLBindParameter (hstmt, 1, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_INFX_UDT_FIXED,<br />

(UDWORD)lospec_size, 0, lospec_buffer, lospec_size, &lospec_valsize);<br />

100 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


c=SQLBindParameter (hstmt, 2, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, (UDWORD)0,<br />

0, &mode, sizeof(mode), &cbMode);<br />

loptr_valsize = loptr_size;<br />

SQLBindParameter (hstmt, 3, SQL_PARAM_INPUT_OUTPUT, SQL_C_BINARY,<br />

SQL_INFX_UDT_FIXED, (UDWORD)loptr_size, 0, loptr_buffer, loptr_size, &loptr_valsize);<br />

SQLBindParameter (hstmt, 4, SQL_PARAM_OUTPUT, SQL_C_SLONG, SQL_INTEGER, (UDWORD)0,<br />

0, &lofd, sizeof(lofd), &lofd_valsize);<br />

SQLExecDirect (hstmt, (SQLCHAR *) "{call ifx_lo_create(?, ?, ?, ?)}", SQL_NTS);<br />

SQLFreeStmt (hstmt, SQL_RESET_PARAMS);<br />

/* Call ifx_lo_write to write the BLOB data */<br />

SQLBindParameter (hstmt, 1, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, (UDWORD)0, 0,<br />

&lofd, sizeof(lofd), &lofd_valsize);<br />

SQLBindParameter (hstmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR,<br />

(UDWORD)blob_size, 0, blob_data, blob_size, &blob_wsize);<br />

SQLExecDirect (hstmt, (SQLCHAR *) "{call ifx_lo_write(?, ?)}", SQL_NTS);<br />

SQLFreeStmt (hstmt, SQL_RESET_PARAMS);<br />

loptr_valsize = loptr_size;<br />

/* Call SQLExecDirect to do the INSERT */<br />

SQLBindParameter (hstmt, 1, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_INFX_UDT_FIXED,<br />

(UDWORD)loptr_size, 0, loptr_buffer, loptr_size, &loptr_valsize);<br />

SQLExecDirect (hstmt, sqlstmt, SQL_NTS);<br />

/* Call ifx_lo_close() to close the BLOB */<br />

rc = SQLBindParameter (hstmt, 1, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,<br />

(UDWORD)0, 0, &lofd, sizeof(lofd), &lofd_valsize);<br />

SQLExecDirect (hstmt, (SQLCHAR *) "{call ifx_lo_close(?)}", SQL_NTS);<br />

}<br />

free (lospec_buffer);<br />

free (loptr_buffer);<br />

free (blob_data);<br />

SQLFreeStmt (hstmt, SQL_CLOSE);<br />

SQLFreeHandle (SQL_HANDLE_STMT, hstmt);<br />

SQLDisconnect (hdbc);<br />

SQLFreeHandle (SQL_HANDLE_DBC, hdbc);<br />

SQLFreeHandle (SQL_HANDLE_ENV, henv);<br />

return (rc);<br />

Accessing a smart large object<br />

Reading a smart large object from the database involves the following steps:<br />

1. Allocate memory for the smart-large-object pointer structure (loptr).<br />

2. Perform the SELECT statement.<br />

3. Bind the smart-large-object pointer structure variable with loptr retrieved<br />

from the database.<br />

Chapter 3. Working with the ODBC driver 101


4. Call ifx_lo_open() to open the smart large object with the loptr fetched<br />

from the database. This step opens the smart large object on the database.<br />

5. Obtain the size of the smart large object status structure (lostat) and allocate<br />

enough memory.<br />

6. Call ifx_lo_stat() to obtain the BLOB status structure, so that we can<br />

retrieve the estimated size of the BLOB in the next step.<br />

7. Call ifx_lo_stat_size() to retrieve the size of the BLOB data and to allocate<br />

enough memory.<br />

8. Call ifx_lo_read() to retrieve the BLOB data.<br />

9. Perform any operation with the BLOB data.<br />

10.Call ifx_lo_close() to close the BLOB.<br />

Example 3-24 shows a simple application that selects a CLOB column from the<br />

database.<br />

Example 3-24 The select_lo.c application<br />

#include <br />

#include <br />

#include <br />

#ifdef WIN32<br />

#include <br />

#include <br />

#include <br />

#include <br />

#include <br />

#endif<br />

#include "infxcli.h"<br />

int main (long argc, char* argv[])<br />

{<br />

SQLHDBChdbc;<br />

SQLHENVhenv;<br />

SQLHSTMThstmt;<br />

/* BLOB file descriptor */<br />

SQLLENlofd;<br />

SQLLENlofd_valsize = 0;<br />

/* BLOB pointer structure */<br />

SQLCHAR*loptr_buffer;<br />

SQLSMALLINTloptr_size;<br />

SQLLENloptr_valsize = 0;<br />

/* BLOB status structure */<br />

SQLCHAR*lostat_buffer;<br />

SQLSMALLINTlostat_size;<br />

SQLLENlostat_valsize = 0;<br />

/* BLOB data */<br />

102 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


SQLCHAR*lo_data;<br />

SQLLENlo_data_valsize = 0;<br />

SQLRETURNrc = 0;<br />

SQLCHAR*dsn = "demo_on";<br />

SQLCHAR*selectStmt = (SQLCHAR *) "SELECT advert_descr FROM catalog where catalog_num<br />

= 10075";<br />

SQLINTEGERmode = LO_RDONLY;<br />

SQLLENlo_size;<br />

SQLLENcbMode = 0, cbLoSize = 0;<br />

SQLAllocHandle (SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);<br />

SQLSetEnvAttr (henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) SQL_OV_ODBC3, 0);<br />

SQLAllocHandle (SQL_HANDLE_DBC, henv, &hdbc);<br />

SQLConnect (hdbc, dsn, SQL_NTS, (SQLCHAR *) "", SQL_NTS, (SQLCHAR *) "", SQL_NTS);<br />

SQLAllocHandle (SQL_HANDLE_STMT, hdbc, &hstmt );<br />

/* Get the size of the loptr */<br />

SQLGetInfo (hdbc, SQL_INFX_LO_PTR_LENGTH, &loptr_size, sizeof(loptr_size), NULL);<br />

loptr_buffer = malloc (loptr_size);<br />

SQLExecDirect (hstmt, selectStmt, SQL_NTS);<br />

/* Bind the loptr with the resulset column */<br />

SQLBindCol (hstmt, 1, SQL_C_BINARY, loptr_buffer, loptr_size, &loptr_valsize);<br />

SQLFetch (hstmt);<br />

SQLCloseCursor (hstmt);<br />

/* Call ifx_lo_open() using the loptr fetched from the database */<br />

SQLBindParameter (hstmt, 1, SQL_PARAM_OUTPUT, SQL_C_LONG, SQL_INTEGER, (UDWORD)0, 0,<br />

&lofd, sizeof(lofd), &lofd_valsize);<br />

SQLBindParameter (hstmt, 2, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_INFX_UDT_FIXED,<br />

(UDWORD)loptr_size, 0, loptr_buffer, loptr_size, &loptr_valsize);<br />

SQLBindParameter (hstmt, 3, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, (UDWORD)0, 0,<br />

&mode, sizeof(mode), &cbMode);<br />

SQLExecDirect (hstmt, (SQLCHAR *) "{? = call ifx_lo_open(?, ?)}", SQL_NTS);<br />

SQLFreeStmt (hstmt, SQL_RESET_PARAMS);<br />

/* Get the size of the lostat and allocate enough memory */<br />

SQLGetInfo (hdbc, SQL_INFX_LO_STAT_LENGTH, &lostat_size, sizeof(lostat_size), NULL);<br />

lostat_buffer = malloc(lostat_size);<br />

/* Call ifx_lo_stat() to get the BLOB lostat */<br />

SQLBindParameter (hstmt, 1, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, (UDWORD)0, 0,<br />

&lofd, sizeof(lofd), &lofd_valsize);<br />

SQLBindParameter (hstmt, 2, SQL_PARAM_INPUT_OUTPUT, SQL_C_BINARY,<br />

SQL_INFX_UDT_FIXED, (UDWORD)lostat_size, 0, lostat_buffer, lostat_size,<br />

&lostat_valsize);<br />

SQLExecDirect (hstmt, (SQLCHAR *) "{call ifx_lo_stat(?, ?)}", SQL_NTS);<br />

SQLFreeStmt (hstmt, SQL_RESET_PARAMS);<br />

/* Call ifx_lo_stat_size to get the size of the BLOB data and allocate enough memory*/<br />

Chapter 3. Working with the ODBC driver 103


SQLBindParameter (hstmt, 1, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_INFX_UDT_FIXED,<br />

(UDWORD)lostat_size, 0, lostat_buffer, lostat_size, &lostat_valsize);<br />

SQLBindParameter (hstmt, 2, SQL_PARAM_OUTPUT, SQL_C_LONG, SQL_BIGINT, (UDWORD)0, 0,<br />

&lo_size, sizeof(lo_size), &cbLoSize);<br />

SQLExecDirect (hstmt, (SQLCHAR *) "{call ifx_lo_stat_size(?, ?)}", SQL_NTS);<br />

SQLFreeStmt (hstmt, SQL_RESET_PARAMS);<br />

lo_data = malloc (lo_size + 1);<br />

/* Call ifx_lo_read() to get the BLOB data */<br />

SQLBindParameter (hstmt, 1, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, (UDWORD)0, 0,<br />

&lofd, sizeof(lofd), &lofd_valsize);<br />

SQLBindParameter (hstmt, 2, SQL_PARAM_OUTPUT, SQL_C_CHAR, SQL_CHAR, lo_size, 0,<br />

lo_data, lo_size, &lo_data_valsize);<br />

SQLExecDirect (hstmt, (SQLCHAR *) "{call ifx_lo_read(?, ?)}", SQL_NTS);<br />

lo_data[lo_size] = '\0';<br />

SQLFreeStmt (hstmt, SQL_RESET_PARAMS);<br />

/* Call ifx_lo_close() to close the BLOB */<br />

SQLBindParameter (hstmt, 1, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, (UDWORD)0, 0,<br />

&lofd, sizeof(lofd), &lofd_valsize);<br />

SQLExecDirect (hstmt, (SQLCHAR *) "{call ifx_lo_close(?)}",SQL_NTS);<br />

}<br />

fprintf(stdout,"%s",lo_data);<br />

free (loptr_buffer);<br />

free (lostat_buffer);<br />

free (lo_data);<br />

SQLFreeStmt (hstmt, SQL_CLOSE);<br />

SQLFreeHandle (SQL_HANDLE_STMT, hstmt);<br />

SQLDisconnect (hdbc);<br />

SQLFreeHandle (SQL_HANDLE_DBC, hdbc);<br />

SQLFreeHandle (SQL_HANDLE_ENV, henv);<br />

return (rc);<br />

Smart large object automation<br />

Developing an application to handle smart large objects using the smart large<br />

object automation method does not require any special attention. Use<br />

SQL_LONGBINARY and SQL_LONGVARCHAR as data type.<br />

Example 3-25 Illustrates how to insert a smart large object with the<br />

SQL_INFX_ATTR_LO_AUTOMATIC enabled.<br />

Example 3-25 Lo_auto.c<br />

#include <br />

#include <br />

#include <br />

104 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


#ifdef WIN32<br />

#include <br />

#include <br />

#include <br />

#include <br />

#include <br />

#endif<br />

#include "infxcli.h"<br />

int main (long argc, char* argv[])<br />

{<br />

SQLHDBC hdbc;<br />

SQLHENV henv;<br />

SQLHSTMT hstmt;<br />

SQLCHAR* dsn="demo_on";<br />

SQLCHAR sqlstmt[128];<br />

SQLCHAR str[128];<br />

SQLLEN str_len = SQL_NTS;<br />

SQLSMALLINT BufferLength = 128;<br />

SQLINTEGER int_val;<br />

SQLRETURN rc = 0;<br />

SQLAllocHandle (SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);<br />

SQLSetEnvAttr (henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) SQL_OV_ODBC3, 0);<br />

SQLAllocHandle (SQL_HANDLE_DBC, henv, &hdbc);<br />

SQLConnect (hdbc, dsn, SQL_NTS, (SQLCHAR *) "", SQL_NTS, (SQLCHAR *) "", SQL_NTS);<br />

SQLAllocHandle (SQL_HANDLE_STMT, hdbc, &hstmt );<br />

/* Set SQL_INFX_ATTR_ODBC_TYPES_ONLY connection attribute to FALSE*/<br />

SQLSetConnectAttr(hdbc, SQL_INFX_ATTR_ODBC_TYPES_ONLY, (SQLPOINTER) SQL_FALSE,<br />

SQL_IS_UINTEGER);<br />

/* Set SQL_INFX_ATTR_LO_AUTOMATIC connection attribute to TRUE*/<br />

SQLSetConnectAttr(hdbc, SQL_INFX_ATTR_LO_AUTOMATIC, (SQLPOINTER) SQL_TRUE,<br />

SQL_IS_UINTEGER);<br />

SQLAllocHandle (SQL_HANDLE_STMT, hdbc, &hstmt );<br />

/* Preare the SQL statement */<br />

sprintf(sqlstmt, "INSERT INTO catalog(catalog_num,advert_descr) VALUES (0,?)");<br />

SQLPrepare (hstmt, sqlstmt, SQL_NTS);<br />

/* Bind the input parameter and Execute the SQL */<br />

SQLBindParameter (hstmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_LONGVARCHAR,<br />

BufferLength, 0, &str, 0, &str_len);<br />

SQLExecute (hstmt);<br />

SQLFreeStmt (hstmt, SQL_CLOSE);<br />

SQLFreeHandle (SQL_HANDLE_STMT, hstmt);<br />

SQLDisconnect (hdbc);<br />

SQLFreeHandle (SQL_HANDLE_DBC, hdbc);<br />

Chapter 3. Working with the ODBC driver 105


}<br />

SQLFreeHandle (SQL_HANDLE_ENV, henv);<br />

return (rc);<br />

Complex data types<br />

Rows and Collections are composite values that consist of one or more<br />

elements. You can use the execute SQL statements to access an entire row or<br />

collection. However, you cannot access individual elements within a row or<br />

collection.<br />

To access composite values from the ODBC driver you must use the Client<br />

functions for Rows and Collections.<br />

Client functions for Rows and Collections<br />

The ODBC functions for handling Rows and Collections start with the prefix<br />

ifx_rc_. Table 3-12 lists the available functions.<br />

Table 3-12 Row and Collection Client functions<br />

Function Description<br />

ifx_rc_count() Returns the number of elements or fields that are in a row or<br />

collection<br />

ifx_rc_create() Creates a buffer for a row or collection<br />

ifx_rc_delete() Deletes an element from a collection<br />

ifx_rc_describe() Returns information about the complex data type or and individual<br />

element<br />

ifx_rc_fetch() Returns the value of an element that is in a row or collection<br />

ifx_rc_free() Frees a row or collection handle<br />

ifx_rc_insert() Inserts a new element into a collection<br />

ifx_rc_isnull() Evaluate if a complex type is NULL or not<br />

ifx_rc_setnull() Set a complex type to NULL<br />

ifx_rc_typespec() Returns the type specification for a row or collection<br />

ifx_rc_update() Updates the value for an element that is in a row or collection<br />

106 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Creating a complex data type<br />

Example 3-26 shows how to perform an INSERT operation using the <strong>Informix</strong><br />

ODBC functions ifx_rc_xxx. We use a simple table customer_rc defined as<br />

follows:<br />

CREATE ROW TYPE name_t (<br />

fname VARCHAR(15),<br />

lname VARCHAR(15)<br />

);<br />

CREATE TABLE customer_rc (<br />

customer_num SERIAL,<br />

customer_name name_t,<br />

contact_dates LIST(DATETIME YEAR TO DAY NOT NULL)<br />

);<br />

Example 3-26 Create_rc.c<br />

#include <br />

#include <br />

#include <br />

#ifdef WIN32<br />

#include <br />

#include <br />

#include <br />

#include <br />

#include <br />

#endif<br />

#include "infxcli.h"<br />

int main (long argc, char* argv[])<br />

{<br />

SQLHDBChdbc;<br />

SQLHENVhenv;<br />

SQLHSTMThstmt;<br />

/* Row variables */<br />

HINFX_RChrow;<br />

HINFX_RChlist;<br />

SQLCHAR*dsn = "demo_on";<br />

SQLRETURNrc = 0;<br />

SQLINTEGERi, in;<br />

SQLLENdata_size = SQL_NTS;<br />

SQLSMALLINTposition = SQL_INFX_RC_ABSOLUTE;<br />

SQLSMALLINTjump;<br />

SQLCHARrow_data[2][15] = {"Ludwig", "Pauli"};<br />

SQLLENrow_data_size = SQL_NTS;<br />

SQLCHARlist_data[2][25] = {"2008-08-16","2008-08-16"};<br />

SQLLENlist_data_size = SQL_NTS;<br />

Chapter 3. Working with the ODBC driver 107


SQLCHAR*insertStmt = (SQLCHAR *) "INSERT INTO customer_rc VALUES (0, ?, ?)";<br />

SQLLENcbHrow = 0, cbHlist = 0, cbPosition = 0, cbJump = 0;<br />

/* Connection */<br />

SQLAllocHandle (SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);<br />

SQLSetEnvAttr (henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) SQL_OV_ODBC3, 0);<br />

SQLAllocHandle (SQL_HANDLE_DBC, henv, &hdbc);<br />

SQLConnect (hdbc, dsn, SQL_NTS, (SQLCHAR *) "", SQL_NTS, (SQLCHAR *) "", SQL_NTS);<br />

SQLAllocHandle (SQL_HANDLE_STMT, hdbc, &hstmt );<br />

/* Call ifx_rc_create() to allocate a row handle */<br />

SQLBindParameter (hstmt, 1, SQL_PARAM_OUTPUT, SQL_C_BINARY, SQL_INFX_RC_ROW,<br />

sizeof(HINFX_RC), 0, &hrow, sizeof(HINFX_RC), &cbHrow);<br />

SQLBindParameter (hstmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, 0, 0, (SQLCHAR *)<br />

"ROW(fname VARCHAR(15), lname VARCHAR(15))", 0, &data_size);<br />

SQLExecDirect (hstmt, (SQLCHAR *) "{? = call ifx_rc_create(?)}", SQL_NTS);<br />

/* Call ifx_rc_create() to allocate a list handle */<br />

SQLBindParameter (hstmt, 1, SQL_PARAM_OUTPUT, SQL_C_BINARY, SQL_INFX_RC_LIST,<br />

sizeof(HINFX_RC), 0, &hlist, sizeof(HINFX_RC), &cbHlist);<br />

SQLBindParameter (hstmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, 0, 0, (SQLCHAR *)<br />

"LIST (DATETIME YEAR TO DAY NOT NULL)", 0, &data_size);<br />

SQLExecDirect (hstmt, (SQLCHAR *) "{? = call ifx_rc_create(?)}", SQL_NTS);<br />

SQLFreeStmt (hstmt, SQL_RESET_PARAMS);<br />

/* call ifx_rc_update() to insert elements into the row */<br />

for (i=0; i


SQLFreeStmt (hstmt, SQL_RESET_PARAMS);<br />

SQLBindParameter (hstmt, 1, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_INFX_RC_COLLECTION,<br />

sizeof(HINFX_RC), 0, hrow, sizeof(HINFX_RC), &cbHrow);<br />

SQLBindParameter (hstmt, 2, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_INFX_RC_COLLECTION,<br />

sizeof(HINFX_RC), 0, hlist, sizeof(HINFX_RC), &cbHlist);<br />

SQLExecDirect (hstmt, insertStmt, SQL_NTS);<br />

SQLBindParameter (hstmt, 1, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_INFX_RC_ROW,<br />

sizeof(HINFX_RC), 0, hrow, sizeof(HINFX_RC), &cbHrow);<br />

SQLExecDirect(hstmt, (SQLCHAR *)"{call ifx_rc_free(?)}", SQL_NTS);<br />

/* Free the list handle */<br />

SQLBindParameter (hstmt, 1, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_INFX_RC_LIST,<br />

sizeof(HINFX_RC), 0, hlist, sizeof(HINFX_RC), &cbHlist);<br />

SQLExecDirect(hstmt, (SQLCHAR *)"{call ifx_rc_free(?)}", SQL_NTS);<br />

}<br />

SQLFreeStmt (hstmt, SQL_CLOSE);<br />

SQLFreeHandle (SQL_HANDLE_STMT, hstmt);<br />

SQLDisconnect (hdbc);<br />

SQLFreeHandle (SQL_HANDLE_DBC, hdbc);<br />

SQLFreeHandle (SQL_HANDLE_ENV, henv);<br />

return (rc);<br />

Example 3-27 shows the information inserted into the customer_rc table after the<br />

execution of the example.<br />

Example 3-27 The customer_rc table<br />

> select * from customer_rc<br />

> ;<br />

customer_num 1<br />

customer_name ROW('Ludwig','Pauli')<br />

contact_dates LIST{'2008-08-16','2008-08-16'}<br />

1 row(s) retrieved.<br />

><br />

Chapter 3. Working with the ODBC driver 109


Accessing a complex data type<br />

Example 3-28 demonstrates how to select a Row type with the ODBC driver.<br />

Example 3-28 The select_row.c application<br />

#include <br />

#include <br />

#include <br />

#ifdef WIN32<br />

#include <br />

#include <br />

#include <br />

#include <br />

#include <br />

#endif<br />

#include "infxcli.h"<br />

int main (long argc, char* argv[])<br />

{<br />

SQLHDBC hdbc;<br />

SQLHENV henv;<br />

SQLHSTMT hstmt, hstmt_row;<br />

HINFX_RC hrow;<br />

SQLCHAR *dsn="demo_on";<br />

SQLRETURN rc = 0;<br />

SQLINTEGER i;<br />

SQLSMALLINT position = SQL_INFX_RC_ABSOLUTE, jump = 0;<br />

SQLLEN cbHrow = 0, cbPosition = 0, cbJump = 0, cbRCData = 0;<br />

SQLLEN data_size = SQL_NTS, cbrow = 0;<br />

SQLCHAR* sqlstmt = (SQLCHAR *) "SELECT customer_name FROM customer_rc WHERE<br />

customer_num = 1";<br />

SQLCHAR row_data[200];<br />

/* Connection */<br />

SQLAllocHandle (SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);<br />

SQLSetEnvAttr (henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) SQL_OV_ODBC3, 0);<br />

SQLAllocHandle (SQL_HANDLE_DBC, henv, &hdbc);<br />

SQLConnect (hdbc, dsn, SQL_NTS, (SQLCHAR *) "", SQL_NTS, (SQLCHAR *) "", SQL_NTS);<br />

SQLAllocHandle (SQL_HANDLE_STMT, hdbc, &hstmt);<br />

SQLAllocHandle (SQL_HANDLE_STMT, hdbc, &hstmt_row);<br />

/* Call ifx_rc_create() to allocate a row handle */<br />

SQLBindParameter (hstmt, 1, SQL_PARAM_OUTPUT, SQL_C_BINARY, SQL_INFX_RC_ROW,<br />

sizeof(HINFX_RC), 0, &hrow, sizeof(HINFX_RC), &cbHrow);<br />

SQLBindParameter (hstmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, 0, 0, (SQLCHAR *)<br />

"row", 0, &data_size);<br />

SQLExecDirect (hstmt, (SQLCHAR *) "{? = call ifx_rc_create(?)}", SQL_NTS);<br />

SQLFreeStmt (hstmt, SQL_RESET_PARAMS);<br />

110 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


* Bind the row handle with the resulset column */<br />

SQLExecDirect (hstmt, sqlstmt, SQL_NTS);<br />

SQLBindCol (hstmt, 1, SQL_C_BINARY, (SQLPOINTER) hrow, sizeof(HINFX_RC), &cbHrow);<br />

SQLFetch (hstmt);<br />

/* Get the row data */<br />

fprintf(stdout, "Row data:\n");<br />

for (i=0; icl /DWIN32 /D_CRT_SECURE_NO_DEPRECATE -ID:\infx\csdk350tc7\incl\cli<br />

odbc32.lib /nologo select_row.c<br />

select_row.c<br />

C:\work>select_row<br />

Row data:<br />

Chapter 3. Working with the ODBC driver 111


C:\work><br />

3.3.5 Error handling<br />

Ludwig<br />

Pauli<br />

In this section, we show how to obtain additional information when an ODBC<br />

function fails.<br />

Error handling sample<br />

When an ODBC function fails, it stores information in the diagnostic record. This<br />

record contains information such as error messages, warning, and status<br />

information about the success or failure of the ODBC call.<br />

An ODBC application can retrieve the diagnostic record or individual fields using<br />

the SQLGetDiagRec() and SQLGetDiagField() ODBC functions.<br />

Example 3-30 shows a typical usage of SQLGetDiagRec().<br />

Example 3-30 A sample connect_error.c application<br />

#include <br />

#include <br />

#include <br />

#ifdef WIN32<br />

#include <br />

#include <br />

#include <br />

#endif<br />

#include "infxcli.h"<br />

int main (long argc, char* argv[])<br />

{<br />

SQLHDBC hdbc;<br />

SQLHENV henv;<br />

SQLRETURN rc = 0;<br />

SQLCHAR connStrIn[1000];<br />

SQLCHAR connStrOut[1000];<br />

SQLSMALLINT connStrOutLen;<br />

UCHAR SqlState[200] = "", ErrorMsg[200] = "";<br />

SQLINTEGER IsamError = 0;<br />

SDWORD NativeError = 0L;<br />

SWORD ErrorMsgp = 0;<br />

SQLSMALLINT recnum = 1;<br />

if (argc != 2)<br />

112 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


{<br />

fprintf (stdout, "Please specify the name of a DSN!\n");<br />

return(1);<br />

}<br />

else<br />

{<br />

if (strstr (argv[1],"DRIVER")==NULL)<br />

sprintf((char *) connStrIn, "DSN=%s;", (char *)argv[1]);<br />

else<br />

sprintf((char *) connStrIn, "%s;", (char *)argv[1]);<br />

}<br />

rc = SQLAllocHandle (SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);<br />

rc = SQLSetEnvAttr (henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) SQL_OV_ODBC3, 0);<br />

rc = SQLAllocHandle (SQL_HANDLE_DBC, henv, &hdbc);<br />

rc = SQLDriverConnect (hdbc, NULL, connStrIn, SQL_NTS, connStrOut, 1000,<br />

&connStrOutLen, SQL_DRIVER_NOPROMPT);<br />

if (rc != SQL_SUCCESS)<br />

{<br />

SQLGetDiagRec(SQL_HANDLE_DBC, hdbc, recnum, SqlState, &NativeError, ErrorMsg,<br />

199, &ErrorMsgp);<br />

fprintf(stdout, "SqlState = %s\n Native Error = %d\n Error Message = %s\n",<br />

SqlState, NativeError, ErrorMsg);<br />

fprintf (stdout, "Connection failed!\n");<br />

return (1);<br />

}<br />

}<br />

fprintf (stdout, "Connection Successful\n");<br />

SQLDisconnect (hdbc);<br />

SQLFreeHandle (SQL_HANDLE_DBC, hdbc);<br />

SQLFreeHandle (SQL_HANDLE_ENV, henv);<br />

return (rc);<br />

Example 3-31 shows the output of Example 3-30 on page 112. In addition to the<br />

ODBC SQLSTATE error, it returns the <strong>Informix</strong> native error and the description<br />

for the error.<br />

Example 3-31 Output of the connect_error.c application<br />

C:\work>cl /DWIN32 /D_CRT_SECURE_NO_DEPRECATE -I%INFORMIXDIR%\incl\cli<br />

odbc32.lib /nologo connect_error.c<br />

connect_error.c<br />

C:\work>connect_error wrongDNS<br />

SqlState = IM002<br />

Native Error = 0<br />

Error Message = [Microsoft][ODBC Driver Manager] Data source name not found<br />

and no default driver specified<br />

Connection failed!<br />

Chapter 3. Working with the ODBC driver 113


C:\work>connect_error demo_on;UID=wronguser<br />

SqlState = 28000<br />

Native Error = -951<br />

Error Message = [<strong>Informix</strong>][<strong>Informix</strong> ODBC Driver][<strong>Informix</strong>]Incorrect password<br />

or user wronguser@localhost is not known on the database server.<br />

Connection failed!<br />

C:\work><br />

Because this function is called quite often, it make sense to have a function to<br />

display the error message. Example 3-32 illustrates a typical error handling<br />

function.<br />

Example 3-32 A sample simple_select_werr.c application<br />

#include <br />

#include <br />

#include <br />

#ifdef WIN32<br />

#include <br />

#include <br />

#include <br />

#endif<br />

#include "infxcli.h"<br />

void CheckDiag (SQLSMALLINT handle_type, SQLHANDLE handle, char *text)<br />

{<br />

RETCODErc = SQL_SUCCESS;<br />

UCHARSqlState[200] = "", ErrorMsg[200] = "";<br />

SQLINTEGERIsamError = 0;<br />

SDWORDNativeError = 0L;<br />

SWORDErrorMsgp = 0;<br />

SQLSMALLINTrecnum = 1;<br />

fprintf (stdout,"Error in %s \n",text);<br />

while (rc != SQL_NO_DATA_FOUND) {<br />

rc = SQLGetDiagRec(handle_type, handle, recnum, SqlState, &NativeError,<br />

ErrorMsg, 199, &ErrorMsgp);<br />

if (rc != SQL_NO_DATA_FOUND) {<br />

SQLGetDiagField(handle_type, handle, recnum, SQL_DIAG_ISAM_ERROR,<br />

&IsamError, SQL_IS_INTEGER, NULL);<br />

fprintf (stdout," SqlState = %s\n Native Error = %d\n Error Message = %s\n<br />

ISAM Error = %d\n", SqlState, NativeError, ErrorMsg, IsamError);<br />

}<br />

recnum++;<br />

}<br />

}<br />

int main (long argc, char* argv[])<br />

{<br />

SQLHDBC hdbc;<br />

114 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


SQLHENV henv;<br />

SQLHSTMT hstmt;<br />

SQLRETURN rc = 0;<br />

SQLCHAR connStrIn[1000];<br />

SQLCHAR connStrOut[1000];<br />

SQLSMALLINT connStrOutLen;<br />

int sqllen;<br />

SQLCHAR *sqlstmt;<br />

if (argc != 3)<br />

{<br />

fprintf (stdout, "Please specify the name of a DSN and the SQL Statement to<br />

run!\n");<br />

return(1);<br />

}<br />

else<br />

{<br />

if (strstr (argv[1],"DRIVER")==NULL)<br />

sprintf((char *) connStrIn, "DSN=%s;", (char *)argv[1]);<br />

else<br />

sprintf((char *) connStrIn, "%s;", (char *)argv[1]);<br />

}<br />

sqllen = strlen((char *)argv[2]);<br />

sqlstmt = (SQLCHAR *) malloc (sqllen + sizeof(char));<br />

strcpy((char *)sqlstmt, (char *)argv[2]);<br />

SQLAllocHandle (SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);<br />

SQLSetEnvAttr (henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) SQL_OV_ODBC3, 0);<br />

SQLAllocHandle (SQL_HANDLE_DBC, henv, &hdbc);<br />

SQLDriverConnect (hdbc, NULL, connStrIn, SQL_NTS, connStrOut, 1000, &connStrOutLen,<br />

SQL_DRIVER_NOPROMPT);<br />

fprintf (stdout, "Connected\n");<br />

SQLAllocHandle (SQL_HANDLE_STMT, hdbc, &hstmt );<br />

}<br />

rc = SQLExecDirect (hstmt, sqlstmt, SQL_NTS);<br />

if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO)<br />

{<br />

CheckDiag(SQL_HANDLE_STMT, hstmt,"SQLExecDirect()");<br />

fprintf (stdout, "SQLExecDirectW() failed!\n");<br />

return (1);<br />

}<br />

fprintf (stdout, "Executed SQL Statement:\n%s\n",sqlstmt);<br />

SQLDisconnect (hdbc);<br />

SQLFreeHandle (SQL_HANDLE_DBC, hdbc);<br />

SQLFreeHandle (SQL_HANDLE_ENV, henv);<br />

return (rc);<br />

Chapter 3. Working with the ODBC driver 115


We create a function called CheckDiag() to retrieve the diagnostic information:<br />

void CheckDiag (SQLSMALLINT handle_type, SQLHANDLE handle, char *text)<br />

Example 3-33 shows the output of the previous sample.<br />

Example 3-33 Output of the simple_select_werr.c application<br />

C:\work>simple_sql_werror demo_on "wrong sql"<br />

Connected<br />

Error in SQLExecDirect()<br />

SqlState = 42000<br />

Native Error = -201<br />

Error Message = [<strong>Informix</strong>][<strong>Informix</strong> ODBC Driver][<strong>Informix</strong>]A syntax error has<br />

occurred.<br />

ISAM Error = 0<br />

SQLExecDirectW() failed!<br />

C:\work>simple_sql_werror demo_on "DELETE from wrongtable"<br />

Connected<br />

Error in SQLExecDirect()<br />

SqlState = 42S02<br />

Native Error = -206<br />

Error Message = [<strong>Informix</strong>][<strong>Informix</strong> ODBC Driver][<strong>Informix</strong>]The specified table<br />

(wrongtable) is not in the database.<br />

ISAM Error = -111<br />

SQLExecDirectW() failed!<br />

C:\work><br />

Note: If an error is generated by the database server, the error message<br />

contains the string [<strong>Informix</strong>] before the description of the error. For<br />

example:<br />

ODBC SQLSTATE errors with <strong>Informix</strong> ODBC Driver<br />

The error that is returned by the ODBC function is based on the X/Open standard<br />

SQLSTATE errors. For the SQLSTATE codes, refer to the <strong>Informix</strong> ODBC Driver<br />

Guide at:<br />

http://publib.boulder.ibm.com/infocenter/idshelp/v115/topic/com.ibm.odbc.doc/si<br />

i091033222.htm#sii091033222<br />

116 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong><br />

Error in SQLExecDirect()<br />

SqlState = 42S02<br />

Native Error = -206<br />

Error Message = [<strong>Informix</strong>][<strong>Informix</strong> ODBC Driver][<strong>Informix</strong>]The specified<br />

table (test) is not in the database.<br />

ISAM Error = -111<br />

SQLExecDirectW() failed!


3.3.6 Troubleshooting<br />

In this section, we discuss typical problems when using the <strong>Informix</strong> ODBC<br />

drivers and available traces.<br />

Environment<br />

Make sure the setup of <strong>Informix</strong> Client is correct. If your application fails to load<br />

the ODBC driver, verify that the <strong>Informix</strong> Client or Data Server Client libraries are<br />

accessible to the application.<br />

► The environment variable PATH should contain the bin directory of your Client<br />

package.<br />

► The shared library PATH variable on a UNIX system should contain the<br />

directory where the shared libraries are located.<br />

► Make sure that the INFORMIXDIR variable is set correctly (as an environment<br />

variable or stored in the registry using the setnet32.exe utility).<br />

► Any 32-bit applications require 32-bit drivers to work. Make sure that the<br />

drivers that you have installed are of the same type as your application.<br />

If your application fails to connect, make sure the connection details are valid.<br />

Client SDK on Windows contains a simple connection tool called iLogin, which<br />

you can use to check whether you have connection with the database server. If<br />

iLogin fails to connect, all the other drivers will fail also.<br />

► Check that the values stored in the registry with the setnet32.exe utility are<br />

valid.<br />

► If you use 32-bit and 64-bit drivers on the same system, remember that on a<br />

Windows system, there are two registry hives to store the connectivity<br />

information. Make sure that both are correct.<br />

Tracing<br />

When developing an application using the ODBC driver, most problems are<br />

caused by passing incorrect parameters to the ODBC functions.<br />

ODBC Trace<br />

You can generate a trace file of all the calls to the ODBC driver using the ODBC<br />

Trace facility. On a Windows system, you can enable ODBC Trace using the<br />

ODBC Data Source Administrator.<br />

Chapter 3. Working with the ODBC driver 117


Figure 3-14 shows the Tracing tab.<br />

Figure 3-14 Enabling trace<br />

Note: Remember to select Machine-Wide tracing for all user identities if<br />

your application runs as a service or with a different user.<br />

Example 3-34 shows some of the entries in an ODBC trace file.<br />

Example 3-34 ODBC trace<br />

...<br />

rccreate 99c-db8 EXIT SQLBindParameter with return code 0<br />

(SQL_SUCCESS)<br />

HSTMT 01D51DC0<br />

UWORD 2<br />

SWORD 1 <br />

SWORD 1 <br />

SWORD 1 <br />

SQLULEN 25<br />

SWORD 0<br />

PTR 0x002CFEC8<br />

SQLLEN 0<br />

SQLLEN * 0x002CFF50 (-3)<br />

rccreate 99c-db8 ENTER SQLBindParameter<br />

HSTMT 01D51DC0<br />

UWORD 3<br />

SWORD 1 <br />

SWORD 5 <br />

118 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


...<br />

SWORD 5 <br />

SQLULEN 0<br />

SWORD 0<br />

PTR 0x002CFF68<br />

SQLLEN 0<br />

SQLLEN * 0x002CFF54<br />

On a UNIX system, ODBC trace is active if the Trace parameter in the [ODBC]<br />

section of the odbc.ini configuration file is set to 1.<br />

Example 3-35 shows the Trace settings for the odbc.ini file.<br />

Example 3-35 Trace in the odbc.ini file<br />

;<br />

; Trace file Section<br />

;<br />

Trace=1<br />

TraceFile=/tmp/odbctrace.out<br />

InstallDir=/opt/<strong>IBM</strong>/informix<br />

TRACEDLL=idmrs09a.so<br />

SQLIDEBUG<br />

All the <strong>Informix</strong> clients use the SQLI protocol to communicate with the database<br />

server.<br />

In addition to the ODBC trace, you can generate an SQLIDEBUG trace that<br />

contains all the message between the client application and the database server.<br />

You can enable SQLIDEBUG trace at the <strong>Informix</strong> Client side by defining the<br />

environment variable as follows:<br />

SQLIDEBUG=2:path_to_trace_files<br />

Alternatively, you can enable trace at the server side by running the following<br />

command:<br />

onmode -p 1 sqli_dbg<br />

Note: On a Windows system, when using the server side tracing, the<br />

SQLIDEBUG files are created in the C:\temp\sqli directory. This directory<br />

must exist before you can enable the trace.<br />

On a UNIX system, the trace files are created in the /tmp/sqli directory.<br />

Chapter 3. Working with the ODBC driver 119


Example 3-36 demonstrates how to set SQLIDEBUG trace on the client.<br />

Example 3-36 SQLIDEBUG sample<br />

C:\work>set SQLIDEBUG=2:sqli_trace<br />

C:\work>simple_sql_werror demo_on "wrong_sql"<br />

Connected<br />

Error in SQLExecDirect()<br />

SqlState = 42000<br />

Native Error = -201<br />

Error Message = [<strong>Informix</strong>][<strong>Informix</strong> ODBC Driver][<strong>Informix</strong>]A syntax error has<br />

occurred.<br />

ISAM Error = 0<br />

SQLExecDirectW() failed!<br />

C:\work>dir sqli_trace_2940_1016_1f428b8<br />

Volume in drive C is W2003<br />

Volume Serial Number is 50DA-70D7<br />

Directory of C:\work<br />

22/06/2010 18:39 348 sqli_trace_2940_1016_1f428b8<br />

1 File(s) 348 bytes<br />

0 Dir(s) 76,628,099,072 bytes free<br />

C:\work><br />

The SQLIDEBUG trace files contains the SQLI packages between the server and<br />

the client. To obtain an readable output, you must run the sqliprt tool.<br />

Example 3-37 demonstrates how to run sqliprt.<br />

Example 3-37 The sqliprt output<br />

C:\work>sqliprt -o trace.txt sqli_trace_2940_1016_1f428b8<br />

C:\work>type trace.txt<br />

SQLIDBG Version 1<br />

C->S (4) Time: 2010-06-22 18:39:05.43700<br />

SQ_INTERNALVER<br />

Internal Version Number: 316<br />

C->S (14) Time: 2010-06-22 18:39:05.43700<br />

SQ_PROTOCOLS<br />

SQ_EOT<br />

S->C (14) Time: 2010-06-22 18:39:05.43700<br />

SQ_PROTOCOLS<br />

120 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


SQ_EOT<br />

C->S (90) Time: 2010-06-22 18:39:05.43700<br />

SQ_INFO<br />

INFO_ENV<br />

Name Length = 12<br />

Value Length = 34<br />

"DBTEMP"="C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp"<br />

"SUBQCACHESZ"="10"<br />

"OPTOFC"="0"<br />

INFO_DONE<br />

SQ_EOT<br />

S->C (2) Time: 2010-06-22 18:39:05.43700<br />

SQ_EOT<br />

C->S (4) Time: 2010-06-22 18:39:05.43700<br />

SQ_BEGIN<br />

SQ_EOT<br />

S->C (10) Time: 2010-06-22 18:39:05.43700<br />

SQ_XACTSTAT<br />

SQ_EOT<br />

C->S (4) Time: 2010-06-22 18:39:05.43700<br />

SQ_CMMTWORK<br />

SQ_EOT<br />

S->C (10) Time: 2010-06-22 18:39:05.43700<br />

SQ_XACTSTAT<br />

SQ_EOT<br />

C->S (22) Time: 2010-06-22 18:39:05.43700<br />

SQ_PREPARE<br />

# values: 0<br />

CMD.....: "wrong_sql" [9]<br />

SQ_NDESCRIBE<br />

SQ_WANTDONE<br />

SQ_EOT<br />

S->C (12) Time: 2010-06-22 18:39:05.43700<br />

SQ_ERR<br />

SQL error..........: -201<br />

ISAM/RSAM error....: 0<br />

Offset in statement: 1<br />

Error message......: "" [0]<br />

SQ_EOT<br />

C:\work><br />

Note: On a UNIX system, the equivalent of the sqliprt tool is sqliprint.<br />

Chapter 3. Working with the ODBC driver 121


DRDADEBUG<br />

All <strong>IBM</strong> Data Server drivers use the DRDA protocol to communicate with the<br />

database server.<br />

Similar to SQLIDEBUG, you can enable DRDADEBUG trace at the server side<br />

by running the following onmode command:<br />

onmode -p 1 drda_dbg<br />

The DRDA trace files are created in the /tmp/drda directory for a UNIX system<br />

and the C:\temp\drda directory for a Windows system. You need to use the<br />

drdaprint tool to convert the trace files to a readable format.<br />

Example 3-38 shows the use of drdaprint.<br />

Example 3-38 Using the drdaprint tool<br />

C:\temp\drda>dir<br />

Volume in drive C is W2003<br />

Volume Serial Number is 50DA-70D7<br />

Directory of C:\temp\drda<br />

22/06/2010 18:50 .<br />

22/06/2010 18:50 ..<br />

22/06/2010 18:50 2,269 drda.47<br />

1 File(s) 2,269 bytes<br />

2 Dir(s) 76,628,135,936 bytes free<br />

C:\temp\drda>drdaprint<br />

Usage: drdaprint [-f] [-o outfile] inpfile<br />

-f: format hex dump<br />

C:\temp\drda>drdaprint -o trace.txt drda.47<br />

C:\temp\drda><br />

Example 3-39 shows a section of the DRDA trace file.<br />

Example 3-39 DRDATrace file<br />

C:\temp\drda>type trace.txt<br />

DRDADBG Version 1<br />

1 data IDS DRDA Communication Manager<br />

function sqljcIntReceive()<br />

bytes 270<br />

time 2010-06-22 18:50:13.31200<br />

RECEIVE BUFFER(AS):<br />

122 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


EXCSAT RQSDSS (ASCII) (EBCDIC)<br />

0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF 0123456789ABCDEF<br />

0000 00C3D041000100BD 10410080115EA289 ...A.....A...^.. .C}..........;si<br />

0010 949793856DA29893 6DA685999996994B ....m...m......K mple_sql_werror.<br />

0020 85A7F0F6F1F4F0C4 F9F4F0F0F0000000 ................ ex06140D94000...<br />

0030 0000000000000000 0000000000000000 ................ ................<br />

0040 0000000000000000 000000000060F0F0 .............`.. .............-00<br />

0050 F0F1C1C4D4C9D5C9 E2E3D9C1E3D6D940 ...............@ 01ADMINISTRATOR<br />

0060 4040404040404040 4040404040404040 @@@@@@@@@@@@@@@@<br />

0070 E2E3D6D9C5E26DC4 F0C4C2F240404040 ......m.....@@@@ STORES_D0DB2<br />

0080 4040404040404040 40F0001814041403 @@@@@@@@@....... 0......<br />

0090 000A2407000A1474 0005240F00081440 ..$....t..$....@ ...............<br />

00A0 0009000B1147D8C4 C2F261D5E3000A11 .....G....a..... ......QDB2/NT...<br />

00B0 6DC4E4C2C9E3D600 0C115AE2D8D3F0F9 m.........Z..... _DUBITO...]SQL09<br />

00C0 F0F7F0 ... 070<br />

Chapter 3. Working with the ODBC driver 123


124 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Chapter 4. Working with ESQL/C<br />

This chapter discusses ESQL/C, an SQL application programming interface<br />

(API) that enables you to embed Structured Query Language (SQL) statements<br />

directly into a C program. ESQL/C is bundled with the <strong>Informix</strong> Client Software<br />

Development Kit (Client SDK). The ESQL/C preprocessor, esql, converts each<br />

SQL statement and all <strong>IBM</strong> <strong>Informix</strong>-specific code to C-language source code<br />

and invokes the C compiler to compile it.<br />

The advantage of using ESQL/C is that it supports all the data types as well as<br />

extended data types of <strong>Informix</strong> and is optimized for an <strong>IBM</strong> <strong>Informix</strong> database. If<br />

you are using only <strong>Informix</strong> as your database server, then using ESQL/C might<br />

be your best choice.<br />

In this chapter, we discuss the basic elements of an <strong>Informix</strong> ESQL/C application<br />

and show how to perform database operations within an ESQL/C program. We<br />

end the chapter by looking at various methods in handling exceptions and<br />

troubleshooting.<br />

This chapter includes the following topics:<br />

► <strong>Informix</strong> ESQL/C<br />

► Setup and configuration<br />

► Windows system configuration<br />

► Developing an ESQL/C application<br />

4<br />

© Copyright <strong>IBM</strong> Corp. 2010. All rights reserved. 125


4.1 <strong>Informix</strong> ESQL/C<br />

<strong>Informix</strong> ESQL/C includes the following software components:<br />

► The <strong>Informix</strong> ESQL/C libraries of C functions, which provide access to the<br />

database server<br />

► The <strong>Informix</strong> ESQL/C header files, which provide definitions for the data<br />

structures, constants, and macros that are useful to the <strong>Informix</strong> ESQL/C<br />

program<br />

► The esql command, which processes the <strong>Informix</strong> ESQL/C source code to<br />

create a C source file that it then passes to the C compiler<br />

► The finderr utility on the UNIX system and the <strong>Informix</strong> Error Messages<br />

Windows-based <strong>Informix</strong> error messages utility that enable you to obtain<br />

information about <strong>IBM</strong> <strong>Informix</strong>-specific error messages<br />

On Windows platforms, <strong>Informix</strong> provides the following additional utilities:<br />

► The setnet32.exe utility, which is a Windows-based utility that enables you to<br />

set configuration information<br />

► The iLogin utility, which is a demonstration program that displays a dialog box<br />

with fields for the connection parameters and for testing a connection to the<br />

database server (uses the stores7 database)<br />

Figure 4-1 gives an overview of the relationship between ESQL/C and the native<br />

C and illustrates the process of the transfer of control.<br />

Figure 4-1 Relationship between <strong>Informix</strong> ESQL/C and C<br />

When you have created an <strong>Informix</strong> ESQL/C program file, you run the esql<br />

command on that file. By default, the <strong>Informix</strong> ESQL/C preprocessor runs first<br />

and translates the embedded SQL statements in the program into <strong>Informix</strong><br />

ESQL/C function calls that communicate with the database server. The <strong>Informix</strong><br />

ESQL/C preprocessor produces a C source file and calls the C compiler. The C<br />

compiler then compiles your source file and links any other C source file, object<br />

file, or library file the same way as any other C program.<br />

126 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


If the esql command does not encounter errors in one of these steps, it<br />

generates an executable file. You can run the compiled <strong>Informix</strong> ESQL/C<br />

program as you would run any C program. When the program runs, it calls the<br />

<strong>Informix</strong> ESQL/C library procedures. The library procedures set up<br />

communications with the database server to carry out the SQL operations.<br />

4.2 Setup and configuration<br />

<strong>Informix</strong> ESQL/C is installed, by default, as a part of Client SDK. The release<br />

notes for Client SDK contain the information about supported versions of the <strong>IBM</strong><br />

<strong>Informix</strong> database server. Make sure that you install the version of Client SDK<br />

that is supported by the database with which you are working.<br />

4.3 Windows system configuration<br />

On a Windows system, the default Client SDK installation directory is C:\Program<br />

Files\<strong>IBM</strong>\<strong>Informix</strong>\Client-SDK. Make sure that the INFORMIXDIR<br />

environment variable is pointing to the directory where the product was installed.<br />

The PATH environment variable needs to contain the following directories:<br />

► The path to the bin directory that is under the installation directory needs to<br />

be defined (that is, the PATH variable needs the $INFORMIXDIR/bin directory<br />

defined).<br />

► The path where native C compiler is located. <strong>Informix</strong> Client products are<br />

certified with the Microsoft Visual C++ 2005 SP1.<br />

UNIX configuration<br />

On UNIX platforms, the default installation directory for Client SDK is<br />

/opt/<strong>IBM</strong>/informix. The INFORMIXDIR environment variable needs to point to<br />

the directory where the product was installed. Add the following directories to the<br />

PATH environment variable:<br />

► The bin directory under the installation directory, $INFORMIXDIR/bin<br />

► The path to the native C compiler<br />

The sqlhosts file contains the information that is required to connect to an <strong>IBM</strong><br />

<strong>Informix</strong> database server. You must set this file to include an entry for your<br />

<strong>Informix</strong> database server name, ESQL/C required protocol, host name, and port<br />

number. By default, the sqlhosts file is under the $INFORMIXDIR/etc/ directory.<br />

You can use the INFORMIXSQLHOSTS environment variable to point to a<br />

different location.<br />

Chapter 4. Working with ESQL/C 127


Example 4-1 shows a simple sqlhosts file.<br />

Example 4-1 The sqlhosts file<br />

#server protocol hostname service/port<br />

demo_on onsoctcp kodiak 9088<br />

For more information about the sqlhosts file, refer to:<br />

http://publib.boulder.ibm.com/infocenter/idshelp/v115/topic/com.ibm.admin.doc/i<br />

ds_admin_0158.htm<br />

4.4 Developing an ESQL/C application<br />

In this section, we describe how to connect to a database, how to perform basic<br />

database operations such as delete and insert, and how to update using<br />

ESQL/C. We also describe the handling of extended data types by ESQL/C.<br />

We use the sample instance and database that <strong>Informix</strong> Server provides to<br />

demonstrate ESQL/C application development. The sample instance, demo_on, is<br />

created when the <strong>Informix</strong> server is installed. On a Windows operating system,<br />

the sample instance is ol_svr_custom. You can create a sample database,<br />

stores_demo, under the demo_on instance and populate that sample database<br />

with tables and data by running the dbaccessdemo utility that resides in the<br />

$INFORMIXDIR/bin/ directory.<br />

4.4.1 Creating an ESQL/C application<br />

To build an <strong>Informix</strong> ESQL/C application:<br />

1. Develop a C program with the embedded <strong>Informix</strong> SQL statements, and name<br />

the program with a .ec or .ecp extension. The SQL statements are qualified<br />

with an EXEC SQL keyword or the dollar sign ($) symbol as shown in the<br />

following example:<br />

EXEC SQL include sqlca;<br />

EXEC SQL SELECT fname into :c1 FROM customer WHERE customer_num=:i1<br />

$SET ISOLATION DIRTY READ;<br />

2. Preprocess the <strong>Informix</strong> ESQL/C source file with the esql command. The<br />

esql command also invokes the C compiler to compile the program into object<br />

code.<br />

As necessary, correct errors that are reported by the preprocessor and the<br />

compiler and then repeat this step.<br />

128 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


3. Link the object code into one or more executable files using the esql<br />

command. The executable files have a .exe extension.<br />

4. Run the application.<br />

You run the compiled <strong>Informix</strong> ESQL/C program as you would any C program.<br />

When the program runs, it calls the <strong>Informix</strong> ESQL/C library procedures. The<br />

library procedures set up communications with the database server to carry<br />

out the SQL operations.<br />

Example 4-2 shows a simple program, customer.ec, that connects to the<br />

database and retrieves data. All the SQL-related statements are embedded in<br />

the C program with the EXEC SQL keyword.<br />

Example 4-2 Simple ESQL/C program<br />

#include <br />

EXEC SQL include sqlca;<br />

EXEC SQL include sqltypes;<br />

int main()<br />

{<br />

EXEC SQL BEGIN DECLARE SECTION;<br />

int i1=101;<br />

char c1[50];<br />

char c2[50];<br />

EXEC SQL END DECLARE SECTION;<br />

int i2;<br />

EXEC SQL connect to 'stores_demo';<br />

EXEC SQL select fname,lname into :c1, :c2 from customer where<br />

customer_num=:i1<br />

;<br />

if (SQLCODE == 100)<br />

{<br />

printf("SQLCODE=%d\n",SQLCODE);<br />

printf("Data not found\n");<br />

}<br />

else<br />

{<br />

printf("SQLCODE=%d\n",SQLCODE);<br />

printf("Data found \n");<br />

printf("Last Name \t%s\n",c1);<br />

printf("First Name \t%s\n",c2);<br />

}<br />

}<br />

Chapter 4. Working with ESQL/C 129


Compiling ESQL/C programs<br />

The esql command translates <strong>Informix</strong> ESQL/C code to C code and then calls<br />

the C compiler to compile and link the C code.<br />

The C compiler takes the following actions:<br />

1. Compiles the C language statements to object code.<br />

2. Links to <strong>Informix</strong> ESQL/C libraries and to any other files or libraries that you<br />

specify.<br />

3. Creates an executable file.<br />

The general syntax for an esql command to compile is as follows:<br />

esql <br />

By default, the esql command creates an executable called a.out in the current<br />

directory. You can explicitly specify the name of the executable file with the -o<br />

option. For example, the following command compiles the customer.ec<br />

executable file shown in Example 4-2 on page 129 and produces the executable<br />

file customer.exe:<br />

esql -o customer.ec customer.exe<br />

If you run the esql command on a Windows operating system, the name of the<br />

target file defaults to the name of the first <strong>Informix</strong> ESQL/C source file on the<br />

esql command line. The extension is changed to either .exe or .dll, depending<br />

on the type of target that is generated.<br />

You can use a compiler other than the native C compiler by setting the<br />

INFORMIXC environment variable. Table 4-1 lists the native C compilers on<br />

various platforms.<br />

Table 4-1 Native C compiler<br />

Platforms Native compiler<br />

Solaris CC<br />

HP aC++<br />

Windows VC++ / VS2008/ VS2005<br />

AIX xlc<br />

Open source gcc/g++<br />

If you want to pass C compiler options that have the same names as <strong>Informix</strong><br />

ESQL/C processor options, precede them with the -cc option. For example, the<br />

130 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


following esql command passes the -od and -g options to the C compiler but<br />

uses the -db2 option itself:<br />

esql -cc -od -g demo1.ec -db2<br />

Shared libraries<br />

<strong>IBM</strong> <strong>Informix</strong> products use the <strong>Informix</strong> general libraries for interactions between<br />

the client SQL API products (<strong>IBM</strong> <strong>Informix</strong> ESQL/C and <strong>IBM</strong> <strong>Informix</strong><br />

ESQL/COBOL) and the database server. You can choose between the following<br />

types of <strong>Informix</strong> general libraries to link with your <strong>Informix</strong> ESQL/C application:<br />

► Static <strong>Informix</strong> general libraries<br />

To link a static library, the linker copies the library functions to the executable<br />

file of your <strong>Informix</strong> ESQL/C program. The static <strong>Informix</strong> general libraries<br />

allow an <strong>Informix</strong> ESQL/C program on computers that do not support shared<br />

memory to access the <strong>Informix</strong> general library functions.<br />

To link static libraries use the -static option, for example:<br />

esql -static file.ec -o file.exe<br />

► Shared <strong>Informix</strong> general libraries<br />

To link a shared library, the linker copies information about the location of the<br />

library to the executable file of your <strong>Informix</strong> ESQL/C program. The shared<br />

<strong>Informix</strong> libraries allow several applications to share a single copy of these<br />

libraries, which the operating system loads just once into shared memory.<br />

► Thread-safe versions of static and shared <strong>Informix</strong> general libraries<br />

The thread-safe versions of <strong>Informix</strong> general libraries allow an <strong>Informix</strong><br />

ESQL/C application that has several threads to call these library functions<br />

simultaneously. The thread-safe versions of <strong>Informix</strong> libraries are available as<br />

both static libraries and shared libraries.<br />

There are some platform specific considerations when you link shared <strong>Informix</strong><br />

general libraries to an ESQL/C module. The environment variable that specifies<br />

the search path at run time is different depending on the platform, as listed in<br />

Table 4-2.<br />

Table 4-2 Environment variable for shared libraries<br />

Platform Environment variable<br />

AIX LIBPATH<br />

Solaris LD_LIBRARY_PATH<br />

HP-UX SHLIB_PATH<br />

Mac OS X DYLD_LIBRARY_PATH<br />

Chapter 4. Working with ESQL/C 131


Platform Environment variable<br />

Linux LD_LIBRARY_PATH<br />

Windows LIB<br />

Set the $INFORMIXDIR/lib directory and any of its subdirectories to specify the<br />

shared-library path. For example, on Linux, set the LD_LIBRARY_PATH<br />

environment variable as follows:<br />

► Bourne shell<br />

LD_LIBRARY_PATH=$INFORMIXDIR/lib:$LD_LIBRARY_PATH<br />

export LD_LIBRARY_PATH<br />

► C shell<br />

setenv LD_LIBRARY_PATH $INFORMIXDIR/lib:$LD_LIBRARY_PATH<br />

On a Windows system, use the following command:<br />

set LIB = %INFORMIXDIR%\lib\;%LIB%<br />

To link shared <strong>Informix</strong> general libraries with an <strong>Informix</strong> ESQL/C module, you do<br />

not need to specify a command-line option. <strong>Informix</strong> ESQL/C links shared<br />

libraries by default. The following command compiles the file.ec source file with<br />

shared <strong>Informix</strong> libraries:<br />

esql myfile.ec -o myfile.exe<br />

Choosing between shared and static library versions<br />

Shared libraries are most useful in multiuser environments where only one copy<br />

of the library is required for all applications. Shared libraries bring the following<br />

benefits to your <strong>Informix</strong> ESQL/C application:<br />

► Shared libraries reduce the size of executable files because these library<br />

functions are linked dynamically on an as-needed basis.<br />

► At run time, a single copy of a shared library can be linked to several<br />

programs, which results in less memory use.<br />

► The effects of shared libraries in an <strong>Informix</strong> ESQL/C executable are<br />

transparent to the user.<br />

Although shared libraries save both disk and memory space, when an <strong>Informix</strong><br />

ESQL/C application uses them, it must perform the following overhead tasks:<br />

► Dynamically load the shared library into memory for the first time<br />

► Perform link-editing operations<br />

► Execute library position-independent code<br />

132 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


These overhead tasks can incur runtime penalties and are not necessary when<br />

you use static libraries.<br />

4.4.2 Performing database operations<br />

In this section, we discuss how to perform basic database operations in an<br />

ESQL/C application:<br />

► Database connections<br />

► Simple SQL statements (SELECT, INSERT, UPDATE, and DELETE)<br />

► Static and dynamic SQL<br />

► Calling SQL routines (stored procedures)<br />

► Using transactions<br />

In the program, we try to make use of most commonly used data types. For<br />

information about other data types, refer to:<br />

http://publib.boulder.ibm.com/infocenter/idshelp/v115/index.jsp?topic=/com.ibm.<br />

esqlc.doc/sii-03-sourceforchaptitle.htm<br />

Database connections<br />

When an <strong>Informix</strong> ESQL/C application executes, it has no connections to any<br />

database server. For SQL statements to run, however, such a connection must<br />

exist. To establish a connection to a database server, the <strong>Informix</strong> ESQL/C<br />

program must take the following actions:<br />

1. Use an SQL statement to establish a connection to the database server.<br />

2. Specify, in the SQL statement, the name of the database server to which to<br />

connect.<br />

The client application connects to the default database server when the<br />

application does not explicitly specify a database server for the connection. You<br />

must set the INFORMIXSERVER environment variable even if the application<br />

does not establish a connection to the default database server.<br />

If user name and password are not explicitly specified using the InetLogin<br />

structure or the USER clause, the default user ID is used to attempt the<br />

connection. The default user ID is the login name of the user who is running the<br />

application.<br />

Chapter 4. Working with ESQL/C 133


Example 4-3 shows a statement that connects to the stores_demo database<br />

under the demo_on instance.<br />

Example 4-3 Database connection statement<br />

EXEC SQL connect to 'stores_demo@demo_on';<br />

EXEC SQL connect to stores_demo user :username using :password;<br />

For more information about database connections in ESQL/C, refer to:<br />

http://publib.boulder.ibm.com/infocenter/idshelp/v115/topic/com.ibm.esqlc.doc/s<br />

ii12164286.htm#sii12164286<br />

Simple SQL statements<br />

There are several way to execute an SQL statement from an ESQL/C application.<br />

The application must choose an appropriate method based on the nature of the<br />

SQL statement.<br />

► SQL statements that do not return a result set of data such as INSERT,<br />

DELETE, UPDATE, or Data Definition Language (DDL) can be executed<br />

using the EXEC SQL command (same as the $ prefix) or the EXEC SQL<br />

execute immediate statement. Both methods produce the same C code.<br />

EXEC SQL execute immediate :cmdstring;<br />

$CREATE TABLE my_customer (fname char(20));<br />

If the SQL statement is going to be executed more than one time during the<br />

life of the application, it can be prepared with the EXEC SQL PREPARE<br />

command and then executed when required using the EXEC SQL EXECUTE<br />

command:<br />

EXEC SQL prepare d_id from :stmt_buf;<br />

EXEC SQL execute d_id;<br />

► SQL statements that return one row can be executed using the EXEC SQL<br />

EXECUTE INTO command. These types of statement are normally referred<br />

as singleton statements.<br />

EXEC SQL SELECT specs into :mspecs FROM my_customer WHERE customer_num=2;<br />

► SQL statements that return more than one row are executed using a select<br />

cursor:<br />

EXEC SQL declare cursor1 cursor for SELECT fname into :var1 from customer;<br />

EXEC SQL open cursor1;<br />

EXEC SQL fetch cursor1;<br />

134 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Example 4-4 demonstrates how to execute an SQL statement using some of<br />

these previously described methods.<br />

Example 4-4 Simple SQL statements (INSERT, UPDATE, and DELETE)<br />

#include <br />

#include <br />

EXEC SQL include sqlca;<br />

EXEC SQL include sqltypes;<br />

int main()<br />

{<br />

EXEC SQL BEGIN DECLARE SECTION;<br />

char cmdstring[4096];<br />

string *fname[5] = { "Ludwig","Carole", "Philip", "Anthony", "Raymond" };<br />

string *lname[5] = { "Pauli", "Sadler", "Currie", "Higgins", "Vector" };<br />

string *company[5] = {"All Sports Supplies","Sports Spot", "Phil's Sports", "Play<br />

Ball!", "Los Altos Sports" };<br />

char pref='t';<br />

char *specs[5] = { "This is just any string ", "This is just another string ",<br />

"This is the third string", "This is one more string", "This is the last string"};<br />

lvarchar mspecs[250];<br />

char *order_date[5] = {"08/01/77","08/02/77","08/03/77","08/04/77","08/05/77"};<br />

float ship_charge[5] = {10000.59,590000.32,345577.12,987098.32,876893.22};<br />

char *ship_duration[5] = {"10:10:10","11:11:11","22:22:22","33:33:33","44:44:44"};<br />

EXEC SQL END DECLARE SECTION;<br />

$WHENEVER ERROR STOP;<br />

int i;<br />

EXEC SQL connect to 'stores_demo';<br />

$ CREATE TABLE my_customer (<br />

customer_num bigserial,<br />

fname char(15),<br />

lname char(15),<br />

company char(30),<br />

preferred boolean,<br />

specs lvarchar<br />

);<br />

$ CREATE TABLE my_orders (<br />

order_num bigserial,<br />

order_date date ,<br />

customer_num bigint,<br />

ship_charge money(10,2),<br />

ship_duration INTERVAL hour to second<br />

);<br />

for (i = 0; i < 5 ; i++)<br />

{<br />

$INSERT INTO my_customer VALUES (<br />

0,<br />

Chapter 4. Working with ESQL/C 135


:fname[i],<br />

:lname[i],<br />

:company[i],<br />

:pref,<br />

:specs[i]<br />

);<br />

}<br />

for (i = 0; i < 5 ; i++)<br />

{<br />

sprintf(cmdstring, "INSERT INTO my_orders VALUES (10000001,'%s',%d,%f,'%s' );",<br />

order_date[i], i,ship_charge[i], ship_duration[i]);<br />

EXEC SQL execute immediate :cmdstring;<br />

}<br />

sprintf(cmdstring, "UPDATE my_customer SET specs='This is a new spec' WHERE customer_num<br />

= 2");<br />

EXEC SQL execute immediate :cmdstring;<br />

if (SQLCODE != 0)<br />

printf("SQLCODE=%d\n",SQLCODE);<br />

sprintf(cmdstring, "DELETE FROM my_customer where customer_num=3");<br />

EXEC SQL execute immediate :cmdstring;<br />

if (SQLCODE != 0)<br />

printf("SQLCODE=%d\n",SQLCODE);<br />

EXEC SQL SELECT specs into :mspecs FROM my_customer WHERE customer_num=2;<br />

if (SQLCODE != 0)<br />

printf("SQLCODE=%d\n",SQLCODE);<br />

else<br />

printf("The spec for the customer is :%s\n", mspecs);<br />

}<br />

For additional information regarding the execution of SQL statements, refer to:<br />

http://publib.boulder.ibm.com/infocenter/idshelp/v10/index.jsp?topic=/com.ibm.e<br />

sqlc.doc/esqlc298.htm<br />

Static and dynamic SQL<br />

The SQL statements shown in Example 4-4 on page 135 are all static SQL<br />

statements. With a static SQL statement, all the information that is needed is<br />

known at compile time. However, in some applications the programmer does not<br />

know the contents or possibly even the types of SQL statements that the<br />

program needs to execute. For example, a program might prompt the user to<br />

enter a SELECT statement, so that the programmer has no idea what columns<br />

are accessed when the program runs.<br />

Such applications require dynamic SQL statements. Dynamic SQL statements<br />

allow an <strong>IBM</strong> <strong>Informix</strong> ESQL/C program to build an SQL statement at run time, so<br />

that the contents of the statement can be determined by user input.<br />

136 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Example 4-5 shows how to use dynamic SQL in a program.<br />

Example 4-5 Dynamic SQL statements<br />

#include <br />

EXEC SQL include sqlca;<br />

EXEC SQL include sqltypes;<br />

int main()<br />

{<br />

EXEC SQL BEGIN DECLARE SECTION;<br />

int i1;<br />

char cmdstring[2048];<br />

char c1[50];<br />

char c2[50];<br />

EXEC SQL END DECLARE SECTION;<br />

int i2;<br />

EXEC SQL connect to 'stores_demo';<br />

printf("Enter the customer number [101-128] to see the names:");<br />

scanf("%d", &i1);<br />

sprintf (cmdstring, "SELECT fname,lname from customer where customer_num = ?");<br />

EXEC SQL prepare ex_id from :cmdstring;<br />

EXEC SQL execute ex_id into :c1,:c2 using :i1;<br />

;<br />

if (SQLCODE == 100)<br />

{<br />

printf("SQLCODE=%d\n",SQLCODE);<br />

printf("Data not found\n");<br />

}<br />

else<br />

{<br />

printf("SQLCODE=%d\n",SQLCODE);<br />

printf("Data found \n");<br />

printf("Last Name \t%s\n",c1);<br />

printf("First Name \t%s\n",c2);<br />

}<br />

}<br />

OUTPUT:<br />

Enter the customer number [101-128] to see the names:102<br />

SQLCODE=0<br />

Data found<br />

Last Name Carole<br />

First Name Sadle<br />

Chapter 4. Working with ESQL/C 137


The SELECT statement shown in Example 4-5 on page 137 is called a singleton<br />

SELECT statement because it returns only one row. For SELECT statements<br />

that return multiple rows, you must use a SELECT cursor statement.<br />

Example 4-6 shows how to use cursor for SELECT statements that return<br />

multiple rows.<br />

Example 4-6 Using cursor for SELECT statements that return multiple rows<br />

#include <br />

EXEC SQL include sqlca;<br />

EXEC SQL include sqltypes;<br />

int main()<br />

{<br />

EXEC SQL BEGIN DECLARE SECTION;<br />

int i;<br />

char cmdstring[2048];<br />

char c1[50];<br />

char c2[50];<br />

EXEC SQL END DECLARE SECTION;<br />

EXEC SQL connect to 'stores_demo';<br />

printf("Enter customer number [103 - 128] :");<br />

scanf("%d", &i);<br />

sprintf (cmdstring, "SELECT fname,lname from customer where customer_num < ?;");<br />

EXEC SQL prepare ex_id from :cmdstring;<br />

EXEC SQL declare ex_cursor cursor for ex_id;<br />

EXEC SQL open ex_cursor using :i;<br />

/* Print out what DESCRIBE returns*/<br />

for (;;)<br />

{<br />

EXEC SQL fetch ex_cursor into :c1,:c2;<br />

if (strncmp(SQLSTATE, "00", 2) != 0)<br />

break;<br />

if (SQLCODE == 100)<br />

{<br />

printf("SQLCODE=%d\n",SQLCODE);<br />

printf("Data not found\n");<br />

}<br />

else<br />

{<br />

printf("%s\t%s\n",c1,c2);<br />

}<br />

}<br />

OUTPUT:<br />

Enter customer number [103 - 128] : 108<br />

Ludwig Pauli<br />

Carole Sadler<br />

Philip Currie<br />

138 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Anthony Higgins<br />

Raymond Vector<br />

George Watson<br />

Charles Ream<br />

For more details about dynamic SQL and the cursors, refer to:<br />

http://publib.boulder.ibm.com/infocenter/idshelp/v115/topic/com.ibm.esqlc.doc/s<br />

ii-sc3dysq-35492.htm#sii-sc3dysq-35492<br />

Calling SQL routines<br />

In this section, we demonstrate how to call an SQL routine from an ESQL/C<br />

application. You can accomplish a wide range of objectives with SQL routines,<br />

including improving database performance, simplifying writing applications, and<br />

limiting or monitoring access to data. Because an SQL routine is stored in an<br />

executable format, you can use it for repeated tasks to improve performance.<br />

When you invoke an SPL routine, rather than straight SQL code, you can bypass<br />

repeated parsing, validity checking, and query optimization.<br />

Example 4-7 shows a simple program that contains an SPL routine that receives<br />

arguments price and percent tax and that returns price after adding the tax.<br />

Example 4-7 Calling SQL routines<br />

#include <br />

$ INCLUDE sqlca.h;<br />

$ INCLUDE sqltypes.h;<br />

int main()<br />

{<br />

EXEC SQL BEGIN DECLARE SECTION;<br />

char cmdstring[2048];<br />

float n1,n2;<br />

int i=2;<br />

EXEC SQL END DECLARE SECTION;<br />

EXEC SQL whenever sqlerror stop;<br />

EXEC SQL CONNECT TO 'stores_demo';<br />

sprintf(cmdstring, "CREATE FUNCTION inc_price(n1 money(8,2), n2 int) RETURNING<br />

money(8,2) RETURN(n1 + (n1 *n2)/ 100); END FUNCTION;");<br />

EXEC SQL execute immediate :cmdstring;<br />

sprintf(cmdstring, "SELECT FIRST 5 total_price, inc_price(total_price,?) from items ;");<br />

EXEC SQL prepare ex_id from :cmdstring;<br />

EXEC SQL declare ex_cursor cursor for ex_id;<br />

EXEC SQL open ex_cursor using :i;<br />

/* Print out what DESCRIBE returns*/<br />

for (;;)<br />

{<br />

Chapter 4. Working with ESQL/C 139


EXEC SQL fetch ex_cursor into :n1,:n2;<br />

if (strncmp(SQLSTATE, "00", 2) != 0)<br />

break;<br />

if (SQLCODE == 100)<br />

{<br />

printf("SQLCODE=%d\n",SQLCODE);<br />

printf("Data not found\n");<br />

}<br />

else<br />

{<br />

printf("%f\t%f\n",n1,n2);<br />

}<br />

}<br />

}<br />

OUTPUT:<br />

250.000000 255.000000<br />

960.000000 979.200012<br />

240.000000 244.800003<br />

20.000000 20.400000<br />

840.000000 856.799988<br />

Using transactions<br />

A transaction is a collection of SQL statements that are treated as a single unit of<br />

work. All the SQL statements that you issue in an ANSI-compliant database are<br />

contained in transactions automatically. With a database that is not ANSI<br />

compliant, transaction processing is an option.<br />

In a database that is not ANSI compliant, a transaction is enclosed by a BEGIN<br />

WORK statement and a COMMIT WORK or a ROLLBACK WORK statement. In<br />

an ANSI-compliant database, the BEGIN WORK statement is unnecessary,<br />

because all statements are contained in a transaction automatically. You need to<br />

indicate only the end of a transaction with a COMMIT WORK or ROLLBACK<br />

WORK statement.<br />

Example 4-8 shows an example using transactions.<br />

Example 4-8 Using transactions<br />

#include <br />

$include "sqlca.h";<br />

$include "sqlhdr.h";<br />

$include "sqltypes.h";<br />

main()<br />

{<br />

EXEC SQL BEGIN DECLARE SECTION;<br />

140 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


int n1;<br />

char c1[20];<br />

EXEC SQL END DECLARE SECTION;<br />

EXEC SQL whenever sqlerror stop;<br />

EXEC SQL CREATE DATABASE itso WITH LOG;<br />

EXEC SQL CREATE TABLE t1(num serial, name char(20));<br />

EXEC SQL BEGIN WORK;<br />

EXEC SQL INSERT INTO t1 VALUES (0,'name1');<br />

EXEC SQL INSERT INTO t1 VALUES (0,'name2');<br />

EXEC SQL INSERT INTO t1 VALUES (0,'name3');<br />

EXEC SQL ROLLBACK;<br />

EXEC SQL BEGIN WORK;<br />

EXEC SQL INSERT INTO t1 VALUES (0,'name4');<br />

EXEC SQL INSERT INTO t1 VALUES (0,'name5');<br />

EXEC SQL COMMIT;<br />

EXEC SQL declare ifx_cursor cursor for select num,name into :n1,:c1 from t1;<br />

EXEC SQL open ifx_cursor ;<br />

for (;;)<br />

{<br />

EXEC SQL fetch ifx_cursor;<br />

if (sqlca.sqlcode!=0)<br />

break;<br />

printf("%d\t%s\n",n1,c1);<br />

}<br />

EXEC SQL close ifx_cursor;<br />

EXEC SQL free ifx_cursor;<br />

}<br />

OUTPUT:<br />

4 name4<br />

5 name5<br />

4.4.3 Data types mapping<br />

This section contains information about the correspondence data types between<br />

SQL and C and how to handle data types in an <strong>IBM</strong> <strong>Informix</strong> ESQL/C program.<br />

When a query is executed by the application, the data that the <strong>Informix</strong> server<br />

returns might be in a different format than the format that the application uses.<br />

The ESQL/C converts the data passed between the application and the<br />

database server. This process is transparent to the application. The only<br />

requirement for the application is to specify the correct data types in ESQL/C.<br />

Chapter 4. Working with ESQL/C 141


Table 4-3 lists a few ESQL/C data type mapping as examples.<br />

Table 4-3 <strong>Informix</strong> data type mapping<br />

<strong>Informix</strong> SQL ESQL/C<br />

BOOLEAN boolean<br />

BYTE loc_t<br />

LVARCHAR lvarchar<br />

NCHAR(n) fixchar [n] or string [n+1]<br />

NVARCHAR(m) varchar[m+1] or string [m+1]<br />

SERIAL8 int8 or ifx_int8_t<br />

TEXT loc_t<br />

BLOB ifx_lo_t<br />

CLOB ifx_lo_t<br />

LIST(e) collection<br />

MULTISET(e) collection<br />

Opaque data type lvarchar, fixed binary, or var binary<br />

ROW(...) row<br />

SET(e) collection<br />

For a complete list of all the <strong>Informix</strong> SQL to ESQL/C data type mapping, refer to:<br />

http://publib.boulder.ibm.com/infocenter/idshelp/v115/index.jsp?topic=/com.ibm.<br />

esqlc.doc/sii03147680.htm<br />

4.4.4 Handling special data types<br />

This section describe how to work with <strong>Informix</strong> specific data types. We discuss<br />

the following data types:<br />

► Smart large objects (BLOB and CLOB)<br />

► Collection data types (LIST, MULTISET, and SET)<br />

► ROW data type<br />

To store large objects inside database, you can use data types such as TEXT,<br />

BYTE, BLOB, and CLOBS. <strong>Informix</strong> supports simple large objects and smart<br />

large objects. Simple large objects are the TEXT and BYTE types that exist<br />

primarily for compatibility with earlier versions of <strong>Informix</strong> applications. The smart<br />

142 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


large objects are the BLOB and CLOBs. When you write new applications that<br />

need to access large objects, use smart large objects to hold character (CLOB)<br />

and binary (BLOB) data.<br />

Table 4-4 summarizes the advantages that smart large objects present over<br />

simple large objects.<br />

Table 4-4 Advantages of smart blobs over simple blobs<br />

Large object feature Simple large objects Smart large objects<br />

Maximum size of data 2 gigabytes 4 terabytes<br />

Data accessibility No random access to data Random access to data<br />

Reading the large object The database server reads<br />

a simple large object on an<br />

all or nothing basis.<br />

Writing the large object The database server<br />

updates a simple large<br />

object on an all or nothing<br />

basis.<br />

Library functions provide<br />

access that is similar to<br />

accessing an<br />

operating-system file. You<br />

can access specified<br />

portions of the smart large<br />

object.<br />

The database server can<br />

rewrite only a portion of a<br />

smart large object.<br />

Data logging Data logging is always on. Data logging can be turned<br />

on and off.<br />

Example using CLOB and BLOBs<br />

<strong>Informix</strong> ESQL/C supports the SQL data types CLOB and BLOB with the<br />

ifx_lo_t data type. Because of the potentially huge size of smart large object<br />

data, the <strong>Informix</strong> ESQL/C program does not store the data directly in a host<br />

variable. Instead, the client application accesses the data as a file-like structure.<br />

To use smart large object variables in an <strong>Informix</strong> ESQL/C program, take the<br />

following actions:<br />

1. Declare a host variable with the ifx_lo_t data type.<br />

2. Access the smart large object with a combination of the following three data<br />

structures:<br />

– The LO-specification structure, ifx_lo_create_spec_t<br />

– The LO-pointer structure, ifx_lo_t<br />

– An integer LO file descriptor<br />

Smart large objects are stored logically in a table column but stored physically in<br />

a specific type of dbspaces called smart blob space (sbspace). You must create<br />

Chapter 4. Working with ESQL/C 143


the sbspace in the server before you can run this example. For details about<br />

creating the sbspace, refer to:<br />

http://publib.boulder.ibm.com/infocenter/idshelp/v115/topic/com.ibm.admin.doc/i<br />

ds_admin_0491.htm<br />

Example 4-9 illustrates how to work with BLOB and CLOB data types using<br />

ESQL/C functions. The filetoclob and filetoblob functions are used to enter<br />

the CLOB and BLOB data respectively. If your files are located on the client<br />

system, then use the client name as the second argument to the filetoblob<br />

function. If your files are located on the server system, then use the server name<br />

as the second argument.<br />

The output is a part of the file that you insert as a BLOB. In this example, we<br />

used a readme.txt file.<br />

Example 4-9 The ifx_lo_sample.ec file<br />

#include <br />

$include "sqlca.h";<br />

$include "sqlhdr.h";<br />

$include "sqltypes.h";<br />

main()<br />

{<br />

int error, ic1, oflags, cflags, extsz, imsize, isize, iebytes;<br />

time_t time;<br />

struct tm *date_time;<br />

char col_name[300]="test", sbspc[129];<br />

EXEC SQL BEGIN DECLARE SECTION;<br />

fixed binary 'blob' ifx_lo_t c2;<br />

char srvr_name[256];<br />

ifx_lo_create_spec_t *cspec;<br />

ifx_lo_stat_t *stats;<br />

ifx_int8_t size, c1, estbytes, maxsize;<br />

int lofd;<br />

long atime, ctime, mtime, refcnt;<br />

EXEC SQL END DECLARE SECTION;<br />

EXEC SQL whenever sqlerror stop;<br />

EXEC SQL connect to 'stores_demo';<br />

EXEC SQL create table t2 (c1 int, c2 blob);<br />

EXEC SQL insert into t2 values (1,filetoblob ('/tmp/README.txt', 'server','t2','c2'));<br />

EXEC SQL declare ifxcursor cursor for select c1,c2 into :c1,:c2 from t2 for update;<br />

EXEC SQL open ifxcursor;<br />

for (;;)<br />

{<br />

144 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


EXEC SQL fetch ifxcursor;<br />

if (sqlca.sqlcode!=0)<br />

break;<br />

lofd = ifx_lo_open(&c2, LO_RDWR, &error);<br />

ifx_lo_read(lofd, srvr_name, 256, &error);<br />

printf("Value: %s\n",srvr_name);<br />

ifx_lo_write(lofd,col_name,5,&error);<br />

ifx_lo_close(lofd);<br />

}<br />

EXEC SQL close ifxcursor;<br />

EXEC SQL free ifxcursor;<br />

ifx_lo_close(lofd);<br />

}<br />

For more information about the ESQL/C functions to create, alter, and access<br />

BLOB and CLOB data, refer to:<br />

http://publib.boulder.ibm.com/infocenter/idshelp/v115/index.jsp?topic=/com.ibm.<br />

esqlc.doc/sii-03-sourceforchaptitle.htm<br />

Example using collection data types<br />

Collection data types (SET, LIST, and MULTISET) enable you to store and<br />

manipulate collections of data within a single row of a table. A collection data<br />

type has two components:<br />

► A type constructor, which determines whether the collection type is a SET,<br />

MULTISET, or LIST<br />

► An element type, which specifies the type of data that the collection can<br />

contain<br />

The elements of a collection can be of any data type. The elements of a<br />

collection are the values that the collection contains. In a collection that contains<br />

the values {'blue', 'green', 'yellow', and 'red'}, blue represents a single<br />

element in the collection. Every element in a collection must be of the same type.<br />

For example, a collection whose element type is INTEGER can contain only<br />

integer values.<br />

<strong>Informix</strong> ESQL/C uses collection variables to access collection data types. A<br />

collection variable stores the elements from a collection column as though they<br />

were rows in a table. You can use this virtual table as part of a cursor declaration<br />

to fetch the individual elements of the collection column.<br />

Chapter 4. Working with ESQL/C 145


Example 4-10 shows the ESQL/C commands that are used to retrieve an<br />

element from a collection column. The parents column is a collection of INT<br />

values. The collection is stored into the host variable hv1 and is used to open a<br />

cursor using the variable as a virtual table, table(:hv1).<br />

Example 4-10 The collection_sample<br />

EXEC SQL client collection hv1;<br />

EXEC SQL int parent_id;<br />

EXEC SQL select parents into :hv1 from grade12_parents where class_id = 1;<br />

EXEC SQL declare cur1 cursor for select id from table(:hv1);<br />

EXEC SQL open cur1;<br />

EXEC SQL fetch cur1 into :parent_id;<br />

The INT elements of the collection are retrieved from the host variable using the<br />

EXEC SQL fetch cur1 command.<br />

Example 4-11 shows a complete ESQL/C program that illustrates how to insert<br />

and select into tables that contain the collection data types.<br />

Example 4-11 Example using collection types<br />

#include <br />

static void print_collection(<br />

const char *tag,<br />

EXEC SQL BEGIN DECLARE SECTION;<br />

parameter client collection c<br />

EXEC SQL END DECLARE SECTION;<br />

)<br />

{<br />

EXEC SQL BEGIN DECLARE SECTION;<br />

int4 value;<br />

EXEC SQL END DECLARE SECTION;<br />

mint item = 0;<br />

}<br />

146 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong><br />

EXEC SQL WHENEVER ERROR STOP;<br />

printf("COLLECTION: %s\n", tag);<br />

EXEC SQL DECLARE c_collection CURSOR FOR<br />

SELECT * FROM TABLE(:c);<br />

EXEC SQL OPEN c_collection;<br />

while (sqlca.sqlcode == 0)<br />

{<br />

EXEC SQL FETCH c_collection INTO :value;<br />

if (sqlca.sqlcode != 0) break;<br />

printf("\tItem %d, value = %d\n", ++item, value);<br />

}<br />

EXEC SQL CLOSE c_collection;<br />

EXEC SQL FREE c_collection;


mint main(int argc, char **argv)<br />

{<br />

EXEC SQL BEGIN DECLARE SECTION;<br />

client collection list (integer not null) lc1;<br />

client collection set (integer not null) sc1;<br />

client collection multiset (integer not null) mc1;<br />

char *dbase = "stores_demo";<br />

mint seq;<br />

char *stmt1 =<br />

"INSERT INTO t_collections VALUES(0, "<br />

"'LIST{-1,0,-2,3,0,0,32767,249}', 'SET{-1,0,-2,3}', "<br />

"'MULTISET{-1,0,0,-2,3,0}') ";<br />

EXEC SQL END DECLARE SECTION;<br />

if (argc > 1)<br />

dbase = argv[1];<br />

EXEC SQL WHENEVER ERROR STOP;<br />

printf("Connect to %s\n", dbase);<br />

EXEC SQL connect to :dbase;<br />

EXEC SQL CREATE TEMP TABLE t_collections<br />

(<br />

seq serial not null,<br />

l1 list (integer not null),<br />

s1 set (integer not null),<br />

m1 multiset(integer not null)<br />

);<br />

EXEC SQL EXECUTE IMMEDIATE :stmt1;<br />

EXEC SQL ALLOCATE COLLECTION :lc1;<br />

EXEC SQL ALLOCATE COLLECTION :mc1;<br />

EXEC SQL ALLOCATE COLLECTION :sc1;<br />

}<br />

EXEC SQL DECLARE c_collect CURSOR FOR<br />

SELECT seq, l1, s1, m1 FROM t_collections;<br />

EXEC SQL OPEN c_collect;<br />

EXEC SQL FETCH c_collect INTO :seq, :lc1, :sc1, :mc1;<br />

EXEC SQL CLOSE c_collect;<br />

EXEC SQL FREE c_collect;<br />

print_collection("list/integer", lc1);<br />

print_collection("set/integer", sc1);<br />

print_collection("multiset/integer", mc1);<br />

EXEC SQL DEALLOCATE COLLECTION :lc1;<br />

EXEC SQL DEALLOCATE COLLECTION :mc1;<br />

EXEC SQL DEALLOCATE COLLECTION :sc1;<br />

puts("OK");<br />

return 0;<br />

Chapter 4. Working with ESQL/C 147


Example 4-12 shows the output of Example 4-11 on page 146.<br />

Example 4-12 Collection example output<br />

Connect to stores_demo<br />

COLLECTION: list/integer<br />

Item 1, value = -1<br />

Item 2, value = 0<br />

Item 3, value = -2<br />

Item 4, value = 3<br />

Item 5, value = 0<br />

Item 6, value = 0<br />

Item 7, value = 32767<br />

Item 8, value = 249<br />

COLLECTION: set/integer<br />

Item 1, value = -1<br />

Item 2, value = 0<br />

Item 3, value = -2<br />

Item 4, value = 3<br />

COLLECTION: multiset/integer<br />

Item 1, value = -1<br />

Item 2, value = 0<br />

Item 3, value = 0<br />

Item 4, value = -2<br />

Item 5, value = 3<br />

Item 6, value = 0<br />

OK<br />

4.4.5 Exception handling<br />

The applications that you write require that the database server processes your<br />

SQL statements successfully as you intend. If a query fails and you do not know<br />

about the failure, you might display meaningless data to the user.<br />

To handle such errors, an <strong>Informix</strong> ESQL/C program must check that every SQL<br />

statement executes as you intend.<br />

This section discusses the two widely used exception handling methods in<br />

<strong>Informix</strong> applications development:<br />

► Use the SQLSTATE variable and the GET DIAGNOSTICS statement to check<br />

for runtime errors and warnings that your <strong>Informix</strong> ESQL/C program might<br />

generate.<br />

► Use the SQLCODE variable and the SQL Communications Area (sqlca) to<br />

check for runtime errors and warnings that your <strong>Informix</strong> ESQL/C program<br />

might generate.<br />

148 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


For more information about ESQL/C Exception handling, refer to:<br />

http://publib.boulder.ibm.com/infocenter/idshelp/v115/index.jsp?topic=/com.ibm.<br />

esqlc.doc/sii-11-40709.htm<br />

Exception handling with the SQLSTATE variable<br />

After the database server executes an SQL statement, it sets the SQLSTATE<br />

variable with a value that indicates the success or failure of the statement. From<br />

this value, your program can determine if it needs to perform further diagnostics.<br />

If the SQLSTATE variable indicates a problem, you can use the GET<br />

DIAGNOSTICS statement to obtain more information.<br />

Example 4-13 shows how to handle exceptions using the SQLSTATE variable<br />

and the GET DIAGNOSTICS statement. The GET DIAGNOSTICS statement<br />

returns information that is held in the fields of the diagnostics area. The<br />

diagnostics area is an internal structure that the database server updates after it<br />

executes an SQL statement. Each application has one diagnostics area.<br />

Example 4-13 Error handling in ESQL/C<br />

#include <br />

#include <br />

void error_chk()<br />

{<br />

EXEC SQL BEGIN DECLARE SECTION;<br />

mint excp_count;<br />

char overflow[2];<br />

mint excp_num=1;<br />

char message[255];<br />

mint mlen;<br />

char sql_state_code[6];<br />

mint i=1;<br />

EXEC SQL END DECLARE SECTION;<br />

printf("SQLSTATE: %s\n",SQLSTATE);<br />

printf("SQLCODE: %d\n", SQLCODE);<br />

printf("\n");<br />

EXEC SQL get diagnostics :excp_count = NUMBER, :overflow = MORE;<br />

EXEC SQL get diagnostics exception :i :sql_state_code = RETURNED_SQLSTATE, :message =<br />

MESSAGE_TEXT, :mlen = MESSAGE_LENGTH;<br />

printf("EXCEPTION %d: SQLSTATE=%s\n", i, sql_state_code);<br />

message[mlen-1] = '\0';<br />

printf("MESSAGE TEXT: %s\n", message);<br />

}<br />

mint main(int argc, char **argv)<br />

{<br />

EXEC SQL BEGIN DECLARE SECTION;<br />

char *dbase = "stores_demo";<br />

Chapter 4. Working with ESQL/C 149


}<br />

EXEC SQL END DECLARE SECTION;<br />

150 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong><br />

if (argc > 1)<br />

dbase = argv[1];<br />

EXEC SQL WHENEVER sqlerror CALL error_chk ;<br />

printf("Connect to %s\n", dbase);<br />

EXEC SQL connect to :dbase;<br />

EXEC SQL SELECT province FROM customer WHERE customer_num=1;<br />

return 0;<br />

OUTPUT:<br />

Connect to stores_demo<br />

SQLSTATE: IX000<br />

SQLCODE: -217<br />

4.4.6 Troubleshooting<br />

EXCEPTION 1: SQLSTATE=IX000<br />

MESSAGE TEXT: Column (province) not found in any table in the query (or SLV is<br />

undefined).<br />

In this section, we list frequent ESQL/C errors and discuss how to diagnose a<br />

problem using the trace facility. The following typical errors can occur in ESQL/C<br />

applications:<br />

► Locale mismatch<br />

The most common error you might encounter when writing ESQL/C<br />

application is a locale mismatch error:<br />

-23197 Database locale information mismatch<br />

The straight forward solution is to match all the locale-related environment<br />

variables, namely CLIENT_LOCALE, DB_LOCALE, and SERVER_LOCALE.<br />

The default values for CLIENT_LOCALE are en_us.8859-1 for UNIX and<br />

en_us.1252 for Windows systems. You can set these variables using the<br />

export (ksh) or setenv (csh) commands, depending on which shell you are<br />

using. On Windows systems, you can set the locale using the setnet32.exe<br />

utility.<br />

For more information about these locales and related material, refer to:<br />

http://publib.boulder.ibm.com/infocenter/idshelp/v115/index.jsp?topic=/com.<br />

ibm.glsug.doc/ids_gug_035.htm


► Compile and linking errors<br />

If there is a problem with the compile or linking, the following error message is<br />

returned:<br />

error while loading shared libraries: libifsql.so: cannot open shared<br />

object file: No such file or directory<br />

This error is due generally to a wrong setting of the shared library path. Refer<br />

to 4.4.1, “Creating an ESQL/C application” on page 128 for information about<br />

the correct settings.<br />

► Database connection errors<br />

if there is an issue with the database connection, the following error message<br />

is returned:<br />

-25596 The INFORMIXSERVER value is not listed in the sqlhosts file or the<br />

Registry.<br />

This error is due to incorrect setting of INFORMIXSERVER variable. Verify<br />

that it is set to the server instance to which you want to connect.<br />

The SQLIDEBUG trace<br />

ESQL/C uses the SQLI protocol to communicate with the <strong>Informix</strong> database<br />

server. The SQLIDEBUG trace allows you to trace all the messages between the<br />

client and server. You can use it to diagnose problems such as SQL errors,<br />

unexpected return values, or performance issues.<br />

You can enable the SQLIDEBUG trace on both the client and the server side.<br />

On the server side, you can enable SQLIDEBUG using the onmode -p 1<br />

sqli_dbg parameter.<br />

To set SQLIDEBUG on the client side, create the environment variable<br />

SQLIDEBUG with the following format:<br />

sqlidebug=2:path_trace_file<br />

where path_trace_file corresponds to the location and name of the trace file.<br />

Example 4-14 shows how to create the variable on a UNIX platform and how to<br />

decode the SQLI trace file using the sqliprint utility, which is included as part of<br />

Client SDK.<br />

Example 4-14 The SQLIDEBUG trace<br />

informix@irk:/work$ export SQLIDEBUG=2:/tmp/sqlitrace<br />

informix@irk:/work$<br />

informix@irk:/work$ sqliprint /tmp/sqlitrace_17008_0_8c819d0 | more<br />

...<br />

Chapter 4. Working with ESQL/C 151


C->S (16) Time: 2010-07-06 20:21:58.05185<br />

SQ_DBOPEN<br />

"stores7" [7]<br />

NOT EXCLUSIVE<br />

SQ_EOT<br />

S->C (28) Time: 2010-07-06 20:21:58.05487<br />

SQ_DONE<br />

Warning..: 0x15<br />

# rows...: 0<br />

rowid....: 0<br />

serial id: 0<br />

SQ_COST<br />

estimated #rows: 1<br />

estimated I/O..: 1<br />

SQ_EOT<br />

C->S (56) Time: 2010-07-06 20:21:58.05595<br />

SQ_PREPARE<br />

# values: 1<br />

CMD.....: "SELECT code, sname FROM state WHERE code = ?" [44]<br />

SQ_NDESCRIBE<br />

SQ_WANTDONE<br />

...<br />

152 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Chapter 5. Working with the JDBC<br />

drivers<br />

5<br />

In this chapter, we describe how to develop a Java application using the two<br />

available Java Database Connectivity (JDBC) drivers. This chapter includes the<br />

following topics:<br />

► JDBC drivers for an <strong>Informix</strong> database<br />

► Setup and configuration<br />

► JDBC type mapping<br />

► Performing database operations<br />

► <strong>Informix</strong> additional features<br />

© Copyright <strong>IBM</strong> Corp. 2010. All rights reserved. 153


5.1 JDBC drivers for an <strong>Informix</strong> database<br />

Java Database Connectivity (JDBC) is the JavaSoft specification of a standard<br />

application programming interface (API) that allows Java programs to access<br />

database management systems.<br />

The JDBC API consists of a set of interfaces and classes written in the Java<br />

programming language. Using these standard interfaces and classes,<br />

programmers can write applications that connect to databases, send queries<br />

written in structured query language (SQL), and process the results.<br />

Because JDBC is a standard specification, one Java program that uses the<br />

JDBC API can connect to any database management system (DBMS), as long<br />

as a driver exists for that particular DBMS.<br />

For more information about the JDBC API, refer to JDBC documentation at<br />

http://java.sun.com/javase/6/docs/technotes/guides/jdbc/<br />

You can use the following JDBC drivers from a Java application to process data<br />

in an <strong>IBM</strong> <strong>Informix</strong> database:<br />

► <strong>IBM</strong> <strong>Informix</strong> JDBC Driver<br />

► <strong>IBM</strong> Data Server Driver for JDBC and SQLJ<br />

Both JDBC drivers are developed as pure-Java drivers (Type 4). Thus, when you<br />

use a Type 4 driver from a Java application, your session connects directly to the<br />

database or database server without a middle layer.<br />

5.1.1 <strong>IBM</strong> <strong>Informix</strong> JDBC Driver<br />

<strong>IBM</strong> <strong>Informix</strong> JDBC Driver is a platform-independent, industry-standard Type 4<br />

driver that provides enhanced support for distributed transactions.<br />

<strong>Informix</strong> JDBC Driver follows the JDBC 3.0 specifications, providing support for<br />

the following <strong>IBM</strong> <strong>Informix</strong> database engines:<br />

► <strong>IBM</strong> <strong>Informix</strong> 7.x, 9.4x, 10.0, 11.10 and 11.50<br />

► <strong>IBM</strong> <strong>Informix</strong> Extended Parallel Server (XPS) 8.5x<br />

► <strong>IBM</strong> <strong>Informix</strong> Standard Engine (SE) 7.x<br />

► <strong>IBM</strong> <strong>Informix</strong> OnLine Version 5.x<br />

To use <strong>IBM</strong> <strong>Informix</strong> JDBC Driver Version 3.50.JC6, you must use a JDK 1.4.2 or<br />

later package on your platform.<br />

154 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


You can download the <strong>Informix</strong> JDBC Driver from:<br />

http://www14.software.ibm.com/webapp/download/search.jsp?go=y&rs=ifxjdbc<br />

Example 5-1 shows the contents of the <strong>Informix</strong> JDBC Driver package.<br />

Example 5-1 <strong>Informix</strong> JDBC directory<br />

demo<br />

doc<br />

javadoc<br />

release<br />

lib<br />

ifxjdbc.jar<br />

ifxjdbcx.jar<br />

ifxlang.jar<br />

ifxlsupp.jar<br />

ifxsqlj.jar<br />

ifxtools.jar<br />

license<br />

proxy<br />

This is a brief explanation of the .jar files in the driver:<br />

► ifxjdbc.jar<br />

The optimized implementations of the JDBC API interfaces, classes, and<br />

methods.<br />

► ifxjdbcx.jar<br />

The implementation of data source, connection pooling, and XA-related class<br />

files.<br />

► ifxlang.jar<br />

The localized versions of all message text supported by the driver.<br />

► ifxlsupp.jar<br />

Support functions for the ifxlang.jar package.<br />

► ifxsqlj.jar<br />

The classes for runtime support of SQLJ programs.<br />

► ifxtools.jar<br />

The ClassGenerator, lightweight directory access protocol (LDAP) loader, and<br />

other utilities.<br />

Chapter 5. Working with the JDBC drivers 155


5.1.2 <strong>IBM</strong> Data Server Driver for JDBC and SQLJ<br />

<strong>IBM</strong> Data Server Driver for JDBC and SQLJ, formerly known as <strong>IBM</strong> Driver for<br />

JDBC and SQLJ, is a JDBC driver that uses the DRDA protocol to communicate<br />

with <strong>IBM</strong> database servers. The use of a common communication protocol such<br />

as DRDA means that the <strong>IBM</strong> Data Server Driver for JDBC and SQLJ allows you<br />

to write client applications that can use both DB2 and <strong>Informix</strong> database servers.<br />

The <strong>IBM</strong> Data Server Driver for JDBC and SQLJ is compliant with the JDBC 3.0<br />

and JDBC 4.0 specifications. This driver is included as part of the <strong>IBM</strong> Data<br />

Server Driver Package, which is bundled with <strong>Informix</strong> Client Software<br />

Development Kit (Client SDK). <strong>IBM</strong> Data Server Driver for JDBC and SQLJ is<br />

also available as a separate download at:<br />

http://www-01.ibm.com/support/docview.wss?rs=71&uid=swg24026929<br />

Example 5-2 shows a listing of the files that are included in the <strong>IBM</strong> Data Server<br />

Driver for JDBC and SQLJ installation package and highlights important files.<br />

Example 5-2 Data Server Driver for JDBC directory (snippet)<br />

db2jcc.jar<br />

db2jcc4.jar<br />

sqlj.zip<br />

sqlj4.zip<br />

jdbc4_LI_en<br />

jdbc4_LI_en.rtf<br />

jdbc_LI_en<br />

The Data Server Driver for JDBC and SQLJ includes the following JDBC drivers:<br />

► db2jcc.jar<br />

Use the db2jcc.jar file in the CLASSPATH if you plan to use the version of<br />

the <strong>IBM</strong> Data Server Driver for JDBC and SQLJ that includes only JDBC 3.0<br />

and earlier functions.<br />

► db2jcc4.jar<br />

Use the db2jcc4.jar file in the CLASSPATH if you plan to use the version of<br />

the <strong>IBM</strong> Data Server Driver for JDBC and SQLJ that includes only JDBC 4.0<br />

and earlier functions.<br />

► sqlj.zip<br />

Provides support for SQLJ Java applications. SQLJ is used to embed SQL<br />

statements inside Java applications.<br />

► sqlj4.zip<br />

Type 4 driver for SQLJ applications.<br />

156 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


5.2 Setup and configuration<br />

5.2.1 Configuration<br />

In this section, we discuss the setup and configuration parameters of <strong>Informix</strong><br />

JDBC drivers. We also discuss how to verify the connection with the <strong>Informix</strong><br />

database server.<br />

The Data Server Client Driver for JDBC requires the use of a DRDA connection.<br />

Thus, the <strong>Informix</strong> database server must have an alias configured for DRDA<br />

communications. <strong>Informix</strong> JDBC Driver uses native <strong>Informix</strong> protocol or SQLI and<br />

requires no specific alias on the <strong>Informix</strong> database server when using the<br />

<strong>Informix</strong> JDBC Driver.<br />

On the database server, verify that the sqlhosts file contains the correct listeners<br />

for the <strong>Informix</strong> database server.<br />

Example 5-3 shows the sqlhosts file of the <strong>Informix</strong> server that we used in our<br />

examples.<br />

Example 5-3 Our sqlhosts file<br />

demo_on onipcshm kefka demo_on<br />

demo_on_tcp onsoctcp kefka 9088<br />

demo_on_drda drsoctcp kefka 9089<br />

For information regarding how to set up and configure a DRDA alias on the<br />

<strong>Informix</strong> server, refer to 2.1.3, “Configuring <strong>Informix</strong> Server” on page 27.<br />

On the client system, you must have one of the two JDBC drivers installed. For<br />

information about the installation and configuration, refer to 2.2.3, “Setting up<br />

<strong>IBM</strong> Data Server drivers” on page 43 and 2.2.4, “Setting up <strong>Informix</strong> JDBC” on<br />

page 53.<br />

To use any JDBC driver in an application, you must set the CLASSPATH<br />

environment variable to point to the driver files. The CLASSPATH environment<br />

variable tells the Java virtual machine (JVM) and other applications where to find<br />

the Java class libraries that are used in a Java program.<br />

Chapter 5. Working with the JDBC drivers 157


Example 5-4 shows the CLASSPATH environment variable, which contains the<br />

default location of both JDBC drivers.<br />

Example 5-4 CLASSPATH example<br />

set CLASSPATH=C:\Program Files\<strong>IBM</strong>\<strong>IBM</strong> DATA SERVER<br />

DRIVER\java\db2jcc.jar;C:\Program<br />

Files\<strong>IBM</strong>\<strong>Informix</strong>_JDBC_Driver\lib\ifxjdbc.jar;C:\Program<br />

Files\<strong>IBM</strong>\<strong>Informix</strong>_JDBC_Driver\lib\ifxjdbcx.jar;%CLASSPATH%;.;<br />

Products such as <strong>IBM</strong> Data Studio or <strong>IBM</strong> WebSphere® Application Server have<br />

specific location and configuration files for the JDBC drivers. Always refer to each<br />

individual documentation for setup details.<br />

You can find additional information regarding the configuration of the<br />

CLASSPATH environment variable in refer to 2.2.3, “Setting up <strong>IBM</strong> Data Server<br />

drivers” on page 43 and 2.2.4, “Setting up <strong>Informix</strong> JDBC” on page 53.<br />

5.2.2 Verify connectivity with <strong>Informix</strong> JDBC Driver<br />

In this section, we demonstrate how to verify a correct setup and configuration of<br />

the <strong>Informix</strong> JDBC Driver.<br />

To load <strong>IBM</strong> <strong>Informix</strong> JDBC Driver, the application can use the following<br />

Class.forName() Java method, passing the name of the <strong>Informix</strong> JDBC Driver as<br />

argument:<br />

Class.forName("com.informix.jdbc.IfxDriver");<br />

Example 5-5 contains a basic Java program that can be used to verify the<br />

connectivity with the <strong>Informix</strong> JDBC Driver. The connection string uses the<br />

following parameters:<br />

► The <strong>IBM</strong> <strong>Informix</strong> JDBC Driver identifier, jdbc:informix-sqli<br />

► The database server host name, kefka.lenexa.ibm.com<br />

You can also specify the IP address.<br />

► The port number of the SQLI listener of the <strong>Informix</strong> server, 9088<br />

► The database name, stores_demo<br />

► <strong>Informix</strong> instance identified by the INFORMIXSERVER variable<br />

► User and password for connecting to the database server<br />

158 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Example 5-5 SimpleConnection.java<br />

import java.sql.*;<br />

public class SimpleConnection {<br />

public static void main(String[] args) {<br />

String url =<br />

"jdbc:informix-sqli://kefka.lenexa.ibm.com:9088/stores_demo:INFORMIXSERVER=demo<br />

_on;user=informix;password=Ifmx4you";<br />

Connection conn = null;<br />

System.out.println("URL = \"" + url + "\"");<br />

try {<br />

Class.forName("com.informix.jdbc.IfxDriver");<br />

} catch (Exception e) {<br />

System.out.println("FAILED: failed to load <strong>Informix</strong> JDBC driver.");<br />

}<br />

try {<br />

conn = DriverManager.getConnection(url);<br />

} catch (SQLException e) {<br />

System.out.println("FAILED: failed to connect!");<br />

}<br />

try {<br />

System.out.println("Connected ...");<br />

DatabaseMetaData md = conn.getMetaData();<br />

System.out.println("Driver name: " + md.getDriverName());<br />

System.out.println("Driver version: " + md.getDriverVersion());<br />

System.out.println("Database product name: "<br />

+ md.getDatabaseProductName());<br />

System.out.println("Database product version: "<br />

+ md.getDatabaseProductVersion());<br />

} catch (SQLException e) {<br />

System.out.println("FAILED: failed to connect!");<br />

}<br />

try {<br />

conn.close();<br />

} catch (SQLException e) {<br />

System.out.println("FAILED: failed to close the connection!");<br />

}<br />

System.out.println("Done!");<br />

}<br />

}<br />

Chapter 5. Working with the JDBC drivers 159


Example 5-6 shows the compile line and output of the SimpleConnect.java<br />

program.<br />

Example 5-6 Running SimpleConnection.java<br />

C:\RedBook>javac SimpleConnection.java<br />

C:\RedBook>java SimpleConnection<br />

URL =<br />

"jdbc:informix-sqli://kefka:9088/stores_demo:INFORMIXSERVER=demo_on;user=i<br />

nformix;password=Ifmx4you"<br />

Connected ...<br />

Driver name: <strong>IBM</strong> <strong>Informix</strong> JDBC Driver for <strong>IBM</strong> <strong>Informix</strong> Dynamic Server<br />

Driver version: 3.50.JC6W1<br />

Database product name: <strong>Informix</strong> Dynamic Server<br />

Database product version: 11.50.FC7<br />

Done!<br />

5.2.3 Verify connectivity with the Data Server Driver<br />

You can use the same Java program (Example 5-5 on page 159) to verify the<br />

connection with the Data Server Driver for JDBC with minor changes. The<br />

following changes are required:<br />

► Load the Data Server JDBC Driver class using the Class.forName() method:<br />

Class.forName("com.ibm.db2.jcc.DB2Driver");<br />

► The name of the Data Server JDBC Driver in the connection string should be<br />

jdbc:ids.<br />

► The port number to use the Data Server Driver client is different from the<br />

<strong>Informix</strong> JDBC client. A common mistake is to specify the SQLI port in the<br />

URL that leads to an error such as the following error:<br />

com.ibm.db2.jcc.am.io: [jcc][t4][2030][11211][3.58.82] A communication<br />

error occurred during operations on the connection's underlying socket,<br />

socket input stream,or socket output stream. Error location: Reply.fill().<br />

Message: Insufficient data. ERRORCODE=-4499, SQLSTATE=08001<br />

at com.ibm.db2.jcc.am.ed.a(ed.java:319)<br />

at com.ibm.db2.jcc.t4.a.a(a.java:416)<br />

160 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Example 5-7 shows the changes to the SimpleConnection.java source code.<br />

You do not need to specify the INFORMIXSERVER variable when using the <strong>IBM</strong><br />

Data Server Driver for JDBC.<br />

Example 5-7 SimpleConnection.java with Data Server JDBC Driver<br />

...<br />

Class.forName("com.ibm.db2.jcc.DB2Driver");<br />

} catch (ClassNotFoundException cnfe) {<br />

System.out.println("No such class available.");<br />

return;<br />

}<br />

try {<br />

con = DriverManager<br />

.getConnection("jdbc:ids://kefka:9089/stores_demo",<br />

"informix", "Ifmx4you");<br />

System.out.println("connected");<br />

...<br />

Example 5-8 shows how to compile and run the program. Notice that the<br />

metadata information that the JDBC driver retrieves is slightly different from the<br />

metadata retrieved with <strong>IBM</strong> <strong>Informix</strong> JDBC Driver.<br />

Example 5-8 Output of SimpleConnection.java using the Data Server JDBC Driver<br />

C:\RedBook>javac SimpleConnection.java<br />

C:\RedBook>java SimpleConnection<br />

connected<br />

Driver name: <strong>IBM</strong> DB2 JDBC Universal Driver Architecture<br />

Driver version: 3.58.82<br />

Database product name: IDS/UNIX64<br />

Database product version: IFX11500<br />

connected<br />

Done<br />

5.3 JDBC type mapping<br />

Mapping is a way of specifying data type equivalents. Because there are<br />

variations between the SQL data types that are supported by each database<br />

vendor, the JDBC API defines a set of generic SQL data types that to use on the<br />

Java application. In addition to these data types, which are defined by the JDBC<br />

driver, the Java language itself has its own data types that might differ from the<br />

SQL types that the database vendor uses. When writing a Java application, the<br />

Chapter 5. Working with the JDBC drivers 161


programmer uses Java data types to manipulate the data. The application<br />

developers needs to understand the equivalent data type in JDBC and the<br />

equivalent data types on the database server.<br />

Table 5-1 lists a few of the data type mapping that is required when working with<br />

an <strong>IBM</strong> <strong>Informix</strong> database as examples.<br />

Table 5-1 Data Type Mapping from JDBC to <strong>Informix</strong> basic data types<br />

Java Type JDBC Type <strong>Informix</strong> Type<br />

long BIGINT INT8, BIGINT, BIGSERIAL<br />

byte[] BINARY, VARBINARY BYTE<br />

boolean BIT BOOLEAN<br />

java.sql.Date DATE DATE<br />

java.math.BigDecimal DECIMAL DECIMAL<br />

byte[] LONGVARBINARY BYTE or BLOB<br />

java.lang.String LONGVARCHAR TEXT or CLOB<br />

java.math.BigDecimal NUMERIC MONEY<br />

float, java.lang.Float REAL SMALLFLOAT<br />

java.sql.Time TIME DATETIME HOUR TO<br />

SECOND<br />

java.sql.Timestamp TIMESTAMP DATETIME YEAR TO<br />

FRACTION(5)<br />

For the complete list of data type mappings between the <strong>Informix</strong> SQL data types<br />

and the <strong>Informix</strong> JDBC Driver, refer to the JDBC Driver Programmer’s Guide at:<br />

http://publib.boulder.ibm.com/infocenter/idshelp/v115/topic/com.ibm.jdbc_pg.doc<br />

/sii-xc-21122.htm#sii-xc-21122<br />

For more information regarding the data types that the <strong>IBM</strong> Data Server Driver for<br />

JDBC and SQLJ use, refer to:<br />

http://publib.boulder.ibm.com/infocenter/idshelp/v115/topic/com.ibm.jccids.doc/<br />

com.ibm.db2.luw.apdv.java.doc/doc/rjvjdata.htm<br />

162 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


5.4 Performing database operations<br />

In this section, we provide examples of how to use <strong>IBM</strong> <strong>Informix</strong> JDBC Driver and<br />

<strong>IBM</strong> Data Server Driver for JDBC for typical database operations, such as<br />

connection to the <strong>Informix</strong> database, and to manipulate data.<br />

5.4.1 Connection to the database<br />

A Java application can obtain a connection with an <strong>Informix</strong> database using one<br />

of the following methods:<br />

► Use the DriverManager class. This method involves loading the JDBC driver<br />

using the Class.forName() method and obtaining a connection by calling the<br />

getConnection() method:<br />

Class.forName("com.ibm.db2.jcc.DB2Driver");<br />

con = DriverManager.getConnection("jdbc:ids://...");<br />

► Use a DataSource object through the javax.sql extensions.<br />

DB2ConnectionPoolDataSource ds = new DB2ConnectionPoolDataSource();<br />

PooledConnection poolconn = ds.getPooledConnection();<br />

con = poolconn.getConnection();<br />

The DriverManager class was implemented in the original JDBC 1.0 API. This<br />

class provides direct access to all the JDBC driver features; however, it requires<br />

the application to load the JDBC driver manually and to use a hard-coded<br />

connection string with the connection details.<br />

The DataSource interface was introduced in the JDBC 2.0 API as the preferred<br />

method to obtain a JDBC connection. The application has no need to load a<br />

JDBC driver class or provide hard-coded connection details. The interface needs<br />

to know only the name of the DataSource object that it wants to use. The details<br />

for the database connection are stored within the DataSource object definition<br />

outside the application code.<br />

Connecting using the DriverManager<br />

When using the DriverManager class to connect to an <strong>IBM</strong> <strong>Informix</strong> database, a<br />

connection string must be passed to the getConnection() method with the<br />

details for the database server. These details include information such as the<br />

system where the database server is running and the port number needed for the<br />

connection.<br />

Chapter 5. Working with the JDBC drivers 163


Example 5-9 shows the syntax of the connection string used with <strong>Informix</strong> JDBC<br />

Driver and <strong>IBM</strong> Data Server Driver for JDBC.<br />

Example 5-9 DriverManager connection string syntax<br />

jdbc:[jdbc-driver]://[{ip-address|host-name}:{port-number|service-name}][/dbnam<br />

e]:INFORMIXSERVER=servername[{;user=user;password=password]<br />

Connecting to an <strong>Informix</strong> database uses the following parameters:<br />

► jdbc-driver<br />

This parameter identifies a particular JDBC driver. <strong>Informix</strong> JDBC Driver uses<br />

informix-sqli. <strong>IBM</strong> Data Server Driver for JDBC uses ids or db2.<br />

► ip-address or host-name<br />

This parameter specifies the system that is running the database server.<br />

► port-number|service-name<br />

This parameter specifies the communication port that the database server<br />

uses.<br />

► dbname<br />

This parameter names the database to open after a successful connection<br />

with the server.<br />

► INFORMIXSERVER<br />

This parameter identifies the name of the <strong>Informix</strong> database server to which<br />

to connect. This parameter is not required when using Data Server JDBC<br />

Driver.<br />

► User and password<br />

These parameters provide the authentication credentials for the connection.<br />

In addition to these standard details, which are common to all JDBC drivers, the<br />

connection string is also used to specify properties that are relevant only to a<br />

specific JDBC driver or database server. Table 5-2 lists some of the properties<br />

specific to <strong>Informix</strong> JDBC Driver.<br />

Table 5-2 <strong>Informix</strong> JDBC Driver connection string<br />

Parameter Description<br />

DB_LOCALE Locale of the database in the database server.<br />

CLIENT_LOCALE Locale used by the Client application<br />

INFORMIXCONTIME Time-out value for a connection with the server<br />

SQLIDEBUG Enable the trace of the SQLI protocol<br />

164 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Parameter Description<br />

STMT_CACHE Enables SQL statement cache on the server<br />

IFX_ISOLATION_LEVEL Specify the default Isolation Level for the session<br />

<strong>IBM</strong> Data Server Driver for JDBC supports most of the <strong>Informix</strong> JDBC Driver<br />

properties. For a complete list of the properties that are supported when<br />

connecting to an <strong>Informix</strong> database server, refer to:<br />

http://publib.boulder.ibm.com/infocenter/idshelp/v115/index.jsp?topic=/com.ibm.<br />

jdbc_pg.doc/sii-02conect-66368.htm<br />

Example 5-10 shows how to compile a basic Java code that connects to the<br />

<strong>Informix</strong> database. The driver name and connection string are passed as<br />

parameters for the program.<br />

Example 5-10 A connect.java file<br />

C:\work>set CLASSPATH=ifxjdbc.jar:db2jcc.jar:.<br />

C:\work>type connect.java<br />

import java.sql.*;<br />

public class connect{<br />

public static void main( String [] args ) {<br />

Connection conn = null;<br />

Statement is = null;<br />

if (args.lengthjavac connect.java<br />

C:\work>java connect "com.informix.jdbc.IfxDriver"<br />

"jdbc:informix-sqli://kodiak:9088/stores_demo:INFORMIXSERVER=demo_on;<br />

Chapter 5. Working with the JDBC drivers 165


"<br />

Connected to <strong>Informix</strong> Dynamic Server<br />

C:\work>java connect "com.ibm.db2.jcc.DB2Driver"<br />

"jdbc:ids://kodiak:9089/stores_demo:user=informix;password=password";<br />

Connected to IDS/NT64<br />

C:\work><br />

Connecting using the DataSource object extensions<br />

When using a DataSource object, the information for the database connection is<br />

stored as properties of the DataSource object. These properties are usually<br />

stored in a Java Naming and Directory Interface (JNDI) service that is managed<br />

by the Java runtime or the application server.<br />

The application requires no knowledge about the specific connection details. It<br />

makes use of the DataSource object to get a connection with the database<br />

server.<br />

In addition to the method implemented by the JDBC driver to set standard<br />

properties, both <strong>Informix</strong> JDBC Driver and Data Server Driver for JDBC provide<br />

extra methods to set and retrieve properties that are specific to the <strong>Informix</strong><br />

database. These properties have the same effect on the database session as the<br />

<strong>Informix</strong> environment variables that are used by other <strong>Informix</strong> APIs, such as<br />

ODBC or .NET.<br />

Example 5-11 shows a DataSource object that is created using the <strong>Informix</strong><br />

JDBC Driver and how to set some of the DataSource object properties.<br />

Example 5-11 DataSource object sample<br />

IfxDataSource ds = new IfxDataSource();<br />

ds.setServerName("demo_on");<br />

ds.setDatabaseName("stores_demo");<br />

ds.setPortNumber(9089);<br />

ds.setIfxIFXHOST("kodiak");<br />

ds.setIfxCLIENT_LOCALE("en_US.CP1252");<br />

ds.getConnection("informix", "password");<br />

166 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


You can use these <strong>Informix</strong> specific properties to modify the behavior of the<br />

JDBC driver or to control particular features of the database server. Table 5-3<br />

lists a portion of the DataSource object properties that are implemented in the<br />

<strong>Informix</strong> JDBC Driver.<br />

Table 5-3 DataSource object properties<br />

<strong>Informix</strong> variable Method<br />

CLIENT_LOCALE public String getIfxCLIENT_LOCALE()<br />

public void setIfxCLIENT_LOCALE()<br />

DB_LOCALE public String getIfxDB_LOCALE()<br />

public void setIfxDB_LOCALE()<br />

IFX_ISOLATION_LEVEL public String getIfxIFX_ISOLATION_LEVEL()<br />

public void setIfxIFX_ISOLATION_LEVEL (l)<br />

IFX_LOCK_MODE_WAIT public int getIfxIFX_LOCK_MODE_WAIT()<br />

public void setIfxIFX_LOCK_MODE_WAIT ()<br />

SQLIDEBUG public String getIfxSQLIDEBUG ()<br />

public void setIfxSQLIDEBUG ()<br />

STMT_CACHE public String getIfxSTMT_CACHE()<br />

public void setIfxSTMT_CACHE()<br />

USEV5SERVER public boolean isIfxUSEV5SERVER()<br />

public void setIfxUSEV5SERVER()<br />

For a complete list of all the available properties, refer to:<br />

http://publib.boulder.ibm.com/infocenter/idshelp/v115/index.jsp?topic=/com.ibm.<br />

jdbc_pg.doc/sii-xb-13590.htm<br />

Because <strong>IBM</strong> Data Server Driver for JDBC supports both <strong>Informix</strong> and DB2<br />

database servers, the DataSource object properties that it provides are different<br />

from those provided by <strong>Informix</strong> JDBC Driver. For a complete list, refer to:<br />

http://publib.boulder.ibm.com/infocenter/idshelp/v115/index.jsp?topic=/com.ibm.<br />

jccids.doc/com.ibm.db2.luw.apdv.java.doc/doc/rjvdsprp.htm<br />

Chapter 5. Working with the JDBC drivers 167


5.4.2 Manipulating data<br />

In this section, we provide basic examples of how to perform typical data<br />

manipulation tasks using a JDBC driver with an <strong>IBM</strong> <strong>Informix</strong> database.<br />

Simple SQL statements<br />

A Java application can use a Statement object to run basic SQL statements<br />

against the database server. The Statement interface provides two methods:<br />

► executeQuery() returns a ResultSet value<br />

Use this method to run SQL statements that return data (for example, a<br />

SELECT SQL statement).<br />

► executeUpdate() returns the number of rows effected by the SQL statement<br />

Use this method to perform INSERT, DELETE, and UPDATE operations or to<br />

run Data Definition Language (DDL) statements.<br />

Example 5-12 demonstrates how to perform a DELETE statement using the<br />

executeUpdate() method.<br />

Example 5-12 An executeUpdate sample<br />

C:\work>type delete.java<br />

import java.sql.*;<br />

public class delete{<br />

public static void main( String [] args ) {<br />

Connection conn = null;<br />

Statement is = null;<br />

try {<br />

Class.forName("com.informix.jdbc.IfxDriver");<br />

conn =<br />

DriverManager.getConnection("jdbc:informix-sqli://kodiak:9088/stores_demo:INFOR<br />

MIXSERVER=demo_on");<br />

168 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong><br />

is = conn.createStatement();<br />

int rc=is.executeUpdate("DELETE FROM state WHERE code='"+args[0]+"'");<br />

System.out.format("Deleted %d rows",rc);<br />

conn.close();<br />

}<br />

catch ( Exception e ) {<br />

System.err.println(e);<br />

}<br />

}


}<br />

C:\work><br />

C:\work>java delete AZ<br />

Deleted 1 rows<br />

C:\work><br />

Prepare SQL statement with parameters<br />

You can use the PreparedStatement object to run the prepared SQL statement<br />

against the database server. Use the PreparedStatement object when the<br />

application uses an SQL statement repeatedly. The application can run the SQL<br />

statement multiple times with different values, which saves the time that the<br />

application takes to process and optimize an SQL statement.<br />

Example 5-13 demonstrates how to use a PreparedStatement object. The<br />

example inserts a row in the state table using the parameters that are supplied<br />

through the command line.<br />

Example 5-13 An insert.java sample<br />

C:\work>cat insert.java<br />

import java.sql.*;<br />

import java.util.*;<br />

import java.text.*;<br />

public class insert{<br />

public static void main( String [] args ) {<br />

Connection conn = null;<br />

try {<br />

Class.forName("com.informix.jdbc.IfxDriver");<br />

conn =<br />

DriverManager.getConnection("jdbc:informix-sqli://kodiak:9088/stores_demo:INFOR<br />

MIXSERVER=demo_on");<br />

PreparedStatement pstmt=conn.prepareStatement("INSERT INTO state<br />

VALUES(?,?,?)");<br />

pstmt.setString(1, args[0]);<br />

pstmt.setString(2, args[1]);<br />

pstmt.setString(3, args[2]);<br />

int rc=pstmt.executeUpdate();<br />

System.out.format("Inserted %d rows",rc);<br />

Chapter 5. Working with the JDBC drivers 169


conn.close();<br />

}<br />

catch ( Exception e ) {<br />

System.err.println(e);<br />

}<br />

}<br />

}<br />

C:\work>java insert AZ Arizona 0<br />

Inserted 1 rows<br />

C:\work><br />

Retrieve data from a database table<br />

To retrieve data from a database table or a function that returns more than one<br />

row, a JDBC application must use the ResultSet object. When the<br />

executeQuery() method from the Statement or PreparedStatement object is call,<br />

the data is returned in the form of a ResultSet object. This object allows the<br />

fetching of rows from the database.<br />

Example 5-14 demonstrates how to run an SQL SELECT statement to retrieve<br />

data using the PreparedStatement and ResultSet objects. The result of the<br />

prepare statement is stored in the ResultSet object, dbRes. After that, the<br />

dbRes.next() method is used to scroll through the ResultSet data.<br />

Example 5-14 A select.java sample<br />

C:\work>cat select.java<br />

import java.sql.*;<br />

public class select {<br />

public static void main( String [] args ) {<br />

Connection conn = null;<br />

ResultSet dbRes = null;<br />

Statement is = null;<br />

try {<br />

Class.forName("com.informix.jdbc.IfxDriver");<br />

conn =<br />

DriverManager.getConnection("jdbc:informix-sqli://kodiak:9088/stores_demo:INFOR<br />

MIXSERVER=demo_on;’);<br />

PreparedStatement pstmt=conn.prepareStatement("SELECT * FROM state where<br />

code


dbRes = pstmt.getResultSet();<br />

while (dbRes.next()) {<br />

System.out.format("%s,",dbRes.getString(1));<br />

System.out.format("%s,",dbRes.getString(2));<br />

System.out.format("%f\n",dbRes.getDouble(3));<br />

}<br />

dbRes.close();<br />

conn.close();<br />

}<br />

catch ( Exception e ) {<br />

System.err.println(e);<br />

}<br />

}<br />

}<br />

C:\work>java select CA<br />

AL,Alabama ,0.040000<br />

AR,Arizona ,0.000000<br />

AZ,Arizona ,0.055000<br />

C:\work><br />

Transactions<br />

Local transaction are controlled directly with the connection object. Methods<br />

such as Connection.commit() and Connection.rollback() are used to resolved<br />

a transaction.<br />

By default, all the connections that are created by the <strong>Informix</strong> JDBC Driver<br />

Connection object are in AutoCommit mode. Thus, every SQL statement sent to<br />

the <strong>Informix</strong> database server is committed automatically. If control over the<br />

transaction is required, you can turn off the AutoCommit mode using the<br />

Connection.setAutoCommit() method.<br />

When using <strong>Informix</strong> JDBC Driver in an XA environment (XA is a standard<br />

specification for distributed transactions), the AutoCommit feature is always<br />

disabled. The transaction manager is the only component that has control over<br />

the transaction.<br />

Chapter 5. Working with the JDBC drivers 171


Example 5-15 demonstrates how to disable AutoCommit mode using the<br />

setAutoCommit(false) method.<br />

Example 5-15 A sample localtrans.java file<br />

C:\work>cat localtrans.java<br />

import java.sql.*;<br />

import java.util.*;<br />

import java.text.*;<br />

public class localtrans{<br />

public static void main( String [] args ) {<br />

Connection conn = null;<br />

Statement is = null;<br />

try {<br />

Class.forName("com.informix.jdbc.IfxDriver");<br />

conn =<br />

DriverManager.getConnection("jdbc:informix-sqli://kodiak:9088/stores_demo:INFOR<br />

MIXSERVER=demo_on");<br />

conn.setAutoCommit(false);<br />

172 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong><br />

is = conn.createStatement();<br />

int rc = is.executeUpdate("DELETE FROM state WHERE code='UK'");<br />

System.out.format("Deleted %d rows\n",rc);<br />

System.out.format("Aborting transaction\n");<br />

conn.rollback();<br />

conn.close();<br />

}<br />

catch ( Exception e ) {<br />

e.printStackTrace();<br />

}<br />

}<br />

}<br />

C:\work>java localtrans<br />

Deleted 1 rows<br />

Aborting transaction<br />

C:\work>


Run a user-defined routine<br />

The CallableStatement object provides a way to run a user-defined routine<br />

(UDR) using a standard method that is common to all the <strong>IBM</strong> database servers.<br />

The results from the execution of a UDR is returned as a result set or as an OUT<br />

parameter. Use the following SQL syntax to call a UDR using the<br />

CallableStatement interface:<br />

"{? = call function_name (?, ?,...)}";<br />

The placeholders identify the IN, OUT, and INOUT parameters for the UDR.<br />

The application can set and retrieve the value for the routine parameters using<br />

the registerOutParameter() and getxxx() methods.<br />

Example 5-16 shows a basic UDR that is defined with two OUT parameters.<br />

Example 5-16 A state_tax SQL routine<br />

CREATE FUNCTION state_tax(OUT vtax percent,<br />

vcode CHAR(2),<br />

OUT vsname CHAR(20))<br />

RETURNS BOOLEAN;<br />

SELECT sales_tax,upper(sname)<br />

INTO vtax, vsname FROM state<br />

WHERE code=vcode;<br />

RETURN 't';<br />

END FUNCTION;<br />

We use CallableStatement to invoke this UDR from a JDBC application.<br />

Example 5-17 demonstrates how to set the IN and OUT for the UDR. The<br />

BOOLEAN value is returned directly by the SQL function and retrieved using a<br />

ResultSet object. To retrieve the OUT parameters, the example uses the<br />

getDouble() and GetString() methods.<br />

Example 5-17 A callable.java sample file<br />

C:\work>cat callable.java<br />

import java.sql.*;<br />

public class callable {<br />

public static void main( String [] args ) {<br />

Connection conn = null;<br />

try {<br />

Class.forName("com.informix.jdbc.IfxDriver");<br />

Chapter 5. Working with the JDBC drivers 173


conn =<br />

DriverManager.getConnection("jdbc:informix-sqli://kodiak:9088/stores_demo:INFOR<br />

MIXSERVER=demo_on;");<br />

CallableStatement cstmt = conn.prepareCall ("{? = call state_tax(?, ?,<br />

?)}");<br />

cstmt.registerOutParameter(1, Types.DOUBLE);<br />

cstmt.registerOutParameter(3, Types.CHAR);<br />

cstmt.setString(2, "CA");<br />

ResultSet dbRes = cstmt.executeQuery();<br />

// Retrieve OUT parameters from the function<br />

while (dbRes.next())<br />

System.out.format("UDR returns = %s\n", dbRes.getBoolean(1));<br />

// Retrieve OUT parameters from the function<br />

System.out.format("OUT tax %s\n",cstmt.getDouble(1));<br />

System.out.format("OUT sname %s\n",cstmt.getString(3));<br />

dbRes.close();<br />

cstmt.close();<br />

conn.close();<br />

}<br />

catch ( Exception e ) {<br />

System.err.println(e);<br />

}<br />

}<br />

}<br />

C:\work>java callable<br />

UDR returns = true<br />

OUT tax 0.0825<br />

OUT sname CALIFORNIA<br />

C:\work><br />

5.5 <strong>Informix</strong> additional features<br />

This section demonstrates the use of the following additional <strong>IBM</strong> <strong>Informix</strong><br />

features:<br />

► Batch inserts or updates and using ResultSet metadata<br />

► BIGSERIAL data type<br />

► <strong>Informix</strong> smart large objects<br />

► Secure Socket Layer<br />

174 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


5.5.1 Batch inserts or updates and using ResultSet metadata<br />

In this section, we demonstrate the following concepts:<br />

► Batch inserts<br />

When performing multiple inserts (or updates) using a prepared statement, it<br />

is more efficient to do all the inserts in bulk. The method adds all the inserts in<br />

a batch and then runs the batch.<br />

► Using ResultSet metadata<br />

When you run a query from a Java program that generates a result set, there<br />

is additional information available that is separate from the result set itself.<br />

This additional information about the data is returned by the ResultSet<br />

metadata. For example, you might use ResultSet metadata to obtain table<br />

definition information from one database to another database. You can<br />

dynamically obtain all the details about each column that returns data.<br />

Example 5-18 shows the batch insert and how to obtain the column name and<br />

column type from the ResultSet metadata. The schema for the gentemp table is<br />

as follows:<br />

CREATE TABLE gentemp (id INT, name VARCHAR(15) NOT NULL)<br />

We use the con.prepareStatement() method to prepare the SQL INSERT<br />

statement. Then, we execute the statement using the pstmt.addBatch() method,<br />

which makes the INSERT statement a part of a batch operation. After adding 10<br />

rows to the table, we execute the batch operation using the<br />

pstmt.executeBatch() method.<br />

The metadata information for the table is retrieved using the rs.getMetaData()<br />

method.<br />

Example 5-18 Listing for the IfxBatchDemo.java file<br />

import java.sql.*;<br />

import java.io.*;<br />

public class IfxBatchDemo {<br />

public static void main(String args[]) throws SQLException, IOException,Exception {<br />

String IfxURL =<br />

"jdbc:informix-sqli://kodiak:9088/stores_demo:INFORMIXSERVER=demo_on";<br />

Connection con = null;<br />

int cnt = 0;<br />

System.out.println("Start");<br />

Class.forName("com.informix.jdbc.IfxDriver");<br />

con = DriverManager.getConnection(IfxURL);<br />

Chapter 5. Working with the JDBC drivers 175


con.setAutoCommit(false);<br />

Statement stmt = null;<br />

PreparedStatement pstmt = null;<br />

ResultSet rs = null;<br />

ResultSetMetaData rsmd = null;<br />

pstmt = con.prepareStatement("INSERT INTO gentemp (id,name) VALUES (?,?)");<br />

// Fill in 10 rows<br />

for (int i = 0; i < 10; i++) {<br />

pstmt.setInt(1, i + 1000);<br />

pstmt.setString(2, "String #" + i);<br />

pstmt.addBatch();<br />

}<br />

int[] rows = pstmt.executeBatch();<br />

System.out.println(" Inserted data. Rows = " + rows.length);<br />

con.commit();<br />

pstmt.close();<br />

pstmt = con.prepareStatement("SELECT * FROM gentemp");<br />

rs = pstmt.executeQuery();<br />

rsmd = rs.getMetaData();<br />

System.out.println(" " + "Col Names " + rsmd.getColumnName(1) + ","<br />

+ rsmd.getColumnName(2));<br />

System.out.println(" " + "Col Types " + rsmd.getColumnTypeName(1)<br />

+ "," + rsmd.getColumnTypeName(2));<br />

int row = 1;<br />

while (rs.next()) {<br />

System.out.println(" Row " + row + " = "<br />

+ rs.getInt(rsmd.getColumnName(1)) + ","<br />

+ rs.getString(rsmd.getColumnName(2)));<br />

row++;<br />

}<br />

pstmt.close();<br />

con.commit();<br />

con.close();<br />

}<br />

}<br />

176 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


5.5.2 BIGSERIAL data type<br />

<strong>IBM</strong> <strong>Informix</strong> version 11.50 implements the ANSI standard SQL data type<br />

BIGINT and the BIGSERIAL data types:<br />

► BIGINT is mapped to the JDBC standard BIGINT data type. It can be used<br />

from a Java application as any other <strong>Informix</strong> data type.<br />

► BIGSERIAL (similar to SERIAL and SERIAL8) does not have an obvious<br />

mapping to any JDBC data type. Thus, the application must use<br />

<strong>Informix</strong>-specific JDBC methods to retrieve the value of these columns.<br />

The methods to access <strong>Informix</strong> serial data types are included in the <strong>Informix</strong><br />

JDBC implementation of the JAVA java.sql.Statement interface, IfxStatement.<br />

You can use the getSerial(), getSerial8(), and getBigSerial() methods to<br />

retrieve the last value that was inserted on a serial column.<br />

Example 5-19 shows how to retrieve a BIGSERIAL value using the<br />

IfxStatement.getBigSerial() method. The example uses the following schema<br />

for the table:<br />

CREATE TABLE tempbs(id BIGSERIAL, name CHAR(10));<br />

Example 5-19 The bigserial.java sample<br />

import java.sql.*;<br />

import com.informix.jdbc.*;<br />

public class bigserial {<br />

public static void main( String [] args ) {<br />

Connection conn = null;<br />

ResultSet dbRes = null;<br />

long insertedserial = 0;<br />

String<br />

url="jdbc:informix-sqli://kodiak:9088/stores_demo:INFORMIXSERVER=demo_on;";<br />

try {<br />

Class.forName("com.informix.jdbc.IfxDriver");<br />

conn = DriverManager.getConnection(url);<br />

IfxStatement stmt= (IfxStatement) conn.createStatement();<br />

stmt.executeUpdate("INSERT INTO tempbs VALUES (0,'test');");<br />

insertedserial =stmt.getBigSerial();<br />

System.out.println("Last serial: \t"+insertedserial);<br />

stmt.executeQuery("SELECT FIRST 1 * FROM tempbs ORDER BY rowid DESC");<br />

dbRes = stmt.getResultSet();<br />

while (dbRes.next()) {<br />

Chapter 5. Working with the JDBC drivers 177


System.out.format("Last row: \t%d,",dbRes.getLong(1));<br />

System.out.format("%s\n",dbRes.getString(2));<br />

}<br />

dbRes.close();<br />

conn.close();<br />

}<br />

catch ( Exception e ) {<br />

System.err.println(e);<br />

}<br />

}<br />

}<br />

Example 5-19 on page 177 inserts a row in the tempbs table and stores the last<br />

BIGSERIAL value in the insertedSerial variable. Example 5-20 shows how to<br />

compile the example and its output.<br />

Example 5-20 The output of the bigserial.java file<br />

C:\work>javac bigserial.java<br />

C:\work>java bigserial<br />

Last serial: 14<br />

Last row: 14,test<br />

C:\work><br />

5.5.3 <strong>Informix</strong> smart large objects<br />

Smart large objects are a type of large object that <strong>Informix</strong> supports. Smart large<br />

objects are stored logically in a table column but stored physically in a specific<br />

type of dbspace called smart blob space.<br />

The data that is stored in the table column is a structure that contains information<br />

about the large object, such as special attributes or pointers to the location in the<br />

smart blob space that contains the data. <strong>Informix</strong> has the following types of smart<br />

large objects:<br />

► A BLOB stores binary data.<br />

► A CLOB stores character data.<br />

178 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


You can manipulate smart large objects with the <strong>Informix</strong> JDBC Driver using the<br />

following methods:<br />

► Standard JDBC 3.0 API<br />

Using standard JDBC methods such as getString(), setAsciiStream(), or<br />

getBinaryStream() allows an application to handle smart lager objects as<br />

standard Java data types.<br />

► <strong>Informix</strong> smart-large-object extensions<br />

If an application requires random access to the large data, it must use<br />

<strong>Informix</strong> smart-large-object extensions. These extensions to the JDBC API<br />

give the application greater control over the smart-large-object data in terms<br />

of object properties, concurrency access, and logging.<br />

The IfxSmartBlob interface implements most of the smart-large-object<br />

extensions, methods such as IfxLoCreate(), IfxLoOpen(), IfxLoRead(), and<br />

IfxLoWrite() can be used to access the smart large object structures and to<br />

manipulate the data of the object.<br />

For a complete description of all the <strong>Informix</strong> smart-large-objects extensions,<br />

refer to the JDBC Driver Programmer’s Guide, which is available at:<br />

http://publib.boulder.ibm.com/infocenter/idshelp/v115/index.jsp?topic=/com.<br />

ibm.jdbc_pg.doc/sii-04data-36421.htm<br />

Note: <strong>IBM</strong> Data Server Driver for JDBC does not support the <strong>Informix</strong> smart<br />

large object extensions. Only the standard JDBC API is available to work with<br />

smart large objects.<br />

Using the standard JDBC API<br />

Working with smart large objects using the JDBC API does not require any<br />

specific Java code. Example 5-21 demonstrates how to retrieve a CLOB column<br />

from the <strong>Informix</strong> database using the getString() method.<br />

Example 5-21 The getclob.java sample<br />

C:\work>cat getclob.java<br />

import java.sql.*;<br />

public class getclob {<br />

public static void main( String [] args ) {<br />

Connection conn = null;<br />

ResultSet dbRes = null;<br />

Statement is = null;<br />

try {<br />

Class.forName("com.informix.jdbc.IfxDriver");<br />

conn = DriverManager.getConnection(<br />

"jdbc:informix-sqli://kodiak:9088/stores_demo:INFORMIXSERVER=demo_on;");<br />

Chapter 5. Working with the JDBC drivers 179


PreparedStatement pstmt=conn.prepareStatement("SELECT * FROM catalog WHERE<br />

catalog_num=?");<br />

pstmt.setString(1, args[0]);<br />

pstmt.executeQuery();<br />

dbRes = pstmt.getResultSet();<br />

dbRes.next();<br />

System.out.println("Advert description: "+dbRes.getString("advert_descr"));<br />

dbRes.close();<br />

conn.close();<br />

}<br />

catch ( Exception e ) {<br />

System.err.println(e);<br />

}<br />

}<br />

}<br />

C:\work>javac getclob.java<br />

C:\work>java getclob 10001<br />

Advert description: Brown leather. Specify first baseman's or infield/outfield<br />

style. Specify right- or left-handed.<br />

C:\work><br />

Using the <strong>Informix</strong> extensions<br />

The smart-large-object extensions allows a Java application to have direct<br />

control over the large object structures and data pointers that are used to<br />

describe the large object.<br />

The following interfaces provide the methods that are needed to handle smart<br />

large objects:<br />

► IfxLobDescriptor stores the internal characteristics for a smart large object.<br />

The application must create an IfxLobDescriptor object to insert a new large<br />

object in the database.<br />

► IfxLocator identifies a particular large object. An IfxLocator object can be<br />

created or retrieved from the database to perform any I/O operations with the<br />

large object.<br />

► IfxSmartBlob represents a smart large object within the <strong>Informix</strong> JDBC<br />

Driver. This object provides all the methods that are necessary to create,<br />

open, read, and write to a large object.<br />

► IfxloStat stores statistical information about a smart large object, such as<br />

the size, last access time, last modified time, and last status change.<br />

► IfxBblob and IfxCblob add extended functionality to the standard JDBC 3.0<br />

BLOB and CLOB classes.<br />

180 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Example 5-22 demonstrates how to read data from a smart large object using the<br />

IfxSmartBlob method. The code performs the following steps to select the CLOB<br />

column advert_descr:<br />

1. Stores the advert_descr column as an IfxCblob object using the getClob()<br />

method.<br />

2. Gets the IfxLocator from the IfxCblob object through the<br />

cblob.getLocator() method.<br />

3. Creates an IfxSmartBlob object and uses the IfxLocator to open the smart<br />

large object in smb.IfxLoOpen().<br />

4. Reads the first 200 bytes of the CLOB using the smb.IfxLoRead() method.<br />

5. Closes the large object and releases the IfxLocator.<br />

Example 5-22 The loext.java file<br />

import java.sql.*;<br />

import com.informix.jdbc.*;<br />

public class loext{<br />

public static void main( String [] args ) {<br />

Connection conn = null;<br />

byte[] buffer = new byte[200];<br />

try {<br />

Class.forName("com.informix.jdbc.IfxDriver");<br />

conn = DriverManager.getConnection(<br />

"jdbc:informix-sqli://kodiak:9088/stores_demo:INFORMIXSERVER=demo_on;");<br />

PreparedStatement pstmt=conn.prepareStatement("SELECT * FROM catalog WHERE<br />

catalog_num=?");<br />

pstmt.setString(1, args[0]);<br />

pstmt.executeQuery();<br />

ResultSet dbRes = pstmt.getResultSet();<br />

dbRes.next();<br />

IfxCblob cblob = (IfxCblob) dbRes.getClob("advert_descr");<br />

IfxLocator loPtr = cblob.getLocator();<br />

IfxSmartBlob smb = new IfxSmartBlob(conn);<br />

int loFd = smb.IfxLoOpen(loPtr, smb.LO_RDONLY);<br />

int bytesReaded = smb.IfxLoRead(loFd, buffer, buffer.length);<br />

smb.IfxLoClose(loFd);<br />

smb.IfxLoRelease(loPtr);<br />

System.out.println("Advert description: "+new String(buffer).trim());<br />

dbRes.close();<br />

conn.close();<br />

}<br />

catch ( Exception e ) {<br />

Chapter 5. Working with the JDBC drivers 181


System.err.println(e);<br />

}<br />

}<br />

}<br />

Example 5-23 shows how to compile the loext.java sample and the output of<br />

this sample.<br />

Example 5-23 The output of the loext.java file<br />

C:\work>javac loext.java<br />

C:\work>java loext 10001<br />

Advert description: Brown leather. Specify first baseman's or infield/outfield<br />

style. Specify right- or left-handed.<br />

C:\work><br />

For more information regarding the use of smart large objects with <strong>Informix</strong><br />

JDBC Driver, refer to the JDBC Driver Programer’s Guide, which is available at:<br />

http://publib.boulder.ibm.com/infocenter/idshelp/v115/topic/com.ibm.jdbc_pg.doc<br />

/sii-04data-36421.htm#sii-04data-36421<br />

5.5.4 Secure Socket Layer<br />

In addition to the encrypted communications that are provided by the<br />

Communication Support Module (CSM), the <strong>Informix</strong> database server supports<br />

the use of Secure Socket Layer (SSL) communications for the encryption of the<br />

packages between client and server.<br />

<strong>Informix</strong> JDBC Driver supports only CSM encryptions. You must use <strong>IBM</strong> Data<br />

Server Driver for JDBC to connect to an SSL-enabled <strong>Informix</strong> database server.<br />

Before you can use SSL encryption with an <strong>Informix</strong> database, you must<br />

configure both server and client systems.<br />

182 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Preparing the <strong>Informix</strong> server for SSL<br />

To enable SSL on the <strong>Informix</strong> server, create an <strong>Informix</strong> alias using the drsocssl<br />

protocol.<br />

Example 5-24 enables SSL communications with an <strong>Informix</strong> server.<br />

Example 5-24 SSL configuration on the <strong>Informix</strong> server<br />

$gsk7capicmd -keydb -create -db kodiak.kdb -pw password -type cms -stash<br />

$gsk7capicmd -cert -create -db kodiak.kdb -pw password -label testlabel -dn<br />

"CN=bedfont.uk.ibm.com,O=ibm,C=UK" -size 1024 -default_cert yes<br />

$gsk7capicmd -cert -extract -db kodiak.kdb -format ascii -label testlabel -pw<br />

password -target testlabel.cert<br />

$ pwd<br />

/usr3/11.50/ssl<br />

$ ls -a<br />

. kodiak.crl kodiak.rdb testlabel.cert<br />

.. kodiak.kdb kodiak.sth<br />

$ onstat -c | grep ssl<br />

DBSERVERALIASES kodiak_shm,kodiak_drda,kodiak_ssl<br />

$ grep kodiak_ssl $INFORMIXSQLHOSTS<br />

kodiak_ssl drsocssl kodiak 9191<br />

$<br />

For detailed information regarding the configuration of SSL with an <strong>Informix</strong><br />

server, refer to the Configuring a Server Instance for Secure Sockets Layer<br />

Connections topic in the information center at:<br />

http://publib.boulder.ibm.com/infocenter/idshelp/v115/index.jsp?topic=/com.ibm.<br />

sec.doc/ids_ssl_002.htm<br />

Preparing client for SSL<br />

To enable SSL encryption, both the client and server systems must use the same<br />

certificated file. You can import a certified file into the client system using the<br />

keytool utility, which is included with the Java SDK framework.<br />

Example 5-25 demonstrates how to import the testlabel.cert certificate file<br />

that was created in Example 5-24 on page 183 to enable a trusted relationship<br />

between client and server. A keystore file is created to store the keys for the SSL<br />

encrypted connection.<br />

Example 5-25 SSL Client side configuration<br />

C:\work>keytool -importcert -file testlabel.cert -keystore .keystore<br />

Enter keystore password:<br />

Re-enter new password:<br />

Owner: CN=bedfont.uk.ibm.com, O=ibm, C=UK<br />

Chapter 5. Working with the JDBC drivers 183


Issuer: CN=bedfont.uk.ibm.com, O=ibm, C=UK<br />

Serial number: -14b0e6b89751eab1<br />

Valid from: Thu Jul 15 08:10:31 PDT 2010 until: Sat Jul 16 08:10:31 PDT 2011<br />

Certificate fingerprints:<br />

MD5: 66:FA:CF:44:9F:F3:38:40:7B:9D:93:D6:D6:1C:DB:C5<br />

SHA1: CF:38:6F:CA:C9:A1:54:43:FC:64:AD:F6:DF:5F:CA:65:01:58:DE:DE<br />

Signature algorithm name: SHA1withRSA<br />

Version: 3<br />

Trust this certificate? [no]: yes<br />

Certificate was added to keystore<br />

C:\work>dir .key* /b<br />

.keystore<br />

C:\work><br />

Using a Java client<br />

A Java application can connect to the SSL <strong>Informix</strong> server by performing the<br />

following operations:<br />

► Set the javax.net.ssl.truststore system property to point to the created<br />

keystore (in our example, C:\work\.keystore).<br />

► Set the javax.net.ssl.trustStorePassword System property to the<br />

password that is used for the certificate.<br />

► Get a data source object.<br />

► Set the port number to the SSL port, 9191.<br />

► Set the data source property setSslConnection to true.<br />

Example 5-26 shows basic Java code that connects to an SSL <strong>Informix</strong> server.<br />

Example 5-26 Listing conssl.java<br />

import java.sql.*;<br />

import javax.sql.*;<br />

import java.io.*;<br />

import java.util.*;<br />

import com.ibm.db2.jcc.*;<br />

public class conssl {<br />

public static void main(String args[]) throws SQLException, IOException,<br />

Exception {<br />

System.setProperty ("javax.net.ssl.trustStore","c:/work/.keystore");<br />

System.setProperty ("javax.net.ssl.trustStorePassword","password");<br />

DB2ConnectionPoolDataSource ds = new DB2ConnectionPoolDataSource();<br />

ds.setUser("informix");<br />

184 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


}<br />

}<br />

ds.setPassword("password");<br />

ds.setServerName("kodiak");<br />

ds.setDatabaseName("stores_demo");<br />

ds.setPortNumber(9191);<br />

ds.setDriverType(4);<br />

ds.setSslConnection(true); // SSL<br />

PooledConnection poolconn = ds.getPooledConnection();<br />

Connection con = poolconn.getConnection();<br />

DatabaseMetaData md = con.getMetaData();<br />

System.out.println("Driver name: " + md.getDriverName());<br />

System.out.println("Connected to "+ md.getDatabaseProductName());<br />

System.out.println("Database product version: " +<br />

md.getDatabaseProductVersion());<br />

con.close();<br />

After a successful connection, the code produces metadata information such as<br />

the driver name and database version. Example 5-27 shows the output.<br />

Example 5-27 Output of conssl.java<br />

C:\work>javac conssl.java<br />

C:\work>java conssl<br />

Driver name: <strong>IBM</strong> DB2 JDBC Universal Driver Architecture<br />

Connected to IDS/UNIX32<br />

Database product version: IFX11500<br />

C:\work><br />

5.6 Typical errors<br />

Common issues in Java applications for <strong>Informix</strong> include errors due to an<br />

application development environment without proper configuration and SQL<br />

syntax errors. In this section, we discuss these typical errors.<br />

Chapter 5. Working with the JDBC drivers 185


5.6.1 Class not found errors<br />

The following code shows a class not found error message:<br />

C:\RedBook>java IfxSimpleConnection<br />

Exception in thread "main" java.lang.NoClassDefFoundError:<br />

IfxSimpleConnection<br />

Caused by: java.lang.ClassNotFoundException: IfxSimpleConnection<br />

...<br />

This type of error is usually from either failing to load the JDBC driver or failing to<br />

load the application class because the environment is not configured properly.<br />

To resolve this problem:<br />

► Make sure that you have the JDBC driver .jar files in your CLASSPATH.<br />

► Make sure that you have a “.” (dot) to include your current directory in the<br />

CLASSPATH.<br />

5.6.2 Connectivity errors<br />

When an application fails to connect to the server, you see an error message that<br />

is similar to the following message:<br />

Exception in thread "main" java.sql.SQLException:<br />

com.informix.asf.IfxASFException: Attempt to connect to database server<br />

(demo_on) failed.<br />

at com.informix.jdbc.IfxSqliConnect.(IfxSqliConnect.java:1319)<br />

...<br />

To resolve this problem:<br />

► Verify that the server is running and that the ports are configured correctly on<br />

the server.<br />

► Check the port number specified in the application. Remember, <strong>Informix</strong><br />

JDBC Driver connects to an SQLI port, and <strong>IBM</strong> Data Server driver connects<br />

to a DRDA port.<br />

► Verify that there is no firewall between the client and server. Use Telnet to<br />

connect from the client to the server.<br />

186 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


5.6.3 Syntax errors<br />

5.7 Tracing<br />

The exception with SQLCODE -201 is a syntax error in an SQL statement that<br />

you are trying to run. Other than examining the SQL manually, it can be helpful to<br />

know the location of the SQL about which the server is complaining by obtaining<br />

the SQL statement offset as follows:<br />

try {<br />

stmt.execute( SQL );<br />

}<br />

catch(Exception e) {<br />

System.out.println ("Error Offset :"+((IfmxConnection<br />

conn).getSQLStatementOffset() );<br />

System.out.println(e.getMessage() );<br />

}<br />

Tracing the communication with the <strong>Informix</strong> database server might be required<br />

for further diagnostics. The method that you use to enable tracing depends on<br />

the <strong>Informix</strong> JDBC Driver that you are using.<br />

5.7.1 <strong>IBM</strong> <strong>Informix</strong> JDBC Driver<br />

<strong>Informix</strong> JDBC uses the <strong>Informix</strong> SQLI protocol for the communication with the<br />

database server. A trace file with all the SQLI messages can be generated by<br />

enabling the SQLITRACE feature within the JDBC driver.<br />

Depending on the method used for the connection, the SQLIDEBUG can be<br />

activated using a connection string keyword or a DataSource method:<br />

► Set trace for <strong>Informix</strong> JDBC Driver using DriverManager<br />

DriverManager.getConnection("jdbc:informix-sqli://kodiak:9088/sysmaster:INF<br />

ORMIXSERVER=demo_on;user=;password=;SQLIDEBUG=/tmp/jdbctrace");<br />

► Set trace for <strong>Informix</strong> JDBC Driver using a DataSource object<br />

IfxDataSource ifxds = new IfxDataSource();<br />

ifxds.setIfxSQLIDEBUG("c:/temp/sqli.trc");<br />

You can run the trace through the sqliprint utility to render it to text form.<br />

Chapter 5. Working with the JDBC drivers 187


5.7.2 <strong>IBM</strong> Data Server Driver for JDBC<br />

<strong>IBM</strong> Data Server Driver for JDBC uses DRDA as the network protocol and<br />

produces a DRDA trace, which is a straight text output trace that can be<br />

examined directly.<br />

You can enable DRDA trace with the JDBC using the following methods:<br />

► Set trace for <strong>IBM</strong> Data Server Driver using DriverManager<br />

DriverManager.getConnection("jdbc:ids://kodiak:9089/sysmaster:user=;passwor<br />

d=;traceFile=/jcc.trc;TraceLevel=TRACE_ALL;");<br />

► Set trace for <strong>IBM</strong> Data Server Driver using a DataSource object<br />

DB2SimpleDataSource ds = new DB2SimpleDataSource();<br />

ds.setTraceFile("/jcc.trc");<br />

ds.setTraceLevel(com.ibm.db2.jcc.DB2BaseDataSource.TRACE_ALL);<br />

ds.setTraceFileAppend(false);<br />

Both SQLIDEBUG and DRDADEBUG traces can be activated at the server side<br />

rather than on the client system using the <strong>Informix</strong> onmode utility that is included<br />

with the <strong>Informix</strong> database server. You can find more information about both<br />

traces in “Tracing” on page 117.<br />

188 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Chapter 6. <strong>IBM</strong> <strong>Informix</strong> with Hibernate<br />

This chapter describes how to use the HIbernate Java package with an <strong>IBM</strong><br />

<strong>Informix</strong> database.<br />

It includes the following topics:<br />

► Hibernate for Java<br />

► Setup and configuration<br />

► Using Hibernate with an <strong>Informix</strong> database<br />

6<br />

© Copyright <strong>IBM</strong> Corp. 2010. All rights reserved. 189


6.1 Hibernate for Java<br />

This section describes the concepts of Hibernate and the Java Persistence API<br />

(JPA) programming model.<br />

6.1.1 Overview of Hibernate<br />

Hibernate is an open source Java object-relational mapping (ORM) and<br />

persistence framework that allows you to map Plain Old Java Objects (POJO) to<br />

relational database tables using XML configuration files. Hibernate also provides<br />

a data query language, Hibernate Query Language (HQL), and retrieval facilities<br />

that help reduce development time spent on manual data handling in JDBC calls<br />

or SQL statements.<br />

Persistence data refers to any data that must be stored in the database and that<br />

must exist after the application has stopped running. Hibernate provides a way to<br />

persist the typical relational data as well as Java objects that the application<br />

uses.<br />

A relational database stores the information in a tabular way with tables and<br />

columns. A relational database ensures the integrity of the data using SQL<br />

objects such as constraints and referential integrity.<br />

An object-orientated programming (OOP) language, such as Java or C++, does<br />

not have the same data representation as relational databases. The data is<br />

represented by objects with attributes and methods. The relationship between<br />

these objects is implemented with concepts such as inheritance or polymorphism<br />

that do not exist in a relational database.<br />

ORM technologies such as Hibernate try to solve the limitations of<br />

object-orientated languages when using relational databases. ORM allows<br />

developers to focus on the business logic of the application, without the need for<br />

dealing with the data access layer. A developer needs to load only the customer<br />

object and does not need to care about how the information for that particular<br />

customer is stored in the database. ORM solutions produce more robust and<br />

portable code, which means faster development time.<br />

For more information about Hibernate, refer to:<br />

http://docs.jboss.org/hibernate/stable/core/reference/en/html/<br />

190 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


6.1.2 Hibernate concepts<br />

The Hibernate framework includes the following basic concepts:<br />

► Persistence, in Hibernate terms, refers to the concept of storing the state of a<br />

Java object in the database so that it can be restored later.<br />

► Mapping is the process to map SQL tables to Java objects. Mapping is<br />

accomplished using XML mapping files or using Java annotations (metadata<br />

that is added to the application source) in the Java code.<br />

► Object processing refers to the use of the mapped objects from the<br />

application code. How to save and load the state of an Java object using the<br />

Hibernate API or the specific Hibernate Query Language (HQL).<br />

In a simplified words, Hibernate for Java is a set of Java APIs that allows you to<br />

store and retrieve the state of Java objects into a database using a JDBC driver.<br />

Figure 6-1 illustrates the typical components of a Hibernate application.<br />

Figure 6-1 Hibernate components<br />

Chapter 6. <strong>IBM</strong> <strong>Informix</strong> with Hibernate 191


A Hibernate application includes the following components (as shown in<br />

Figure 6-1):<br />

► Application represents the Java application.<br />

► Java object is the object that the application wants to persist (keep in the<br />

database).<br />

► Hibernate properties is the configuration file for the Hibernate framework,<br />

named hibernate.cfg.xml, that contains information such as the connection<br />

details for the database server or the SQL dialect to use.<br />

► XML Mapping is an XML file that contains the mappings between Java<br />

objects and database objects.<br />

► JDBC is the JDBC driver that is used for the database connection. You can<br />

use both <strong>IBM</strong> <strong>Informix</strong> JDBC Driver and <strong>IBM</strong> Data Server Driver for JDBC with<br />

Hibernate.<br />

► <strong>Informix</strong> database is the <strong>IBM</strong> <strong>Informix</strong> database server.<br />

In addition to the ORM, Hibernate also provides connection management and a<br />

transaction management services to be used with a Java application. We do not<br />

discuss these topics in this section. For information regarding the use and<br />

configuration of the connection and transaction management services, refer to:<br />

http://docs.jboss.org/hibernate/core/3.3/reference/en/html/transactions.html<br />

6.2 Setup and configuration<br />

6.2.1 Installation<br />

This section describes the installation and configuration of Hibernate to be used<br />

with an <strong>IBM</strong> <strong>Informix</strong> database.<br />

Hibernate is an open source project that you can download from:<br />

http://sourceforge.net/projects/hibernate/files<br />

The latest version of Hibernate API is V3.5.3, which fully implements the JPA 2.0.<br />

The compressed package name is<br />

hibernate-distribution-3.5.3-Final-dist.zip.<br />

192 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Example 6-1 shows the contents of the Hibernate compressed package.<br />

Example 6-1 Hibernate distribution content<br />

changelog.txt<br />

documentation<br />

javadocs<br />

manual<br />

hibernate-testing.jar<br />

hibernate3.jar<br />

hibernate_logo.gif<br />

lgpl.txt<br />

lib<br />

bytecode<br />

jpa<br />

hibernate-jpa-2.0-api-1.0.0.Final.jar<br />

optional<br />

c3p0<br />

ehcache<br />

infinispan<br />

jbosscache<br />

oscache<br />

proxool<br />

swarmcache<br />

required<br />

antlr-2.7.6.jar<br />

commons-collections-3.1.jar<br />

dom4j-1.6.1.jar<br />

javassist-3.9.0.GA.jar<br />

jta-1.1.jar<br />

slf4j-api-1.5.8.jar<br />

project<br />

The package contains most of the Java libraries that are required to run a<br />

Hibernate application, including the Hibernate documentation and the source<br />

code project files for the Hibernate libraries. Table 6-1 describes the Java<br />

libraries that are included.<br />

Table 6-1 Included Java libraries<br />

File Description<br />

hibernate3.jar Hibernate Core library for Relational Persistence<br />

hibernate-jpa-2.0-api-1<br />

.0.0.Final.jar<br />

Hibernate definition of the Java Persistence 2.0 API<br />

antlr-2.7.6.jar Framework for grammatical descriptions containing Java<br />

Chapter 6. <strong>IBM</strong> <strong>Informix</strong> with Hibernate 193


6.2.2 Configuration<br />

File Description<br />

commons-collections-3.1<br />

.jar<br />

dom4j-1.6.1.jar XML framework for Java<br />

In addition to the libraries that are supplied by the Hibernate package, the .jar<br />

packages contain the following libraries for the JDBC driver that must be included<br />

in the CLASSPATH:<br />

► ifxjdbc.jar: <strong>IBM</strong> <strong>Informix</strong> JDBC Driver<br />

► db2jcc.jar: <strong>IBM</strong> Data Server Driver for JDBC<br />

The Hibernate package is also available as a Maven 2 artifact. Maven is an open<br />

source software project management that uses XML files based on the Project<br />

Object Model (POM) to manage all the attributes and dependencies files of a<br />

Java project. For more information about Maven, refer to the Apache Maven<br />

Project documentation at:<br />

http://maven.apache.org/what-is-maven.html<br />

In this section, we discuss the configuration settings that are required to develop<br />

an <strong>Informix</strong> application with Hibernate.<br />

194 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong><br />

Types that extend and augment the Java Collections<br />

Framework<br />

javassist-3.9.0.GA.jar Java programming Assistant<br />

jta-1.1.jar The javax.transaction package<br />

slf4j-api-1.5.8.jar API for the Simple Logging Facade for Java (SLF4J)<br />

Note: The slf4j-api-1.5.8.jar package does not contain the complete set<br />

of libraries for the Simple Logging Facade for Java (SLF4J). You must use a<br />

package that provides an implementation for SLF4J in conjunction with<br />

Hibernate API.<br />

Several implementations of SLF4J are available at:<br />

http://www.slf4j.org/download.html<br />

In our examples, we use slf4j-simple-1.6.1.jar and slf4j-nop-1.6.1.jar,<br />

which provide simple-logging and discarded-logging.


CLASSPATH<br />

CLASSPATH is an environment variable that tells the Java compiler and the Java<br />

virtual machine (JVM) where to look for Java class files and Java libraries.<br />

To use Hibernate with a Java program, you must include the core library, the<br />

hibernate3.jar file, and all the libraries in the lib/required directory in the<br />

application CLASSPATH. An implementation of the SLF4J logger and the JDBC<br />

driver is also required for Hibernate to work.<br />

Example 6-2 shows a UNIX script that creates the CLASSPATH environment<br />

variable. We use slf4j-nop-1.6.1.jar with discarded-logging and the <strong>Informix</strong><br />

JDBC Driver ifxjdbc.jar file for our examples.<br />

Example 6-2 Hibernate CLASSPATH script<br />

export CLASSPATH=$CLASSPATH:.<br />

export CLASSPATH=$CLASSPATH:/work/lib/commons-collections-3.1.jar<br />

export CLASSPATH=$CLASSPATH:/work/lib/dom4j-1.6.1.jar<br />

export CLASSPATH=$CLASSPATH:/work/lib/hibernate-jpa-2.0-api-1.0.0.Final.jar<br />

export CLASSPATH=$CLASSPATH:/work/lib/hibernate3.jar<br />

export CLASSPATH=$CLASSPATH:/work/lib/javassist-3.9.0.GA.jar<br />

export CLASSPATH=$CLASSPATH:/work/lib/jta-1.1.jar<br />

export CLASSPATH=$CLASSPATH:/work/lib/slf4j-api-1.6.1.jar<br />

export CLASSPATH=$CLASSPATH:/work/lib/antlr-2.7.6.jar<br />

export CLASSPATH=$CLASSPATH:/work/lib/slf4j-nop-1.6.1.jar<br />

export CLASSPATH=$CLASSPATH:/work/lib/ifxjdbc.jar<br />

Hibernate configuration file<br />

Hibernate provides the following files to specify configuration parameters:<br />

► hibernate.properties: A standard Java properties text file<br />

► hibernate.cfg.xml: An XML formatted file<br />

Both files contain the same configuration details for the Hibernate service. If both<br />

files exist, the XML configuration file overrides the settings in the properties file.<br />

The configuration file (hibernate.propertieshibernate.cfg.xml) contains the<br />

information that Hibernate needs to connect to the database server. Details such<br />

as name of the JDBC driver class, ConnectionString, and authentication details<br />

are kept in this file.<br />

The Hibernate libraries require the configuration file (hibernate.properties or<br />

hibernate.cfg.xml) to be located in the root directory of the CLASSPATH.<br />

Chapter 6. <strong>IBM</strong> <strong>Informix</strong> with Hibernate 195


Example 6-3 shows a hibernate.cfg.xml file using the <strong>Informix</strong> JDBC Driver.<br />

Example 6-3 A hibernate.cfg.xml sample<br />

<br />

<br />

<br />

<br />

<br />

<br />

com.informix.jdbc.IfxDriver<br />

<br />

<br />

jdbc:informix-sqli://kodiak:9088/stores_demo:INFORMIXSERVER=demo_on;<br />

<br />

<br />

informix<br />

<br />

<br />

password<br />

<br />

<br />

org.hibernate.dialect.<strong>Informix</strong>Dialect<br />

<br />

false<br />

update<br />

<br />

<br />

<br />

<br />

In addition to the JDBC information, the configuration file also contains<br />

configuration details for the Hibernate service.<br />

Use the dialect property to specify the SQL dialect for the database server. A<br />

Hibernate dialect is a Java class that contains specific details regarding the SQL<br />

syntax that is needed to communicate with a particular database.<br />

When using the <strong>IBM</strong> <strong>Informix</strong> JDBC Driver with Hibernate, set the dialect to<br />

orb.hibernate.dialect.<strong>Informix</strong>Dialect. The dialect for the <strong>IBM</strong> Data Server<br />

Driver for JDBC is org.hibernate.dialect.DB2Dialect.<br />

These classes are included in the hibernate3.jar package and contain a basic,<br />

non-optimized implementation of the <strong>Informix</strong> dialect.<br />

196 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Note: You can find a patch that adds <strong>Informix</strong> SQL optimizations to the original<br />

Hibernate dialect for <strong>Informix</strong> databases at:<br />

http://www.iiug.org/opensource/files/hibernate-3.3.2_informix.tar.gz<br />

The XML configuration file allows the inclusion of XML mapping files. Use the<br />

mapping resource property to specify the XML file that contains the mapping<br />

between the SQL table and the Java object.<br />

Example 6-3 on page 196 includes the State.hbm.xml mapping file as part of the<br />

hibernate configuration, as shown in the following line:<br />

<br />

Properties, such as hibernate.show_sql or hbm2ddl.auto, control the behavior<br />

of the Hibernate service. Use the hibernate.show_sql property to dump all the<br />

SQL statements to the console, which might be useful for debugging purposes.<br />

Set the hbm2ddl.auto property to update to specify that the schema for the SQL<br />

table is updated automatically if it differs from the definition in the XML definition.<br />

For more information regarding all the supported properties for the Hibernate<br />

configuration files, refer to:<br />

http://docs.jboss.org/hibernate/core/3.3/reference/en/html/session-configuration<br />

.html<br />

XML mapping file<br />

You can use the XML mapping file to specify the relations between a Java object<br />

and an SQL database object. These mapping definitions are used to provide<br />

Hibernate with the information that is needed to persist the Java objects into the<br />

relational database. They also provide support features, such as creating the<br />

database schema and relationship between the objects.<br />

XML mapping files are not required when using Java annotations. The mapping<br />

information is added using annotations in the Java source code.<br />

Example 6-4 shows a basic XML file used to map the States table to the State<br />

Java object.<br />

Example 6-4 The State.hbm.xml file<br />

<br />

<br />

<br />


name="State"<br />

table="States"><br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

The definition includes information, such as the table name and column to be<br />

used as identifier (ID), and specific attributes for the elements, such as the<br />

generator class that defines a column as an identifier that is generated<br />

automatically by the Java libraries. These details are used by the Hibernate<br />

libraries to generate SQL statements automatically, including Data Definition<br />

Language (DDL) and Data Manipulation Language (DML).<br />

For a complete list of all the attributes that are available in an XML mapping file,<br />

refer to:<br />

http://docs.jboss.org/hibernate/core/3.3/reference/en/html/mapping.html#mapping<br />

-declaration<br />

6.3 Using Hibernate with an <strong>Informix</strong> database<br />

In this section, we demonstrate how to perform basic operations using the<br />

Hibernate API with an <strong>IBM</strong> <strong>Informix</strong> database server.<br />

6.3.1 Components of a Hibernate application<br />

To develop a Hibernate application, you need to complete the following tasks:<br />

► Create the Java objects.<br />

► Create the XML Mapping files for the Java objects.<br />

► Create the configuration file for the Hibernate framework.<br />

198 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


► Create the HibernateUtil helper class that provides access to the Hibernate<br />

session.<br />

► Create the application that will use the Java persistence objects.<br />

Java object<br />

Hibernate supports the use of Plain Old Java Objects (POJO) for the definition of<br />

a persistence object. Thus, there is a special requirement when writing the Java<br />

class that represents the object.<br />

Example 6-5 shows the contents of the State.java file that is used to define the<br />

State object. The State Java object is created as any normal Java object. The<br />

object has three properties (id, code, and sname) and the usual methods to set<br />

and get those properties, such as setcode() or setsname(). The id attribute is<br />

used to uniquely identify the Java persistence object.<br />

Example 6-5 The State.java file<br />

public class State {<br />

private Long id;<br />

private String code;<br />

private String sname;<br />

}<br />

public State() {}<br />

public State(String text, String text2) {<br />

this.code = text;<br />

this.sname = text2;<br />

}<br />

public Long getId() {<br />

return id;<br />

}<br />

private void setId(Long id) {<br />

this.id = id;<br />

}<br />

public String getcode() {<br />

return code;<br />

}<br />

public void setcode(String text) {<br />

this.code = text;<br />

}<br />

public String getsname() {<br />

return sname;<br />

}<br />

public void setsname(String text) {<br />

this.sname = text;<br />

}<br />

Chapter 6. <strong>IBM</strong> <strong>Informix</strong> with Hibernate 199


Example 6-6 shows the CLASSPATH variable used in the environment and how<br />

to compile the State.java source code.<br />

Example 6-6 Compile line for State.java<br />

C:\work>set classpath<br />

CLASSPATH=C:\work\lib\commons-collections-3.1.jar;C:\work\lib\dom4j-1.6.1.jar;C<br />

:\work\lib\hibernate-jpa-2.0-api-1.0.0.Final.jar;C:\work\lib\hibernate3.jar;C:\<br />

work\lib\ifxjdbc.jar;C:\work\lib\javassist-3.9.0.GA.jar;C:\work\lib\jta-1.1.jar<br />

;C:\work\lib\slf4j-api-1.6.1.jar;C:\work\lib\slf4j-nop-1.6.1.jar;C:\work\lib\an<br />

tlr-2.7.6.jar;.<br />

C:\work>javac State.java<br />

C:\work><br />

XML mapping file<br />

An XML mapping file is required to link the Java object with an <strong>Informix</strong> database<br />

object. The States table keeps all the instances of the Java State object.<br />

The common convention for the name of the XML mapping file is<br />

objectname_hbm.xml.<br />

Example 6-7 shows the contents of the State_hbm.xml file.<br />

Example 6-7 The State_hbm.xml file<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

200 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


The name of the class is State. It is mapped to the <strong>Informix</strong> SQL table States.<br />

The State class contains two types of elements:<br />

► <br />

Defines the mapping from that property to the primary key column. It usually<br />

contains the generator element that is used to generate unique identifiers for<br />

the ID property.<br />

The generator class supports different methods of generating identifiers.<br />

Increment is the most basic method, and sequence allows to use an SQL<br />

sequence to obtain the identifier value. For a list of all the methods<br />

implemented in the generator interface, refer to:<br />

http://docs.jboss.org/hibernate/core/3.3/reference/en/html/mapping.html#map<br />

ping-declaration-id<br />

► <br />

Defines a property for the object, including the name of the property and the<br />

name of the mapped database table column.<br />

The elements of the XML mapping file can have additional attributes to define<br />

specific characteristics of the columns it maps. You can use attributes such as<br />

type and not-null to specify the data type and the nullability of a column.<br />

Hibernate configuration file<br />

The Hibernate configuration file must reside in the root directory of the<br />

CLASSPATH. It contains configuration values for the Hibernate service and<br />

connection details for the database server.<br />

Example 6-8 shows the contents of the hibernate.cfg.xml file that we used in<br />

our sample. The connection details correspond to the <strong>IBM</strong> <strong>Informix</strong> JDBC Driver.<br />

Example 6-8 The hibernate.cfg.xml file<br />

<br />

<br />

<br />

<br />

<br />

<br />

com.informix.jdbc.IfxDriver<br />

<br />

<br />

jdbc:informix-sqli://kodiak:9088/stores_demo:INFORMIXSERVER=demo_on;<br />

<br />

<br />

Chapter 6. <strong>IBM</strong> <strong>Informix</strong> with Hibernate 201


informix<br />

<br />

<br />

password<br />

<br />

<br />

org.hibernate.dialect.<strong>Informix</strong>Dialect<br />

<br />

false<br />

update<br />

<br />

<br />

<br />

Example 6-9 shows the attributes that are required for an <strong>IBM</strong> Data Server Driver<br />

for JDBC connection. The configuration file includes the State.hbm.xml XML<br />

mapping for the State object.<br />

Example 6-9 <strong>IBM</strong> Data Server Driver hibernate.cfg.xml file<br />

<br />

org.hibernate.dialect.DB2Dialect<br />

<br />

<br />

com.ibm.db2.jcc.DB2Driver<br />

<br />

<br />

jdbc:ids://kodiak:9089/stores_demo;<br />

<br />

HibernateUtil helper class<br />

The HibernateUtil class is used to interact with the Hibernate service. It<br />

performs the operations related to the Hibernate SessionFactory classes that<br />

provide a convenient way for the application to access the Hibernate session.<br />

The Java file that contains the HibernateUtil helper class is<br />

HibernateUtil.java. Example 6-10 shows a typical helper class.<br />

Example 6-10 The HiberanteUtil.java file<br />

import org.hibernate.SessionFactory;<br />

import org.hibernate.cfg.Configuration;<br />

public class HibernateUtil {<br />

private static final SessionFactory sessionFactory;<br />

202 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


static {<br />

try {<br />

// Creates the SessionFactory from hibernate.cfg.xml<br />

sessionFactory = new Configuration().configure().buildSessionFactory();<br />

}<br />

catch (Throwable ex) {<br />

System.err.println("SessionFactory creation failed." + ex);<br />

throw new ExceptionInInitializerError(ex);<br />

}<br />

}<br />

public static SessionFactory getSessionFactory() {<br />

return sessionFactory;<br />

}<br />

public static void shutdown() {<br />

// Close caches and connection pools<br />

getSessionFactory().close();<br />

}<br />

}<br />

This class creates a Hibernate session using the parameters that are specified in<br />

the Hibernate configuration file. Create the class by compiling the<br />

HibernateUtil.java Java file as follows:<br />

javac HibernateUtil.java<br />

Java application<br />

The only task that is required by a Java application to use the Hibernate<br />

persistence object is to create a Hibernate Session instance using the<br />

HibernateUtil helper class. After that, the application can create persist objects<br />

in the same manner that it does for any other Java object.<br />

6.3.2 Working with a Hibernate object<br />

Developers must follow an object-orientated methodology when writing<br />

applications using the Hibernate API. With Hibernate, the data is represented by<br />

the status and properties of an object, not by tables and rows in a relational<br />

database.<br />

Storing<br />

When a persistent object is created and saved or stored, an insert operation is<br />

performed on the database.<br />

Chapter 6. <strong>IBM</strong> <strong>Informix</strong> with Hibernate 203


Example 6-11 shows basic Java code that creates a new State object using the<br />

parameters that are supplied in the command line. The example creates a<br />

Hibernate Session object using the helper class and then creates a new State<br />

object called myState. The myState.setcode() and myState.setsname() methods<br />

are used to stored the values that are passed from the command line.<br />

Example 6-11 The Create.java code<br />

import java.util.*;<br />

import org.hibernate.*;<br />

import javax.persistence.*;<br />

public class create {<br />

public static void main(String[] args) {<br />

Session Session = HibernateUtil.getSessionFactory().openSession();<br />

Transaction Transaction = Session.beginTransaction();<br />

State myState = new State();<br />

myState.setcode(args[0]);<br />

myState.setsname(args[1]);<br />

Long stateId = (Long) Session.save(myState);<br />

System.out.println("Stated added: "+myState.getcode()+", "<br />

+myState.getsname());<br />

Transaction.commit();<br />

Session.close();<br />

// Shutting down the application<br />

HibernateUtil.shutdown();<br />

}<br />

}<br />

Example 6-12 shows the compile line and the output of the create.java sample.<br />

Example 6-12 Compiling the create.java sample and the output<br />

C:\work>javac create.java<br />

C:\work>java create AZ Arizona<br />

Stated added: AZ, Arizona<br />

C:\work><br />

The hbm2ddl.auto Hibernate property is set to update in the configuration file,<br />

which means that if the table does not exist in the database, it is created<br />

automatically using the table model that is defined in the XML mapping file.<br />

204 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Example 6-13 shows the schema of the created States table and the new row<br />

that is added to the table.<br />

Example 6-13 States table schema<br />

D:\Infx\ids1150>dbaccess stores_demo -<br />

Database selected.<br />

> INFO COLUMNS FOR states;<br />

Column name Type Nulls<br />

id int8 no<br />

code varchar(255) yes<br />

sname varchar(255) yes<br />

> SELECT * FROM states;<br />

id 1<br />

code AZ<br />

sname Arizona<br />

1 row(s) retrieved.<br />

><br />

The Java object is made persistent, thus saving the state of the object in the<br />

database, using the Session.save() Hibernate method and committing the unit<br />

of work with Transaction.commit().<br />

Loading<br />

To retrieve a persistent object from the database server, the application must<br />

create a Hibernate session and load the state of the object into the current<br />

session.<br />

The process of loading a persistence object can be achieved using several<br />

methods:<br />

► Use Session.load() and Session.get() to retrieve the state of an object from<br />

the database using the object identifier as reference. For example, to load the<br />

State object with ID equal to 1, the following code is needed:<br />

State mystateobj = (State) Session.load(State.class,1);<br />

Chapter 6. <strong>IBM</strong> <strong>Informix</strong> with Hibernate 205


The only difference between the load() and get() methods is the returned<br />

value. If the object is not found, get() returns a null and load() throws an<br />

exception.<br />

► Use an SQL or HQL query. HQL is similar to SQL but is optimized for an<br />

object-orientated environment. You can use methods, such as<br />

Session.createQuery() and Session.createCiteria(), to load the state of<br />

one or multiple objects from the database server. The following command<br />

loads all State objects into a list:<br />

List states = session.createQuery("from state").list();<br />

Example 6-14 demonstrates how to load a single object from the database using<br />

the Session.load() method.<br />

Example 6-14 The load.java sample<br />

import java.util.List;<br />

import org.hibernate.HibernateException;<br />

import org.hibernate.Session;<br />

import org.hibernate.Transaction;<br />

import org.hibernate.criterion.*;<br />

public class load {<br />

public static void main(String[] args) {<br />

}<br />

}<br />

Long stateId = null;<br />

Session Session = HibernateUtil.getSessionFactory().openSession();<br />

Transaction Transaction = Session.beginTransaction();<br />

stateId=Long.parseLong(args[0]);<br />

State mystate = (State) Session.load(State.class,stateId);<br />

System.out.println(mystate.getcode() +", " +<br />

mystate.getsname() );<br />

Transaction.commit();<br />

Session.close();<br />

206 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Example 6-15 shows how to compile and run the previous example. The<br />

application loads the State object identified by the id value passed through the<br />

command line.<br />

Example 6-15 Output of the load.java sample<br />

C:\work>javac load.java<br />

C:\work>java load 1<br />

AZ, Arizona<br />

C:\work>java load 2<br />

CA, California<br />

C:\work><br />

The application can use an HQL query to load all the objects, or entities, of a<br />

particular type. All the State objects are kept in the States table. Example 6-16<br />

shows how to retrieve a list of the State entities.<br />

Example 6-16 The list.java sample<br />

C:\work>cat list.java<br />

import java.util.*;<br />

import org.hibernate.*;<br />

import javax.persistence.*;<br />

public class list {<br />

public static void main(String[] args) {<br />

Session newSession = HibernateUtil.getSessionFactory().openSession();<br />

Transaction newTransaction = newSession.beginTransaction();<br />

List states = newSession.createQuery("from State order by id asc").list();<br />

for ( Iterator iter = states.iterator();<br />

iter.hasNext(); ) {<br />

State state = (State) iter.next();<br />

System.out.println(state.getId() +", "+ state.getcode()<br />

+", " + state.getsname() );<br />

}<br />

newTransaction.commit();<br />

newSession.close();<br />

HibernateUtil.shutdown();<br />

}<br />

}<br />

C:\work>javac list.java<br />

C:\work>java list<br />

Chapter 6. <strong>IBM</strong> <strong>Informix</strong> with Hibernate 207


1, AZ, Arizona<br />

2, CA, California<br />

C:\work><br />

Updating<br />

Updating an persistent object is the process of changing the state of the object.<br />

No specific operation is required for this task. The application must load the<br />

object, change the object properties, and save it.<br />

Example 6-17 demonstrates how to update individual objects. It uses the<br />

parameters from the command line to change the code and sname properties of a<br />

State object.<br />

Example 6-17 The update.java sample<br />

C:\work>cat update.java<br />

import java.util.List;<br />

import org.hibernate.HibernateException;<br />

import org.hibernate.Session;<br />

import org.hibernate.Transaction;<br />

public class update {<br />

public static void main(String[] args) {<br />

Long stateId = null;<br />

Session Session = HibernateUtil.getSessionFactory().openSession();<br />

Transaction Transaction = Session.beginTransaction();<br />

stateId=Long.parseLong(args[0]);<br />

State mystate = (State) Session.load(State.class,stateId);<br />

mystate.setcode(args[1]);<br />

mystate.setsname(args[2]);<br />

Session.save(mystate);<br />

System.out.println("new values: "+ mystate.getcode()+", "+<br />

mystate.getsname() );<br />

Transaction.commit();<br />

Session.close();<br />

}<br />

}<br />

C:\work>javac update.java<br />

208 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


C:\work>java update 1 AZ ARIZONA<br />

new values: AZ, ARIZONA<br />

C:\work><br />

Criteria<br />

Criteria queries are a feature of HQL that allow the building of complex queries<br />

using an object-orientated API.<br />

Example 6-18 shows how to update a president object using an HQL criteria to<br />

retrieve the object from the database. The HQL criteria is created using the name<br />

of the class for the object that you want to select, State.class. An HQL<br />

Restriction, Restriction.eq("code", args[0]), is used to specify a filter for the<br />

criteria. This restriction specifies that the query returns the objects with a specific<br />

code value.<br />

Example 6-18 The update2.java sample<br />

import java.util.*;<br />

import org.hibernate.*;<br />

import javax.persistence.*;<br />

import org.hibernate.criterion.*;<br />

public class update2 {<br />

public static void main(String[] args) {<br />

Session Session = HibernateUtil.getSessionFactory().openSession();<br />

Transaction Transaction = Session.beginTransaction();<br />

Criteria crit = Session.createCriteria(State.class);<br />

crit.add( Restrictions.eq( "code", args[0]) );<br />

List states = crit.list();<br />

for ( Iterator iter = states.iterator(); iter.hasNext(); ) {<br />

State mystate = (State) iter.next();<br />

mystate.setsname(args[1]);<br />

Session.flush();<br />

Long msgId = (Long) Session.save(mystate);<br />

System.out.println("new values: "+ mystate.getcode()+", "+<br />

mystate.getsname() );<br />

}<br />

Transaction.commit();<br />

Session.close();<br />

HibernateUtil.shutdown();<br />

}<br />

}<br />

Chapter 6. <strong>IBM</strong> <strong>Informix</strong> with Hibernate 209


Example 6-19 shows the output of the example.<br />

Example 6-19 The update2.java output<br />

C:\work>javac update2.java<br />

C:\work>java update2 AZ Arizona<br />

new values: AZ, Arizona<br />

C:\work><br />

Deleting<br />

In the Hibernate framework, deleting a persistence object means to make the<br />

object transient. A transient object is a typical Java object, but the state of the<br />

object is not stored anywhere. Thus, the object exists only during the life of the<br />

application.<br />

An object can be deleted using the Session.delete() method. Example 6-20<br />

demonstrates how to use the Session.delete() method.<br />

Example 6-20 The delete.java sample<br />

C:\work>cat delete.java<br />

import java.util.List;<br />

import org.hibernate.HibernateException;<br />

import org.hibernate.Session;<br />

import org.hibernate.Transaction;<br />

public class delete {<br />

public static void main(String[] args) {<br />

Long stateId = null;<br />

Session Session = HibernateUtil.getSessionFactory().openSession();<br />

Transaction Transaction = Session.beginTransaction();<br />

stateId=Long.parseLong(args[0]);<br />

State mystate = (State) Session.load(State.class,stateId);<br />

Session.delete(mystate);<br />

System.out.println( "Object deleted");<br />

Transaction.commit();<br />

Session.close();<br />

}<br />

}<br />

C:\work>javac delete.java<br />

210 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


C:\work>java delete 2<br />

Object deleted<br />

C:\work>java list<br />

1, AZ, Arizona<br />

C:\work><br />

One of the main features of using Hibernate is that it abstracts the JDBC layer<br />

from the application. Thus, applications written using the Hibernate API are not<br />

tied to a specific JDBC driver or relational database server.<br />

You can run all the examples that we present in this section using any of the two<br />

<strong>Informix</strong> JDBC drivers that are available, <strong>IBM</strong> <strong>Informix</strong> JDBC Driver or <strong>IBM</strong> Data<br />

Server Driver for JDBC. Refer to the “Hibernate configuration file” on page 195<br />

for information regarding how to switch between JDBC drivers.<br />

For more information about how to develop using the Hibernate API, refer to:<br />

http://docs.jboss.org/hibernate/core/3.3/reference/en/html/objectstate.html<br />

6.3.3 Using annotations<br />

Java annotations is a feature added into the Java 5 Software Development Kit<br />

(SDK) that allows the inclusion of special annotations within the Java source<br />

code to express metadata relating to program objects.<br />

Hibernate supports Java annotations through the use of the Hibernate<br />

Annotations Extensions. These extensions allow you to include the definition of<br />

specific Hibernate properties, such as configuration properties or object<br />

mappings properties, directly into the Java code.<br />

With annotations, there is no need for a specific XML mapping file to link the Java<br />

objects with the database objects.<br />

Example 6-21 shows the definition of the State object using Hibernate<br />

annotations. Annotations, such as @Entity, @Table or @Column, define the<br />

mapping information that is needed to persist the Java objects into the database.<br />

Example 6-21 The state.java sample with annotations<br />

import javax.persistence.*;<br />

@Entity<br />

@Table(name="States")<br />

public class State {<br />

Chapter 6. <strong>IBM</strong> <strong>Informix</strong> with Hibernate 211


private Long id;<br />

private String code;<br />

private String sname;<br />

public State() {}<br />

public State(String text, String text2) {<br />

this.code = text;<br />

this.sname = text2;<br />

}<br />

@Id<br />

@GeneratedValue(strategy=GenerationType.IDENTITY )<br />

@Column(name="id")<br />

public Long getId() {<br />

return id;<br />

}<br />

private void setId(Long id) {<br />

this.id = id;<br />

}<br />

@Column(name="code", length=2, nullable=false)<br />

public String getcode() {<br />

return code;<br />

}<br />

public void setcode(String text) {<br />

this.code = text;<br />

}<br />

@Column(name="sname", length=15, nullable=false)<br />

public String getsname() {<br />

return sname;<br />

}<br />

public void setsname(String text) {<br />

this.sname = text;<br />

}<br />

}<br />

Because all the information that is required to map the objects is specified as<br />

annotations, you do not need to include a section in the Hibernate<br />

hibernate.cfg.xml configuration file.<br />

212 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


When using annotations, the HibernateUtil helper class, HibernateUtil.java,<br />

uses the AnnotationConfiguration() interface to retrieve the Hibernate<br />

properties and the metadata definition from the object class. Example 6-22<br />

shows the HibernateUtil.java file that is used to create a SessionFactory for<br />

the State.class object.<br />

Example 6-22 The HibernateUtil.java sample for annotations<br />

import org.hibernate.SessionFactory;<br />

import org.hibernate.cfg.AnnotationConfiguration;<br />

public class HibernateUtil {<br />

private static final SessionFactory sessionFactory;<br />

static {<br />

try {<br />

// Create the SessionFactory from hibernate.cfg.xml<br />

}<br />

sessionFactory = new AnnotationConfiguration()<br />

.configure()<br />

.addAnnotatedClass(State.class)<br />

.buildSessionFactory();<br />

} catch (Throwable ex) {<br />

System.err.println("Initial SessionFactory creation failed." + ex);<br />

throw new ExceptionInInitializerError(ex);<br />

}<br />

}<br />

public static SessionFactory getSessionFactory() {<br />

return sessionFactory;<br />

}<br />

public static void shutdown() {<br />

getSessionFactory().close();<br />

}<br />

You do not need to change the code for the Java applications that use the<br />

persistence object. The process when using Hibernate annotations for<br />

manipulating the objects is the same as when using the XML mapping files.<br />

You can find a description of all the Hibernate annotation extensions at:<br />

http://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/#en<br />

tity-hibspec<br />

Chapter 6. <strong>IBM</strong> <strong>Informix</strong> with Hibernate 213


214 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Chapter 7. Working with <strong>IBM</strong> <strong>Informix</strong><br />

OLE DB Provider<br />

7<br />

This chapter describes <strong>IBM</strong> <strong>Informix</strong> OLE DB Provider. It includes the following<br />

topics:<br />

► <strong>IBM</strong> <strong>Informix</strong> OLE DB Provider<br />

► Setup and configuration<br />

► Developing an OLE DB application<br />

► Visual Basic, ADO.NET, and SQL Server<br />

► Troubleshooting and tracing<br />

© Copyright <strong>IBM</strong> Corp. 2010. All rights reserved. 215


7.1 <strong>IBM</strong> <strong>Informix</strong> OLE DB Provider<br />

<strong>Informix</strong> OLE DB Provider is a Universal Data Access component that enables<br />

<strong>IBM</strong> <strong>Informix</strong> Server access from OLE DB consumers.<br />

Microsoft OLE DB is a specification for a set of interfaces that is designed to<br />

expose data from a variety of sources (relational and non-relational). OLE DB<br />

uses the Component Object Model (COM) to accomplish this.<br />

You can use <strong>IBM</strong> <strong>Informix</strong> OLE DB Provider to enable client applications, such as<br />

ActiveX Data Object (ADO) applications and web pages, to access data on an<br />

<strong>IBM</strong> <strong>Informix</strong> database server.<br />

Table 7-1 shows the name and COM class ID of the <strong>IBM</strong> <strong>Informix</strong> OLE DB<br />

Provider.<br />

Table 7-1 COM class ID<br />

Name DLL CLSID<br />

ifxoledbc iifxoledbc.dll {A6D00422-FD6C-11D0-8043-00A0C90F1C59}<br />

Table 7-2 lists the <strong>Informix</strong> database servers that support <strong>IBM</strong> <strong>Informix</strong> OLE DB<br />

Provider.<br />

Table 7-2 Supported databases<br />

Database Server Versions<br />

<strong>IBM</strong> <strong>Informix</strong> 10.0,11.10,11.50<br />

<strong>IBM</strong> <strong>Informix</strong> Extended Parallel Server 8.50 and higher<br />

<strong>IBM</strong> <strong>Informix</strong> Online 5.20 and higher<br />

7.2 Setup and configuration<br />

In this section, we discuss how to install and set up the OLE DB provider and<br />

how to perform basic connectivity tests.<br />

7.2.1 Installation and setup<br />

<strong>IBM</strong> <strong>Informix</strong> OLE DB Provider is included only in the Windows version of<br />

<strong>Informix</strong> Client Software Development Kit (Client SDK). The <strong>Informix</strong> OLE DB<br />

216 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Provider is selected by default in the Client SDK installation. During the<br />

installation process, the provider is registered automatically on the Windows<br />

registry as a command component.<br />

The default installation directory is the C:\Program<br />

Files\<strong>IBM</strong>\<strong>Informix</strong>\Client-SDK directory. The INFORMIXDIR environment<br />

variable should point to the directory where the product is installed. The provider<br />

shared library, ifxoledbc.dll, is located in %INFORMIXDIR%\bin directory.<br />

Because by default <strong>Informix</strong> OLE DB Provider is registered during Client SDK<br />

installation, manual registration is usually not required. However, if needed, you<br />

can register <strong>Informix</strong> OLE DB Provider manually using the Microsoft<br />

regsvr32.exe tool using the following command:<br />

regsvr32.exe %INFORMIXDIR%\bin\ifxoledbc.dll<br />

Note: On a Windows x64 (64-bit) system, there are two versions of the<br />

regsvr32.exe tool:<br />

► The 32-bit version is located in C:\WINDOWS\SysWOW64<br />

► The 64-bit version is located in C:\WINDOWS\System<br />

Use the correct version when registering <strong>Informix</strong> OLE DB Provider.<br />

Otherwise, the application will fail to load the shared library due to a<br />

mismatched version.<br />

After installation, you must run the coledbp.sql script on the database server<br />

against the sysmaster database as user informix to add the tables and functions<br />

that are required by <strong>Informix</strong> OLE DB Provider to work.<br />

The coledbp.sql script is located in the %INFORMIXDIR%\etc directory. If you want<br />

to remove the support functions and tables, use the doledbp.sql script that is<br />

located in the same directory.<br />

7.2.2 Verifying connectivity<br />

Client SDK does not contain any specific tool to test <strong>Informix</strong> OLE DB Provider.<br />

Internally, <strong>Informix</strong> OLE DB Provider uses the same <strong>Informix</strong> connection libraries<br />

as ESQL/C or ODBC. You can test the basic connection details for your database<br />

server using the iLogin utility that is included in the %INFORMIXDIR%\bin directory.<br />

Testing using Visual Basic Scripting Edition<br />

Visual Basic Scripting Edition (VBScript) is a scripting language that is included<br />

as part of the Windows operating system. It provides access to ADO objects<br />

Chapter 7. Working with <strong>IBM</strong> <strong>Informix</strong> OLE DB Provider 217


through COM. You can use it to test whether the <strong>Informix</strong> OLE DB Provider is<br />

configured properly.<br />

A VBScript file is a text file with a .vbs extension that is loaded automatically and<br />

executed by Visual Basic at run time.<br />

Example 7-1 shows a simple VBScript that loads <strong>Informix</strong> OLE DB Provider and<br />

selects a single row from the database.<br />

Example 7-1 The connect.vbs script<br />

' ---- Test_Ifx.vbs ----<br />

On Error Resume Next<br />

args = WScript.Arguments.Count<br />

If args < 1 then<br />

WScript.Echo "usage: connect.vbs Connection_string"<br />

WScript.Echo " e.g.: connect.vbs ""Data Source=stores_demo@demo_on;User<br />

ID=informix;Password=password;"""<br />

WScript.Quit<br />

end If<br />

set conn=createobject("ADODB.Connection")<br />

conn.provider = "Ifxoledbc"<br />

conn.connectionstring = WScript.Arguments.Item(0)<br />

conn.open<br />

If Err then<br />

WScript.Echo "Error!! "+conn.Errors(0).Description<br />

Else<br />

WScript.Echo "Connected"<br />

conn.close<br />

End If<br />

' ---- Test_Ifx.vbs ----<br />

Example 7-2 shows how run the connect.vbs script with a data source string as<br />

the parameter to test the database connectivity.<br />

Example 7-2 Output of the connect.vbs script<br />

c:\work>connect.vbs<br />

usage: connect.vbs Connection_string<br />

e.g.: connect.vbs "Data Source=stores_demo@demo_on;User<br />

ID=informix;Password=password;"<br />

c:\work>connect.vbs "Data Source=stores_demo@demo_on;User<br />

ID=informix;Password=password;"<br />

Connected<br />

218 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


c:\work>connect.vbs "Data Source=stores_demo@demo_on;User<br />

ID=informix;Password=invalid;"<br />

Error!! EIX000: (-951) Incorrect password or user informix@dubito is not known<br />

on the database server.<br />

Rowset Viewer<br />

You can also test <strong>Informix</strong> OLE DB Provider using the Rowset Viewer. The<br />

Rowset Viewer is included with the Microsoft Data Access Components (MDAC)<br />

2.8 Software Development Kit (SDK), which you can download from the following<br />

location:<br />

http://www.microsoft.com/downloads/details.aspx?FamilyID=6c050fe3-c795-4b7d-b03<br />

7-185d0506396c<br />

To test <strong>Informix</strong> OLE DB Provider using the Rowset Viewer tool, perform the<br />

following steps:<br />

1. Run the Rowset tool.<br />

2. Select File � Full Connect.<br />

3. In the Full Connect dialog box, choose Ifxoledbc in the Provider field.<br />

4. In the DataSource field, enter the database server name to which you want to<br />

connect, for example stores_demo@demo_on.<br />

5. Click OK.<br />

You also can use Rowset Viewer to run SQL statements against the database<br />

server. To execute an SQL statement, write the SQL text in the Rowset pane and<br />

click .<br />

7.3 Developing an OLE DB application<br />

This section describes the interfaces that are implemented in <strong>Informix</strong> OLE DB<br />

Provider and demonstrates how to perform basic database operations.<br />

In this section, we discuss the following topics:<br />

► Supported interfaces<br />

► Connecting to database<br />

► Type mapping<br />

► Cursors<br />

► Typical database operations<br />

Chapter 7. Working with <strong>IBM</strong> <strong>Informix</strong> OLE DB Provider 219


7.3.1 Supported interfaces<br />

An OLE DB application creates objects based on ADO interfaces to perform<br />

operations against a database server. Table 7-3 lists a few ADO interfaces that<br />

are implemented in <strong>Informix</strong> OLE DB Provider as examples. For a complete list,<br />

refer to:<br />

http://publib.boulder.ibm.com/infocenter/idshelp/v115/topic/com.ibm.oledb.doc/s<br />

ii-xa-21954.htm#sii-xa-21954<br />

Table 7-3 <strong>Informix</strong> OLE DB Provider supported interfaces<br />

Interface Description<br />

IAccessor Provides methods for accessor management<br />

IColumnsInfo Provides information about columns of a rowset or prepared<br />

command<br />

ICommand Executes commands<br />

IDBCreateCommand Obtains a new command<br />

IDBCreateSession Obtains a new session<br />

IDBDataSourceAdmin Creates, destroys, and modifies data source objects<br />

IDBProperties Gets and sets the values of properties on the data source<br />

object or enumerator and obtains information about all<br />

properties that are supported<br />

IErrorLookup Used by OLE DB error objects to determine the values of the<br />

error message, source, Help file path, and context ID based<br />

on the return code and a provider-specific error number<br />

IGetDataSource Obtains an interface pointer to the data source object<br />

IRowsetIdentity Indicates row instance identity is implemented on the rowset<br />

and enables testing for row identity<br />

ISessionProperties Returns information about the properties a session supports<br />

and the current settings of those properties<br />

ITransaction Used to commit, abort, and obtain status information about<br />

transactions<br />

220 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


7.3.2 Connecting to database<br />

In this section, we describe the connection string options with <strong>Informix</strong> OLE DB<br />

Provider.<br />

The connection details for the database server are passed to <strong>Informix</strong> OLE DB<br />

Provider using a connection string. If the Provider attribute of the Connection<br />

object is not set, you must include the provider keyword as part of the<br />

connection string to specify the name of <strong>Informix</strong> OLE DB Provider, ifxoledbc.<br />

For example:<br />

connStr="Provider=Ifxoledbc;Data Source=stores_demo@demo_on"<br />

Table 7-4 describes the specific connection string attributes for <strong>Informix</strong> OLE DB<br />

Provider.<br />

Table 7-4 Connection string attributes<br />

Keyword Description<br />

Data Source Database and <strong>Informix</strong> Server to which to connect.<br />

The syntax for the Data Source parameter is as<br />

follows:<br />

database@server<br />

If @server is not specified, the default database<br />

server is used (corresponding to the value specified<br />

by the client’s INFORMIXSERVER registry entry or<br />

environment variable).<br />

User ID The user ID used to connect to the <strong>Informix</strong> server<br />

Password The password for the user ID<br />

Persist Security Info Specifies whether the data source can keep<br />

authentication information such as the password<br />

Client_locale The client locale for the application which<br />

correspond to the locale used by the Windows OS<br />

Db_locale The database locale that was used when the<br />

database was created<br />

UNICODE Indicates whether to use <strong>IBM</strong> <strong>Informix</strong> GLS Unicode<br />

Controls and how the code set conversion to<br />

Unicode is done<br />

decasr8 If set, floating point numbers with a scale greater<br />

than 30 are returned as DBTYPE_R8<br />

Chapter 7. Working with <strong>IBM</strong> <strong>Informix</strong> OLE DB Provider 221


7.3.3 Type mapping<br />

Keyword Description<br />

RSASWS or<br />

REPORTSTRINGASWSTRING<br />

A typical connection string for <strong>Informix</strong> OLE DB Provider looks similar to the<br />

following string:<br />

Data Source=stores_demo@demo_on; User ID=informix; Password=password; Persist<br />

Security Info=True; CLIENT_LOCALE=en_US.CP1252; DB_LOCALE=en_US.819<br />

The connection details about the <strong>Informix</strong> server must be stored in the registry<br />

using the setnet32.exe utility included in Client SDK.<br />

<strong>Informix</strong> OLE DB provider supports all the <strong>Informix</strong> data types, both built-in and<br />

extended.<br />

Table 7-5 lists the mappings between the standard OLE DB data types and<br />

specific <strong>Informix</strong> OLE DB types.<br />

Table 7-5 <strong>Informix</strong> specific type mapping table<br />

222 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong><br />

Enables you to control the data mapping for wide<br />

strings<br />

FBS or FETCHBUFFERSIZE The size in bytes of the buffer size used to send data<br />

to or from the database. Minimum value is 4096,<br />

Maximum 32767. Default is 4096.<br />

<strong>Informix</strong> SQL <strong>Informix</strong> OLE DB Provider<br />

BIGINT DBTYPE_I8<br />

BIGSERIAL DBTYPE_I8<br />

BLOB DBTYPE_BYTES<br />

BOOLEAN DBTYPE_BOOL<br />

BYTE DBTYPE_BYTES<br />

CLOB DBTYPE_STR<br />

DATETIME DBTYPE_DBDATE, DBTYPE_DBTIME,<br />

DBTYPE_DBTIMESTAMP<br />

DECIMAL DBTYPE_NUMERIC<br />

DISTINCT Same as underlying type<br />

FLOAT DBTYPE_R8


<strong>Informix</strong> SQL <strong>Informix</strong> OLE DB Provider<br />

INT8 DBTYPE_I8<br />

INTERVAL DBTYPE_STR if mapped as a string<br />

DBTYPE_Ix (8,4,2 or 1) if mapped as a numeric<br />

LIST DBTYPE_VARIANT<br />

LVARCHAR DBTYPE_STR<br />

MONEY (p


7.3.4 Cursors<br />

<strong>Informix</strong> OLE DB Provider Date and time precision<br />

DBTYPE_DBTIMESTAMP Day to fraction, day to hour, day to minute, and day to<br />

second<br />

Fraction to fraction, hour to fraction, and minute to<br />

fraction<br />

Month to fraction, month to hour, month to minute, and<br />

month to second<br />

Second to fraction<br />

Year to fraction, year to hour, year to minute, and year<br />

to second<br />

For a complete list of all the data type mapping, refer to:<br />

http://publib.boulder.ibm.com/infocenter/idshelp/v115/topic/com.ibm.oledb.doc/u<br />

sing990839.htm#using990839<br />

An ADO application uses cursors to move among the data that returned by a<br />

recordset. ADO defines the following types of cursors:<br />

► Forward-Only (adOpenForwardOnly):<br />

Provides a copy of the records at the time the Recordset was created. This is<br />

the default cursor type of ADO.<br />

► Static (adOpenStatic):<br />

Provides a static copy of the records.<br />

► Dynamic (adOpenDynamic):<br />

Provides a real-time copy of the records, new and altered records by other<br />

users are also included.<br />

► Keyset (adOpenKeyset):<br />

Provides a updateable copy of the records at the time the Recordset was<br />

created. Only existing records are included.<br />

224 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


<strong>Informix</strong> OLE DB Provider supports all these cursor types with some limitations<br />

regarding the use of extended data types and location of the cursor (client or<br />

server side). For example:<br />

► Updates of tables with extended data types are not allowed with client-side<br />

scrollable cursors.<br />

► Server-side scrollable cursors are not supported with simple large objects<br />

(BYTE and TEXT) or collections.<br />

► ROWIDs (internal columns added by the <strong>Informix</strong> server on non fragmented<br />

tables) are required on tables bookmarks and updates.<br />

Refer to the <strong>IBM</strong> <strong>Informix</strong> OLE DB Provider Programmer's Guide for a complete<br />

list of these caveats:<br />

http://publib.boulder.ibm.com/infocenter/idshelp/v115/topic/com.ibm.oledb.doc/s<br />

ii-using-29878.htm#sii-using-29878<br />

7.3.5 Typical database operations<br />

In this section, we provide examples of how to use <strong>Informix</strong> OLE DB Provider to<br />

perform typical database operations against an <strong>Informix</strong> database. We cover<br />

operations such as executing SQL statements, selecting data, and handling<br />

errors from <strong>Informix</strong> OLE DB Provider.<br />

For general information about OLE DB architecture and programming, refer to:<br />

http://msdn.microsoft.com/en-us/library/ms713643%28v=VS.85%29.aspx<br />

Command<br />

You can execute SQL commands using an OLE DB provider through the<br />

ICommand interface.<br />

The application has to perform the following steps to execute an SQL statement:<br />

1. Call QueryInterface for IDBCreateCommand to check if commands are<br />

supported in the session.<br />

2. Call IDBCreateCommand::CreateCommand to create the command.<br />

3. Call ICommandText::SetCommandText to specify the SQL statement for the<br />

command.<br />

4. Call ICommand::Execute to execute the SQL statement.<br />

Chapter 7. Working with <strong>IBM</strong> <strong>Informix</strong> OLE DB Provider 225


Example 7-3 demonstrates how to connect to the database and execute an<br />

UPDATE statement. In this example, we use the following operations and<br />

interfaces:<br />

1. Connect to the database<br />

a. Initialize common property options (prompt, DSN, user, and password).<br />

b. Get an Interface for properties:<br />

InterfacepIDBInitialize->QueryInterface(IID_IDBProperties)<br />

pIDBProperties->SetProperties()<br />

c. Get an Interface for creating session object:<br />

pIDBInitialize->QueryInterface(IID_IDBCreateSession)<br />

d. Create a session object:<br />

pCreateSession->CreateSession()<br />

2. Create a command object:<br />

a. Get an Interface for creating command object:<br />

pSession->QueryInterface(IID_IDBCreateCommand)<br />

b. Create the command object and get ICommandText:<br />

226 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong><br />

Interface:pCreateCommand->CreateCommand()<br />

3. Set the CommandText for the command object:<br />

pCommandText->SetCommandText()<br />

4. Execute the command:<br />

pCommandText->Execute()<br />

5. Clean up.<br />

Example 7-3 The command.cpp sample<br />

#define UNICODE<br />

#define _UNICODE<br />

#include <br />

#include <br />

#include <br />

#include <br />

#include <br />

#include <br />

#include <br />

// CLSID For <strong>IBM</strong>-<strong>Informix</strong> Client Side OLE DB Provider<br />

const GUID CLSID_IFXOLEDBC= {0xa6d00422, 0xfd6c, 0x11d0,<br />

{0x80, 0x43, 0x0, 0xa0, 0xc9, 0xf, 0x1c, 0x59}};<br />

#define CHECK(hr) if (((HRESULT)(hr)) < 0) {printf( "Error"); return(hr);}


int main()<br />

{<br />

HRESULT hr = S_OK;<br />

IDBInitialize *pIDBInitialize;<br />

IDBCreateSession *pCreateSession;<br />

IDBCreateCommand *pCreateCommand;<br />

IUnknown *pSession;<br />

ICommandText *pCommandText;<br />

IDBProperties *pIDBProperties;<br />

DBPROP InitProperties[4];<br />

DBPROPSET rgInitPropSet;<br />

_bstr_t bstrDsnName = "stores_demo@demo_on";<br />

_bstr_t bstrUserName = "informix";<br />

_bstr_t bstrPassWord = "password";<br />

_bstr_t bstrCommand = (WCHAR *) L"UPDATE state SET sname = 'California'<br />

WHERE code = 'CA'";<br />

CoInitialize( NULL );<br />

// Instantiate a data source object<br />

CHECK( hr = CoCreateInstance((REFCLSID) CLSID_IFXOLEDBC, NULL,<br />

CLSCTX_INPROC_SERVER, IID_IDBInitialize, (void **) &pIDBInitialize))<br />

// Set all Properties, Prompt, DSN, User and Password<br />

// Initialize common property options.<br />

for (ULONG i = 0; i < 4; i++ )<br />

{<br />

VariantInit(&InitProperties[i].vValue);<br />

InitProperties[i].dwOptions = DBPROPOPTIONS_REQUIRED;<br />

InitProperties[i].colid = DB_NULLID;<br />

InitProperties[1].vValue.vt = VT_BSTR;<br />

}<br />

InitProperties[0].dwPropertyID = DBPROP_INIT_PROMPT;<br />

InitProperties[0].vValue.vt = VT_I2;<br />

InitProperties[0].vValue.iVal = DBPROMPT_NOPROMPT;<br />

InitProperties[1].dwPropertyID = DBPROP_INIT_DATASOURCE;<br />

InitProperties[1].vValue.bstrVal = bstrDsnName;<br />

InitProperties[2].dwPropertyID = DBPROP_AUTH_USERID;<br />

InitProperties[2].vValue.bstrVal = bstrUserName;<br />

InitProperties[3].dwPropertyID = DBPROP_AUTH_PASSWORD;<br />

InitProperties[3].vValue.bstrVal = bstrPassWord;<br />

rgInitPropSet.guidPropertySet = DBPROPSET_DBINIT;<br />

rgInitPropSet.cProperties = 4;<br />

rgInitPropSet.rgProperties = InitProperties;<br />

// Get initialization properties.Interface<br />

CHECK (hr = pIDBInitialize->QueryInterface(IID_IDBProperties,<br />

(void**) &pIDBProperties))<br />

CHECK(hr = pIDBProperties->SetProperties( 1, &rgInitPropSet))<br />

CHECK( hr = pIDBProperties->Release())<br />

Chapter 7. Working with <strong>IBM</strong> <strong>Informix</strong> OLE DB Provider 227


Connect to the Database Server<br />

CHECK(hr = pIDBInitialize->Initialize())<br />

// Get an Interface for creating Session Object<br />

CHECK( hr = pIDBInitialize->QueryInterface(IID_IDBCreateSession,<br />

(void **) &pCreateSession))<br />

// Create a Session Object<br />

CHECK( hr = pCreateSession->CreateSession(NULL, IID_IUnknown,<br />

(IUnknown **) &pSession))<br />

CHECK( hr = pCreateSession->Release())<br />

// Create Command Object<br />

// Get an Interface for creating Command Object<br />

CHECK( hr = pSession->QueryInterface( IID_IDBCreateCommand,<br />

(void **) &pCreateCommand))<br />

// Create Command Object and get ICommandText Interface<br />

CHECK( hr = pCreateCommand->CreateCommand(NULL, IID_ICommandText,<br />

(IUnknown **) &pCommandText ))<br />

CHECK( hr = pCreateCommand->Release())<br />

// Set the CommandText<br />

CHECK( hr = pCommandText->SetCommandText(DBGUID_DBSQL, bstrCommand))<br />

// Executing the Command<br />

CHECK( hr = pCommandText->Execute( NULL, IID_NULL, NULL, NULL, NULL))<br />

printf( "Row Updated");<br />

// Cleanup<br />

pCommandText->Release();<br />

pCommandText = NULL;<br />

pSession->Release();<br />

pSession = NULL;<br />

pIDBInitialize -> Uninitialize();<br />

pIDBInitialize -> Release();<br />

pIDBInitialize = NULL;<br />

}<br />

CoUninitialize();<br />

return(0);<br />

Example 7-4 describes how to compile and run Example 7-3 on page 226. The<br />

connection string is constructed inside the program. No command line<br />

parameters are passed.<br />

Example 7-4 Output of the command.cpp sample<br />

C:\work>cl /EHsc /nologo command.cpp<br />

command.cpp<br />

C:\work>command<br />

Row Updated<br />

C:\work><br />

228 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Rowset<br />

A rowset is a set of rows, and each row has a number of columns of data.<br />

Rowsets are the main OLE DB objects that are used to expose data from a data<br />

source.<br />

You can create a rowset object with the following methods:<br />

► Explicitly create a rowset by calling IOpenRowset::OpenRowset().<br />

► Execute an SQL statement such as SELECT that returns rows with a<br />

ICommand:Execute method.<br />

► Execute any method that returns a rowset or a schema rowset, for example,<br />

ColumnsRowset::GetColumnsRowset or IDBSchemaRowset::GetRowset.<br />

Example 7-5 demonstrates how to create a rowset object and retrieve metadata<br />

information. The operations and interfaces to initialize the session and connect to<br />

the database are always the same in a OLE DB application. This example also<br />

does the following operations:<br />

1. Connect to the database.<br />

2. Create a Command Object.<br />

3. Create a OpenRowSet Object:<br />

pCreateCommand->QueryInterface(IID_IOpenRowset)<br />

pIOpenRowset->OpenRowset()<br />

4. Obtain access to the IColumnsInfo interface from the rowset object:<br />

pRowset->QueryInterface(IID_IColumnsInfo)<br />

5. Retrieve the Column Information:<br />

pColumnsInfo->GetColumnInfo()<br />

6. Clean up.<br />

Example 7-5 The rowset.cpp sample<br />

#define UNICODE<br />

#define _UNICODE<br />

#include <br />

#include <br />

#include <br />

#include <br />

#include <br />

#include <br />

#include <br />

// CLSID For <strong>IBM</strong>-<strong>Informix</strong> Client Side OLE DB Provider<br />

const GUID CLSID_IFXOLEDBC= {0xa6d00422, 0xfd6c, 0x11d0,<br />

{0x80, 0x43, 0x0, 0xa0, 0xc9, 0xf, 0x1c, 0x59}};<br />

Chapter 7. Working with <strong>IBM</strong> <strong>Informix</strong> OLE DB Provider 229


#define CHECK(hr) if (((HRESULT)(hr)) < 0) {printf( "Error"); return(hr);}<br />

int main()<br />

{<br />

HRESULT hr = S_OK;<br />

IDBInitialize *pIDBInitialize;<br />

IUnknown *pSession;<br />

ITransactionJoin *pITransactionJoin;<br />

ICommandText *pCommandText;<br />

IOpenRowset *pIOpenRowset;<br />

IColumnsInfo *pColumnsInfo;<br />

IDBProperties* pIDBProperties;<br />

DBPROP InitProperties[4];<br />

DBPROPSET rgInitPropSet;<br />

IDBCreateSession *pCreateSession = NULL;<br />

IDBCreateCommand *pCreateCommand = NULL;<br />

IRowset *pRowset = NULL;<br />

DBID TableID;<br />

DBPROPSET rgPropSets[1];<br />

DBCOLUMNINFO *pDBColumnInfo;<br />

WCHAR *pStringsBuffer;<br />

ULONG lNumCols;<br />

int i=0;<br />

_bstr_t bstrDsnName = "stores_demo@demo_on";<br />

_bstr_t bstrUserName = "informix";<br />

_bstr_t bstrPassWord = "password";<br />

_bstr_t TableName = L"customer";<br />

CoInitialize( NULL );<br />

// Instantiate a data source object<br />

CHECK( hr = CoCreateInstance((REFCLSID) CLSID_IFXOLEDBC, NULL,<br />

CLSCTX_INPROC_SERVER, IID_IDBInitialize, (void **) &pIDBInitialize))<br />

// Set all Properties, Prompt, DSN, User and Password<br />

// Initialize common property options.<br />

for (ULONG i = 0; i < 4; i++ )<br />

{<br />

VariantInit(&InitProperties[i].vValue);<br />

InitProperties[i].dwOptions = DBPROPOPTIONS_REQUIRED;<br />

InitProperties[i].colid = DB_NULLID;<br />

InitProperties[1].vValue.vt = VT_BSTR;<br />

}<br />

InitProperties[0].dwPropertyID = DBPROP_INIT_PROMPT;<br />

InitProperties[0].vValue.vt = VT_I2;<br />

InitProperties[0].vValue.iVal = DBPROMPT_NOPROMPT;<br />

InitProperties[1].dwPropertyID = DBPROP_INIT_DATASOURCE;<br />

InitProperties[1].vValue.bstrVal = bstrDsnName;<br />

InitProperties[2].dwPropertyID = DBPROP_AUTH_USERID;<br />

InitProperties[2].vValue.bstrVal = bstrUserName;<br />

230 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


InitProperties[3].dwPropertyID = DBPROP_AUTH_PASSWORD;<br />

InitProperties[3].vValue.bstrVal = bstrPassWord;<br />

rgInitPropSet.guidPropertySet = DBPROPSET_DBINIT;<br />

rgInitPropSet.cProperties = 4;<br />

rgInitPropSet.rgProperties = InitProperties;<br />

// Get initialization properties.Interface<br />

CHECK (hr = pIDBInitialize->QueryInterface(IID_IDBProperties,<br />

(void**) &pIDBProperties))<br />

CHECK(hr = pIDBProperties->SetProperties( 1, &rgInitPropSet))<br />

CHECK( hr = pIDBProperties->Release())<br />

// Connect to the Database Server<br />

CHECK(hr = pIDBInitialize->Initialize())<br />

// Get an Interface for creating Session Object<br />

CHECK( hr = pIDBInitialize->QueryInterface(IID_IDBCreateSession,<br />

(void **) &pCreateSession))<br />

// Create a Session Object<br />

CHECK( hr = pCreateSession->CreateSession(NULL, IID_IUnknown,<br />

(IUnknown **) &pSession))<br />

CHECK( hr = pCreateSession->Release())<br />

// Create Command Object<br />

// Get an Interface for creating Command Object<br />

CHECK( hr = pSession->QueryInterface( IID_IDBCreateCommand,<br />

(void **) &pCreateCommand))<br />

// Create Command Object and get ICommandText Interface<br />

CHECK( hr = pCreateCommand->CreateCommand(NULL, IID_ICommandText,<br />

(IUnknown **) &pCommandText ))<br />

CHECK( hr = pCreateCommand->Release())<br />

// Create a OpenRowSet<br />

CHECK( hr = pCreateCommand->QueryInterface( IID_IOpenRowset,<br />

(void **)&pIOpenRowset ))<br />

TableID.eKind = DBKIND_NAME;<br />

TableID.uName.pwszName = TableName;<br />

))<br />

CHECK( hr = pIOpenRowset->OpenRowset( NULL, &TableID, NULL, IID_IRowset,<br />

0, rgPropSets, (IUnknown **)&pRowset<br />

// Obtain access to the IColumnsInfo inteface, from the Rowset object<br />

CHECK( hr = pRowset->QueryInterface(IID_IColumnsInfo, (void ** )<br />

&pColumnsInfo))<br />

// Retrieve the Column Information<br />

CHECK( hr = pColumnsInfo->GetColumnInfo( &lNumCols, &pDBColumnInfo,<br />

&pStringsBuffer))<br />

wprintf( L"\nTable : %s\nColumns :%d\nName\t\tType\tLength",<br />

TableID.uName.pwszName, lNumCols);<br />

for ( i=0; i


}<br />

232 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong><br />

wprintf( L"\n%s\t%d\t%ld", (pDBColumnInfo+i)->pwszName,<br />

(pDBColumnInfo+i)->wType, (pDBColumnInfo+i)->ulColumnSize);<br />

// Free the Column Information Interface<br />

CHECK( (hr = pColumnsInfo->Release()))<br />

// Cleanup<br />

pCommandText->Release();<br />

pCommandText = NULL;<br />

pSession->Release();<br />

pSession = NULL;<br />

pIDBInitialize -> Uninitialize();<br />

pIDBInitialize -> Release();<br />

pIDBInitialize = NULL;<br />

}<br />

CoUninitialize();<br />

return(0);<br />

Example 7-6 shows the name, type, and length columns of the customer table.<br />

Example 7-6 Output of the rowset.cpp sample<br />

C:\work>cl /EHsc /nologo rowset.cpp<br />

rowset.cpp<br />

C:\work>rowset<br />

Table : customer<br />

Columns :7<br />

Name Type Length<br />

customer_num 3 4<br />

customer_type 129 1<br />

customer_name 129 32767<br />

customer_loc 3 4<br />

contact_dates 129 32767<br />

cust_discount 131 19<br />

credit_status 129 1<br />

C:\work><br />

Large objects<br />

Large objects (simple and smart) do not require any special handling when using<br />

<strong>Informix</strong> OLE DB Provider.<br />

Smart large objects (BLOB and TEXT) support the ADO GetChunk() and<br />

AppendChunk() methods.


Example 7-7 demonstrates how to retrieve a CLOB column using the GetChunk()<br />

method from the ADO library in C++. This example fetches the first three rows of<br />

the catalog table from the sample stores_demo database and displays the data<br />

for the catalog_number and advert_descr columns.<br />

Example 7-7 The select.cpp sample<br />

#include <br />

#include <br />

#import "c:\program files\common files\system\ado\msado15.dll" rename<br />

("EOF","adoEOF") no_namespace<br />

#define CREATEiNSTANCE(sp,riid) { HRESULT _hr =sp .CreateInstance( __uuidof( riid<br />

) ); \<br />

if (FAILED(_hr)) _com_issue_error(_hr); }<br />

#define RsITEM(rs,x) rs->Fields->Item[_variant_t(x)]->Value<br />

#define UC (char *)<br />

struct InitOle {<br />

InitOle() { ::CoInitialize(NULL); }<br />

~InitOle() { ::CoUninitialize(); }<br />

} _init_InitOle_;<br />

void main(){<br />

_RecordsetPtr spRS;<br />

_ConnectionPtr spCON;<br />

_variant_t varBLOB;<br />

long lDataLength = 0;<br />

int nrows=3;<br />

try{<br />

CREATEiNSTANCE(spCON,Connection);<br />

spCON->Provider="ifxoledbc";<br />

spCON->ConnectionString = L"Data Source=stores_demo@demo_on;"<br />

L"User ID=informix; Password=password;";<br />

// Connect to the database<br />

spCON->Open( "", "", "", -1 );<br />

CREATEiNSTANCE(spRS,Recordset)<br />

spRS->PutRefActiveConnection( spCON );<br />

spRS->Open(_bstr_t("catalog"),vtMissing, adOpenForwardOnly,<br />

adLockOptimistic,adCmdTable);<br />

while( (spRS->adoEOF == false) && nrows>0 ){<br />

nrows--;<br />

printf("catalog_num = %s\n", UC _bstr_t(RsITEM(spRS,"catalog_num")));<br />

// Get the size of the large object<br />

lDataLength = spRS->Fields->Item["advert_descr"]->ActualSize;<br />

Chapter 7. Working with <strong>IBM</strong> <strong>Informix</strong> OLE DB Provider 233


if(lDataLength > 0) {<br />

// Call GetChunk to retrieve the Blob data<br />

VariantInit(&varBLOB);<br />

varBLOB = spRS->Fields->Item["advert_descr"]->GetChunk(lDataLength);<br />

printf("advert_descr = %s\n", UC _bstr_t(varBLOB));<br />

}<br />

// Move the cursor to the next row<br />

spRS->MoveNext();<br />

}<br />

spRS->Close();<br />

spCON->Close();<br />

}<br />

catch( _com_error &e){<br />

_bstr_t bstrSource(e.Source());<br />

_bstr_t bs = _bstr_t(" Error: ") + _bstr_t(e.Error()) +<br />

_bstr_t(" Msg: ") + _bstr_t(e.ErrorMessage()) +<br />

_bstr_t(" Description: ") + _bstr_t(e.Description());<br />

printf("Error %s\n", bs);<br />

}<br />

}<br />

#undef UC<br />

Example 7-8 shows the content of the output.<br />

Example 7-8 Output of the select.cpp sample<br />

C:\work>cl /EHsc /nologo select.cpp /DWINVER=0x0600<br />

select.cpp<br />

C:\work>select<br />

catalog_num = 10001<br />

advert_descr = Brown leather. Specify first baseman's or infield/outfield<br />

style. Specify right- or left-handed.<br />

catalog_num = 10002<br />

catalog_num = 10003<br />

C:\work><br />

Errors<br />

<strong>Informix</strong> OLE DB Provider supports the ISupportErrorInfo interface.<br />

Applications can retrieve information about an OLE DB error using this interface.<br />

Methods such as IErrorRecords->GetErrorInfo(),<br />

IErrorInfo->GetDescription() and IErrorInfo->GetSource() are fully<br />

supported by <strong>Informix</strong> OLE DB Provider.<br />

234 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Example 7-9 illustrates how to use these methods. This example retrieves the<br />

error information directly after the IDBInitialize->Initialize() function call.<br />

Because error handling should be done after every use of an interface function, it<br />

is a good practice to create an error handle routine to avoid code redundancy.<br />

Example 7-9 The errorinfo.cpp sample<br />

#define UNICODE<br />

#define _UNICODE<br />

#include <br />

#include <br />

#include <br />

#include <br />

#include <br />

#include <br />

#include <br />

// CLSID For <strong>IBM</strong>-<strong>Informix</strong> Client Side OLE DB Provider<br />

const GUID CLSID_IFXOLEDBC= {0xa6d00422, 0xfd6c, 0x11d0,<br />

{0x80, 0x43, 0x0, 0xa0, 0xc9, 0xf, 0x1c, 0x59}};<br />

#define CHECK(hr) if (((HRESULT)(hr)) < 0) {printf( "Error"); return(hr);}<br />

HRESULT GetDetailedErrorInfo(<br />

HRESULThresult,<br />

IUnknown *pBadObject,<br />

GUID IID_BadIntereface);<br />

int main()<br />

{<br />

HRESULT hr = S_OK;<br />

IDBInitialize *pIDBInitialize;<br />

IUnknown *pSession;<br />

IDBProperties* pIDBProperties;<br />

DBPROP InitProperties[4];<br />

DBPROPSET rgInitPropSet;<br />

IDBCreateSession *pCreateSession = NULL;<br />

IErrorInfo *pErrorInfo = NULL;<br />

IErrorInfo *pErrorInfoRec = NULL;<br />

IErrorRecords *pErrorRecords = NULL;<br />

ISupportErrorInfo *pSupportErrorInfo = NULL;<br />

ULONG i,ulNumErrorRecs;<br />

BSTR bstrDescriptionOfError = NULL;<br />

BSTR bstrSourceOfError = NULL;<br />

_bstr_t bstrDsnName = "wrong_db@demo_on"; // WRONG DATABASE<br />

_bstr_t bstrUserName = "informix";<br />

Chapter 7. Working with <strong>IBM</strong> <strong>Informix</strong> OLE DB Provider 235


_bstr_t bstrPassWord = "password";<br />

CoInitialize( NULL );<br />

// Instantiate a data source object<br />

CHECK( hr = CoCreateInstance((REFCLSID) CLSID_IFXOLEDBC, NULL,<br />

CLSCTX_INPROC_SERVER, IID_IDBInitialize, (void **) &pIDBInitialize))<br />

// Set all Properties, Prompt, DSN, User and Password<br />

// Initialize common property options.<br />

for (ULONG i = 0; i < 4; i++ )<br />

{<br />

VariantInit(&InitProperties[i].vValue);<br />

InitProperties[i].dwOptions = DBPROPOPTIONS_REQUIRED;<br />

InitProperties[i].colid = DB_NULLID;<br />

InitProperties[1].vValue.vt = VT_BSTR;<br />

}<br />

InitProperties[0].dwPropertyID = DBPROP_INIT_PROMPT;<br />

InitProperties[0].vValue.vt = VT_I2;<br />

InitProperties[0].vValue.iVal = DBPROMPT_NOPROMPT;<br />

InitProperties[1].dwPropertyID = DBPROP_INIT_DATASOURCE;<br />

InitProperties[1].vValue.bstrVal = bstrDsnName;<br />

InitProperties[2].dwPropertyID = DBPROP_AUTH_USERID;<br />

InitProperties[2].vValue.bstrVal = bstrUserName;<br />

InitProperties[3].dwPropertyID = DBPROP_AUTH_PASSWORD;<br />

InitProperties[3].vValue.bstrVal = bstrPassWord;<br />

rgInitPropSet.guidPropertySet = DBPROPSET_DBINIT;<br />

rgInitPropSet.cProperties = 4;<br />

rgInitPropSet.rgProperties = InitProperties;<br />

// Get initialization properties.Interface<br />

CHECK (hr = pIDBInitialize->QueryInterface(IID_IDBProperties,<br />

(void**) &pIDBProperties))<br />

CHECK(hr = pIDBProperties->SetProperties( 1, &rgInitPropSet))<br />

CHECK( hr = pIDBProperties->Release())<br />

// Connect to the Database Server<br />

hr = pIDBInitialize->Initialize();<br />

if (hr < 0) {<br />

pIDBInitialize->QueryInterface(IID_ISupportErrorInfo,<br />

(LPVOID FAR*)&pSupportErrorInfo);<br />

pSupportErrorInfo->InterfaceSupportsErrorInfo(__uuidof(pIDBInitialize));<br />

GetErrorInfo(0,&pErrorInfo);<br />

//Get the IErrorRecord interface and get the count of error recs.<br />

pErrorInfo->QueryInterface(IID_IErrorRecords,(LPVOID FAR*)&pErrorRecords);<br />

pErrorRecords->GetRecordCount(&ulNumErrorRecs);<br />

//Get the error record, (we only get the first one)<br />

pErrorRecords->GetErrorInfo(0, GetUserDefaultLCID(), &pErrorInfoRec);<br />

pErrorInfoRec->GetDescription(&bstrDescriptionOfError);<br />

236 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


pErrorInfoRec->GetSource(&bstrSourceOfError);<br />

printf("ERROR!\nResult of 0x%0x (%ld) returned\n",(long)hr,(long)hr);<br />

printf("Error Source: %S\n",bstrSourceOfError);<br />

printf("Error Description: %S\n", bstrDescriptionOfError);<br />

pErrorInfo->Release();<br />

pErrorRecords->Release();<br />

pSupportErrorInfo->Release();<br />

pErrorInfoRec->Release();<br />

SysFreeString(bstrSourceOfError);<br />

SysFreeString(bstrDescriptionOfError);<br />

} // if<br />

/* ... some useful code here .... */<br />

}<br />

pIDBInitialize -> Uninitialize();<br />

pIDBInitialize -> Release();<br />

pIDBInitialize = NULL;<br />

CoUninitialize();<br />

return(0);<br />

Example 7-10 shows the output of Example 7-9 on page 235. We use a<br />

non-existent database for the connection. An error is expected during<br />

initialization.<br />

Example 7-10 Output of the errorinfo.cpp sample<br />

C:\work>cl /EHsc /nologo errorinfo.cpp<br />

errorinfo.cpp<br />

C:\work>errorinfo<br />

ERROR!<br />

Result of 0x80004005 (-2147467259) returned<br />

Error Source: Ifxoledbc<br />

Error Description: EIX000: (-329) Database not found or no system permission.<br />

C:\work><br />

7.4 Visual Basic, ADO.NET, and SQL Server<br />

ActiveX and COM objects are a core component of any Windows operating<br />

system. For this reason, OLE DB providers are used extensively by many<br />

Windows applications. In this section, we describe how to use <strong>Informix</strong> OLE DB<br />

Chapter 7. Working with <strong>IBM</strong> <strong>Informix</strong> OLE DB Provider 237


Provider with some of the available Microsoft technologies and applications, such<br />

as ADO.NET or Microsoft SQL Server.<br />

7.4.1 OLE DB with Visual Basic<br />

Visual Basic (VB) is a programming language developed by Microsoft that<br />

focuses on the use of COM objects. Visual Basic is design to be easy to learn<br />

and to allow the development of database applications with far less effort than C<br />

or C++ languages. ADO and <strong>Informix</strong> OLE DB Provider are widely used with<br />

Visual Basic.<br />

In this section, we demonstrate how to use <strong>Informix</strong> OLE DB Provider to access<br />

an <strong>Informix</strong> database using a VBScript that is based on Visual Basic.<br />

Select data<br />

Example 7-11 shows how to query the state table using a recordset with a<br />

VBScript file. We open the recordset using a static server cursor (adUseServer=2<br />

and adOpenStatic=3).<br />

Example 7-11 The select.vbs script<br />

' Create the ADO objects<br />

set cx=createobject("ADODB.Connection")<br />

set cr=createobject("ADODB.Recordset")<br />

' Set the connection string<br />

cx.provider="Ifxoledbc"<br />

cx.connectionstring="Data Source=stores_demo@demo_on;"<br />

' Open the Connection<br />

cx.open<br />

set cr.activeconnection=cx<br />

cr.cursorlocation=2<br />

' Open the Recordset<br />

cr.open "SELECT * FROM state WHERE code='CA'", cx, 2, 3<br />

WScript.Echo cr.fields("sname")<br />

Example 7-12 shows the output of the this script.<br />

Example 7-12 Output of the select.vbs script<br />

c:\work>select.vbs<br />

California<br />

c:\work><br />

238 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Comparing this example with Example 7-5 on page 229, which is written on C++,<br />

shows how easy it is to use OLE DB with Visual Basic.<br />

Example 7-13 demonstrates how to scroll through a recordset.<br />

Example 7-13 The scroll.vbs script<br />

' Create the ADO objects<br />

set cx=createobject("ADODB.Connection")<br />

set cr=createobject("ADODB.Recordset")<br />

set cm=createobject("ADODB.Command")<br />

' Set the connection string<br />

cx.provider = "Ifxoledbc.2"<br />

cx.Open "Data Source=stores_demo@demo_on"<br />

' Set the Command SQL text<br />

cm.ActiveConnection = cx<br />

cm.CommandText = "SELECT * FROM state"<br />

' Open the cursor<br />

cr.CursorLocation = 3 ‘ adUseClient<br />

cr.Open cm<br />

WScript.Echo "First row: " & cr.fields("sname")<br />

' Scroll to the last element in the recordset<br />

cr.MoveLast<br />

WScript.Echo "Last row : " & cr.fields("sname")<br />

We use the MoveLast() method to position the cursor in the last record, as shown<br />

in the output in Example 7-14.<br />

Example 7-14 Output of the scroll.vbs script<br />

c:\work>scroll.vbs<br />

First row: Alaska<br />

Last row : Puerto Rico<br />

c:\work><br />

Add new data<br />

Example 7-15 demonstrate how to add a new record to a table using the<br />

AddNew() method. After adding a new record to the table, the code opens a<br />

cursor and positions it at the end of the recordset to retrieve the last inserted row.<br />

Example 7-15 The addnew.vbs script<br />

' Create the ADO objects<br />

set cx = CreateObject("ADODB.Connection")<br />

set cr = CreateObject("ADODB.Recordset")<br />

' Set the connection string<br />

cx.provider = "Ifxoledbc"<br />

Chapter 7. Working with <strong>IBM</strong> <strong>Informix</strong> OLE DB Provider 239


cx.connectionstring = "Data Source=stores_demo@demo_on;"<br />

cx.Open<br />

Set cr.activeconnection = cx<br />

' Open the recordset<br />

cr.Open "SELECT * FROM state", cx, 3, 2<br />

' Add a new record to the recordset<br />

cr.AddNew<br />

cr.fields("code") = "UN"<br />

cr.fields("sname") = "Unkown"<br />

cr.fields("sales_tax") = "0.0"<br />

' Update the database table<br />

cr.Update<br />

cr.Close<br />

' Retrieve the new inserterd row<br />

cr.open "SELECT * FROM state", cx, 3, 3<br />

cr.MoveLast<br />

WScript.Echo cr.fields("sname")<br />

Example 7-16 shows the value of the sname column after the update operation.<br />

Example 7-16 Output of the addnew.vbs script<br />

c:\work>addnew.vbs<br />

Unkown<br />

c:\work><br />

7.4.2 ADO.NET and the OLEDB bridge<br />

In addition to ADO, developers can also use <strong>Informix</strong> OLE DB Provider with<br />

ADO.NET. Similar to ADO but within the .NET Framework, ADO.NET is a set of<br />

.NET components that are used to retrieve, manipulate, and update data from a<br />

data source.<br />

One of the .NET data providers that is included with ADO.NET is the Microsoft<br />

OLE DB Provider for .NET. This .NET provider acts as bridge between the .NET<br />

framework and standard OLE DB providers so that developers can use .NET<br />

technology with a database server, even if there is no specific .NET data provider<br />

for that particular database.<br />

<strong>IBM</strong> has specific .NET providers to access an <strong>Informix</strong> database:<br />

► <strong>IBM</strong> <strong>Informix</strong> .NET Provider<br />

► <strong>IBM</strong> Data Server Provider for .NET<br />

However, developers can use <strong>Informix</strong> OLE DB Provider through the Microsoft<br />

OLE DB .NET Provider.<br />

240 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Example 7-17 demonstrates how to use <strong>Informix</strong> OLE DB Provider with a .NET<br />

application. The connection string for <strong>Informix</strong> OLE DB Provider is the same.<br />

Refer 7.3.2, “Connecting to database” on page 221 for the complete syntax.<br />

Example 7-17 The getoledb.cs sample<br />

using System;<br />

using System.Data;<br />

using System.Data.OleDb;<br />

class sample {<br />

static void Main(string[] args) {<br />

OleDbConnection con = new OleDbConnection();<br />

con.ConnectionString = "Provider=Ifxoledbc;"<br />

+" Data Source=stores_demo@demo_on; User ID=informix;"<br />

+" Password=password";<br />

DataSet ds = new DataSet();<br />

string sql = "SELECT first 3 * FROM STATE";<br />

OleDbDataAdapter da = new OleDbDataAdapter(sql,con);<br />

da.Fill(ds,"state");<br />

foreach(DataRow dr in ds.Tables[0].Rows) {<br />

Console.WriteLine(dr["code"]);<br />

Console.WriteLine(dr["sname"]);<br />

Console.WriteLine(dr["sales_tax"]);<br />

}<br />

con.Close();<br />

con.Dispose();<br />

}<br />

}<br />

Example 7-18 demonstrates how to compile and run this .NET example.<br />

Example 7-18 Output of the getoledb.cs sample<br />

c:\work>csc.exe /nologo getoledb.cs<br />

c:\work>getoledb<br />

AK<br />

Alaska<br />

0.00000<br />

HI<br />

Hawaii<br />

0.04000<br />

CA<br />

Chapter 7. Working with <strong>IBM</strong> <strong>Informix</strong> OLE DB Provider 241


California<br />

0.08250<br />

c:\work><br />

7.4.3 SQL Server<br />

Using <strong>Informix</strong> OLE DB Provider, you can select data from an <strong>Informix</strong> database<br />

directly from Microsoft SQL Server.<br />

SQL Server uses OLE DB to create linked servers and to retrieve data from any<br />

OLE DB data source.<br />

There are no specific steps to configure or to use <strong>Informix</strong> OLE DB Provider with<br />

SQL Server as a linked server. If <strong>Informix</strong> OLE DB Provider is installed and<br />

configured correctly, SQL Server can use it to connect to an <strong>IBM</strong> <strong>Informix</strong><br />

database server.<br />

We describe how to set up a linked server using the <strong>Informix</strong> provider in this<br />

section.<br />

242 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Figure 7-1 shows the New Linked Server dialog box where you set the<br />

connection details for <strong>Informix</strong> OLE DB Provider.<br />

Figure 7-1 New Linked Server dialog box<br />

In this dialog box, set the following fields:<br />

► Linked server: Specify the name for the SQL Server to link.<br />

► Provider: Choose <strong>IBM</strong> <strong>Informix</strong> OLE DB Provider from the drop-down list.<br />

► Product name: Specify the name of the <strong>Informix</strong> provider, which in this<br />

example is ifxoledbc.<br />

► Data source: Specify the name of the data source as database@server.<br />

► Provider string: Specify any additional connection string parameters that the<br />

provider uses.<br />

Chapter 7. Working with <strong>IBM</strong> <strong>Informix</strong> OLE DB Provider 243


The user ID for the <strong>Informix</strong> database server might differ from the one that is<br />

used with SQL Server. If so, you need to set a remote user mapping. Figure 7-2<br />

shows a user mapping between the sa and informix users.<br />

Figure 7-2 Linked Server Properties: Security options<br />

You can also create linked servers using only SQL statements. Example 7-19<br />

illustrates how to create a linked server to connect to the demo_on <strong>Informix</strong><br />

instance. We use the same connection details shown in Figure 7-1 on page 243.<br />

Example 7-19 Linked Server SQL script<br />

EXEC master.dbo.sp_addlinkedserver<br />

@server = N'demo_on',<br />

@srvproduct=N'ifxoledbc',<br />

@provider=N'ifxoledbc',<br />

@datasrc=N'stores7@demo_on',<br />

@provstr=N''<br />

EXEC sp_addlinkedsrvlogin 'demo_on',false,'sa','informix','password'<br />

SELECT * FROM demo_on.stores7.informix.customer<br />

244 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


The last SQL statement in the script uses the linked server to retrieve the data<br />

from the customer table:<br />

SELECT * FROM demo_on.stores7.informix.customer<br />

For more information about linked servers, refer to:<br />

http://msdn.microsoft.com/en-us/library/ms188279.aspx<br />

7.5 Troubleshooting and tracing<br />

7.5.1 Typical errors<br />

In this section, we discuss typical errors that can occur when using <strong>Informix</strong> OLE<br />

DB Provider and how to enable the tracing facility to collect diagnostic<br />

information.<br />

Most errors encountered when using <strong>Informix</strong> OLE DB Provider are due to an<br />

incorrect setup or an invalid connection string passed to the provider.<br />

<strong>Informix</strong> OLE DB Provider uses the same connectivity libraries as other<br />

components of Client SDK. It also uses the information that is stored in the<br />

registry through the setnet32.exe utility for the database server connection.<br />

It is always a good practice to test this basic connectivity using the iLogin utility<br />

that is included in the Client SDK directory.<br />

Provider not found<br />

Here, we explain the reason and the solution for a “Provider not found” error.<br />

Reason<br />

This error appears if the Windows operating system fails to locate the OLE DB<br />

provider class that is specified by the application.<br />

Solution<br />

During the installation of Client SDK, the OLE DB provider is registered<br />

automatically within the Windows registry. You can register <strong>Informix</strong> OLE DB<br />

Provider manually using the regsvr32 utility as follows:<br />

regsvr32.exe %INFORMIXDIR%\bin\ifxoledbc.dll<br />

If you are running a 64-bit version of Windows, make sure that you register the<br />

provider using the correct version of the regsvr32 binary. Otherwise, it can<br />

Chapter 7. Working with <strong>IBM</strong> <strong>Informix</strong> OLE DB Provider 245


happen that the 32-bit provider is registered as a 64-bit provider (or vice versa)<br />

and the Windows operating system will fail to find and load the provider.<br />

You can verify that the provider library is registered correctly by examining the<br />

Windows registry. Example 7-20 shows the registry entry for 32-bit and 64-bit<br />

<strong>Informix</strong> OLE DB Provider. Remember that the name of the <strong>Informix</strong> provider is<br />

ifxoledbc.<br />

Example 7-20 <strong>Informix</strong> OLE DB registry keys<br />

C:\work>c:\windows\syswow64\reg query<br />

"HKEY_CLASSES_ROOT\CLSID\{A6D00422-FD6C-11D0-8043-00A0C90F1C59}\InprocServer32"<br />

HKEY_CLASSES_ROOT\CLSID\{A6D00422-FD6C-11D0-8043-00A0C90F1C59}\InprocServer32<br />

(Default) REG_SZ C:\Program Files<br />

(x86)\<strong>IBM</strong>\<strong>Informix</strong>\Client-SDK\bin\ifxoledbc.dll<br />

ThreadingModel REG_SZ Both<br />

C:\work>c:\windows\system32\reg query<br />

"HKEY_CLASSES_ROOT\CLSID\{A6D00422-FD6C-11D0-8043-00A0C90F1C59}\InprocServer32"<br />

HKEY_CLASSES_ROOT\CLSID\{A6D00422-FD6C-11D0-8043-00A0C90F1C59}\InprocServer32<br />

(Default) REG_SZ C:\Program<br />

Files\<strong>IBM</strong>\<strong>Informix</strong>\Client-SDK\bin\ifxoledbc.dll<br />

ThreadingModel REG_SZ Both<br />

C:\work><br />

Failed to load the Ifxoledbc.dll<br />

Here, we explain the reason and the solution for a “Failed to load the<br />

Ifxoledbc.dll” error.<br />

Reason<br />

The application fails to load <strong>Informix</strong> OLE DB Provider or one of its libraries.<br />

Solution<br />

The value of INFORMIXDIR (as a environment variable or in the registry) should<br />

be the directory where Client SDK is installed. Ensure that the environment<br />

variable PATH contains the %INFORMIXDIR%\bin directory. For example:<br />

PATH=C:\Program Files\<strong>IBM</strong>\<strong>Informix</strong>\Client-SDK\bin;%PATH%<br />

When an application loads <strong>Informix</strong> OLE DB Provider, Client SDK libraries that<br />

the provider needs for communication and registry access are loaded from the<br />

directory that is used in the registration process.<br />

246 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


On 64-bit version of Windows operating system, ensure that the PATH and<br />

INFORMIXDIR variables are set correctly for all users. Some applications, such<br />

as SQL Server, are executed under credentials that are different than the logged<br />

user and that can have different settings for this variables.<br />

Failed to connect to the database<br />

Here, we explain the reason and the solution for a “Failed to connect to the<br />

database” error.<br />

Reason<br />

The most common reason for this type of error is due to invalid parameters in the<br />

connection string or invalid connectivity information.<br />

Solution<br />

If the application is getting an <strong>Informix</strong> OLE DB error, it has managed to load<br />

<strong>Informix</strong> OLE DB Provider, but it is failing during connection.<br />

For any connection error, always ensure that the basic connectivity works.<br />

Testing whether the client system has access to the database using the iLogin<br />

utility can help to narrow the problem.<br />

If iLogin fails, verify that the connection parameters for the database (server<br />

name, port number, host name, and so on) are correct. Use the setnet32.exe<br />

utility to verify that the information stored in the registry is valid.<br />

The user credentials (user ID and password) can also be set in the registry using<br />

the setnet32.exe utility. Verify that both the user ID and password are valid.<br />

The majority of the connection string parameters must be included exactly as<br />

they appear in Table 7-4 on page 221. Invalid parameters are ignored and can<br />

cause an error connection. See Table 7-7 for examples of valid parameters.<br />

Table 7-7 Valid parameters<br />

Valid Invalid<br />

Data Source DataSource, DSN<br />

User ID UserID, UID<br />

Password PWD<br />

If you are using GLS variables (Client_Locale or Db_locale), make sure that<br />

they are set correctly. If you do not use UNICODE, the code set part of<br />

Client_Locale should be the same as your operating system. Db_Locale should<br />

be your database locale.<br />

Chapter 7. Working with <strong>IBM</strong> <strong>Informix</strong> OLE DB Provider 247


7.5.2 Tracing<br />

Failure when handling database data<br />

Here, we explain the reason and the solution for a “Failed when handling<br />

database data” error.<br />

Reason<br />

These types of errors are caused by using the wrong data type when accessing<br />

<strong>Informix</strong> tables.<br />

Solution<br />

<strong>Informix</strong> OLE DB Provider requires additional functions and tables in the<br />

sysmaster database to handle <strong>Informix</strong> data types correctly. These objects are<br />

created when running the coledbp.sql SQL script.<br />

This script is located in the %INFORMIXDIR%\etc directory, and must be executed<br />

against the sysmaster database as the informix user.<br />

If you are upgrading from an older version of Client SDK, remove these objects<br />

by running the doledbp.sql script from the old client before using the new<br />

coledbp.sql script.<br />

Tracing is useful when diagnosing application problems such as SQL errors or<br />

unexpected behaviors and can even be used for performance analysis.<br />

A developer can set the following types of tracing when using <strong>Informix</strong> OLE DB<br />

Provider:<br />

► <strong>Informix</strong> OLE DB Trace<br />

► SQLIDEBUG<br />

<strong>Informix</strong> OLE DB Trace<br />

<strong>Informix</strong> OLE DB Trace is specific to <strong>Informix</strong> OLE DB Provider. You can set the<br />

IFXOLEDBCTRACE environment variable to point to the location of the trace file,<br />

for example:<br />

IFXOLEDBCTRACE=oledbtrace.txt<br />

The trace file that is generated contains the calls to all the OLE DB interfaces that<br />

the provider uses.<br />

Example 7-21 shows a typical <strong>Informix</strong> OLE DB trace file.<br />

Example 7-21 OLE DB trace<br />

Wed Jun 30 13:59:01 2010<br />

248 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


A44: 53C Enter Clsfact::QueryInterface<br />

Object Address: 0x032C2CB8<br />

A44: 53C Enter Clsfact::AddRef<br />

Object Address: 0x032C2CB8<br />

A44: 53C Exit Object Address: 0x032C2CB8 hr=2<br />

qi: 032C2CB8 (pif 032C2CB8)<br />

A44: 53C Enter Clsfact::Release<br />

Object Address: 0x032C2CB8<br />

A44: 53C Exit Object Address: 0x032C2CB8 hr=1<br />

A44: 53C Enter Clsfact::AddRef<br />

Object Address: 0x032C2CB8<br />

A44: 53C Exit Object Address: 0x032C2CB8 hr=2<br />

A44: 53C Enter Clsfact::Release<br />

Object Address: 0x032C2CB8<br />

A44: 53C Exit Object Address: 0x032C2CB8 hr=1<br />

A44: 53C Enter Clsfact::QueryInterface<br />

Object Address: 0x032C2CB8<br />

A44: 53C Enter Clsfact::AddRef<br />

Object Address: 0x032C2CB8<br />

A44: 53C Exit Object Address: 0x032C2CB8 hr=2<br />

...<br />

In addition to the OLE DB interfaces, the trace facility collects the return value for<br />

any method that is used during the OLE DB session, as shown in Example 7-22.<br />

Example 7-22 Entry and exit points OLE DB trace<br />

A44: 53C Enter Datasrc::QueryInterface<br />

A44: 53C Enter Datasrc::QueryInterface<br />

A44: 53C Enter Datasrc::AddRef<br />

A44: 53C Exit Object Address: 0x032CC370 hr=2<br />

A44: 53C Enter Datasrc::Release<br />

A44: 53C Exit Object Address: 0x032CC370 hr=1<br />

A44: 53C Enter Datasrc::QueryInterface<br />

A44: 53C Enter Datasrc::XIDBProperties::SetProperties<br />

A44: 53C Exit Object Address: 0x032CC38C hr=0<br />

A44: 53C Enter Datasrc::QueryInterface<br />

A44: 53C Enter Datasrc::XIDBProperties::SetProperties<br />

A44: 53C Exit Object Address: 0x032CC38C hr=0<br />

A44: 53C Enter Datasrc::QueryInterface<br />

A44: 53C Enter Datasrc::XIDBInitialize::Initialize<br />

A44: 53C Exit Object Address: 0x032CC384 hr=0<br />

A44: 53C Enter Datasrc::QueryInterface<br />

A44: 53C Enter Datasrc::XIDBProperties::GetProperties<br />

Chapter 7. Working with <strong>IBM</strong> <strong>Informix</strong> OLE DB Provider 249


A44: 53C Exit Object Address: 0x032CC38C hr=0<br />

A44: 53C Enter Datasrc::QueryInterface<br />

A44: 53C Enter Datasrc::XIDBCreateSession::CreateSession<br />

SQLIDEBUG<br />

SQLI is the communication protocol used by Client SDK. SQLIDEBUG is a trace<br />

facility of all the messages between an <strong>Informix</strong> client and an <strong>Informix</strong> database<br />

server. This trace is common to all the Client SDK components (ESQL/C, ODBC,<br />

OLE DB, and so on).<br />

You can find a description and how to enable SQLIDEBUG in 3.3.6,<br />

“Troubleshooting” on page 117.<br />

When diagnosing a performance problem, sometimes it is useful to collect an<br />

SQLIDEBUG trace to have an idea of where the delay occurs. Using the summary<br />

option when processing the SQLIDEBUG file with sqliprint produces a detailed<br />

description of all the messages between the client and server, as shown in<br />

Example 7-23.<br />

Example 7-23 Sqliprint summary output<br />

>>>>>>>>>>>>>>>>>> SUMMARY INFORMATION >>>>CLIENT ELAPSED CLOCK TIME (sec): 0.047000<br />

>>>>>>>>>>SERVER+NETWORK CLOCK TIME (sec): 0.000000<br />

FROM C->S<br />

Msg occured Total Avg Min Max<br />

------------------------------------------------------------------<br />

SQ_PREPARE 1 0.000000 0.000000 0.000000 0.000000<br />

SQ_ID 4<br />

SQ_CLOSE 1<br />

SQ_RELEASE 2<br />

SQ_EOT 7<br />

SQ_NDESCRIBE 1<br />

SQ_SFETCH 1 0.000000 0.000000 0.000000 0.000000<br />

SQ_WANTDONE 1<br />

SQ_EXIT 1<br />

SQ_INFO 1<br />

SQ_RET_TYPE 1<br />

SQ_INTERNALVER 1<br />

SQ_PROTOCOLS 1<br />

------------------------------------------------------------------<br />

FROM S->C<br />

Msg occured Total Avg Min Max<br />

------------------------------------------------------------------<br />

250 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


UNKNOWN 1<br />

SQ_DESCRIBE 1 0.000000 0.000000 0.000000 0.000000<br />

SQ_EOT 6<br />

SQ_TUPLE 1<br />

SQ_TUPID 1<br />

SQ_PROTOCOLS 1<br />

------------------------------------------------------------------<br />

=======================================================================<br />

COMMAND TEXT INFORMATION (first 99 are listed)<br />

a( b) CMD[##]= ' first 60 bytes of cmd text '<br />

where a = 'P'repare, or 'N'ot prepared, and b = length of command string<br />

-----------------------------------------------------------------------<br />

P( 28) CMD[ 0]='SELECT rowid, * FROM state;'<br />

-----------------------------------------------------------------------<br />

=======================================================================<br />

Fetch Array feature not used<br />

OPTOFC feture not used<br />

Number of open/reoptimzation encountered = 0<br />

Number of C->S message send = 22<br />

Number of S->C message send = 21<br />

Number of prepare statements encountered = 1<br />

Number of execute statements encountered = 0<br />

Number of singleton select encountered = 0<br />

Number of open cursor encountered = 0<br />

Number of close cursor encountered = 1<br />

Number of non-blob put = 0, averge size of each put is 0.000000<br />

Number of non-blob fetch = 1, averge size of each fetch is 25.000000<br />

Number of blob put = 0, averge size of each put is 0.000000<br />

Number of blob fetch = 0, averge size of each fetch is 0.000000<br />

>>>>>>>>>>>>>>> END SUMMARY INFORMATION


252 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Chapter 8. Working with .NET data<br />

providers<br />

8<br />

This chapter describes the .NET providers that are available for working with an<br />

<strong>Informix</strong> database server. It includes the following topics:<br />

► <strong>Informix</strong> and .NET data providers<br />

► Setup and configuration<br />

► Developing a .NET application<br />

► Visual Studio Add-In for Visual Studio<br />

© Copyright <strong>IBM</strong> Corp. 2010. All rights reserved. 253


8.1 <strong>Informix</strong> and .NET data providers<br />

A .NET data provider is a .NET assembly that lets .NET applications access and<br />

manipulate data in a database by implementing several interfaces that follow the<br />

Microsoft ADO.NET architecture. Any application that can be executed by the<br />

Microsoft .NET Framework can use a .NET data provider.<br />

<strong>IBM</strong> provides the following .NET data providers to work with an <strong>IBM</strong> <strong>Informix</strong><br />

database:<br />

► <strong>IBM</strong> Infomix .NET Provider<br />

► <strong>IBM</strong> Data Server Provider for .NET<br />

Both providers rely on internal calls to the ODBC and CLI drivers. They are not<br />

100% managed-code providers.<br />

8.2 Setup and configuration<br />

This chapter describes the .NET providers that are available to connect to an<br />

<strong>IBM</strong> <strong>Informix</strong> database. We explain how to configure and test the connectivity<br />

with both Infomix .NET Provider and Data Server Provider for .NET.<br />

8.2.1 <strong>IBM</strong> <strong>Informix</strong> .Net Provider<br />

<strong>Informix</strong> .NET Provider is part of the <strong>Informix</strong> Client Software Development Kit<br />

(Client SDK). <strong>Informix</strong> .NET Provider is certified to work on both 32-bit and 64-bit<br />

editions of Windows XP, Windows Vista, Windows Server 2003, Windows Server<br />

2008, and Windows 7.<br />

The provider requires that Microsoft .NET Framework SDK 1.1 or higher is<br />

already installed on the computer. The provider is installed by default when<br />

performing a complete installation of Client SDK.<br />

<strong>Informix</strong> .NET Provider supports the following <strong>Informix</strong> database servers:<br />

► <strong>IBM</strong> <strong>Informix</strong> 10.00, 11.10, and 11.50<br />

► <strong>IBM</strong> <strong>Informix</strong> Extended Parallel Server 8.50 and later<br />

The assembly name of the <strong>Informix</strong> .NET Provider is <strong>IBM</strong>.Data.<strong>Informix</strong>.<br />

The assembly files are located in the Client SDK directory. The provider for a<br />

.NET 1.1 application is in the %INFORMIXDIR%\netf11 directory. For a .NET 2.0<br />

and above, use the provider located in the %INFORMIXDIR\netf20 directory.<br />

254 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


The installation process registers two strong-named assemblies in the global<br />

assembly cache (GAC).<br />

Table 8-1 shows <strong>Informix</strong> .NET Provider assembly versions.<br />

Table 8-1 <strong>Informix</strong> .NET Provider assembly versions<br />

.NET framework Assembly version<br />

1.1 2.81.0.0<br />

2.0 and above 3.0.0.2<br />

The assemblies are registered in the common section of the GAC (GAC_MSIL).<br />

Thus, only one version of the provider (32-bit or 64-bit) can be stored in the GAC<br />

at a time.<br />

Note: There is no 64-bit version of the .NET 1.1 Framework, so the .NET 1.1<br />

Provider is not installed on a Windows 64-bit platform.<br />

8.2.2 <strong>IBM</strong> Data Server Provider for .NET<br />

Data Server Provider for .NET is included in the <strong>IBM</strong> Data Server Package. The<br />

provider supports multiple <strong>IBM</strong> data servers, including <strong>IBM</strong> <strong>Informix</strong> (11.x) and<br />

DB2.<br />

As with <strong>Informix</strong> .NET Provider, the Data Server Provider for .NET is not 100%<br />

managed code. Thus, it requires the DB2 CLI component for communication with<br />

the database.<br />

The following Data Server providers for an <strong>Informix</strong> database are available:<br />

► <strong>IBM</strong>.Data.DB2 is the preferred .NET provider when developing new<br />

applications.<br />

► <strong>IBM</strong>.Data.<strong>Informix</strong> is the .NET provider assembly that is normally used to<br />

migrate an application that is developed using <strong>Informix</strong> .NET Provider.<br />

The assembly files are located in the netf20 subdirectory under the Data Server<br />

Client directory, which by default is C:\Program Files\<strong>IBM</strong>\<strong>IBM</strong> DATA SERVER<br />

DRIVER\netf20.<br />

Note: The 64-bit version of the Data Server Client Package also includes the<br />

32-bit drivers.<br />

Chapter 8. Working with .NET data providers 255


Both providers have the same assembly version, 9.0.0.2. Table 8-2 shows the<br />

Data Server Provider for .NET assembly version.<br />

Table 8-2 Data Server Provider for .NET assembly versions<br />

.NET Provider Assembly version<br />

<strong>IBM</strong>.Data.DB2 9.0.0.2<br />

<strong>IBM</strong>.Data.<strong>Informix</strong> 9.0.0.2<br />

8.2.3 Verifying connectivity<br />

<strong>Informix</strong> .NET Provider uses communication libraries internally as do the other<br />

drivers that are included in Client SDK. Thus, it uses the same connectivity<br />

information that is normally stored in the registry through the use of the<br />

setnet32.exe utility.<br />

When there is no specific tool to verify the connectivity with <strong>Informix</strong> .NET<br />

Provider, you can use a simple .NET application to test it.<br />

The Microsoft .NET Framework SDK is required to use a .NET provider that<br />

contains a .NET language compiler.<br />

Example 8-1 shows a simple C code sample that verifies the connection with the<br />

database server. This example takes the connection string as the first argument<br />

and uses it to connect to the database.<br />

Example 8-1 A connect.cs sample<br />

using System;<br />

using System.Data;<br />

using <strong>IBM</strong>.Data.<strong>Informix</strong>;<br />

class Connect<br />

{<br />

static void Main(string[] args)<br />

{<br />

IfxConnection conn;<br />

if (args.Length>0) {<br />

try {<br />

conn = new IfxConnection(args[0]);<br />

conn.Open();<br />

Console.WriteLine("Connected");<br />

Console.WriteLine(String.Format("Server Type: {0}, Server<br />

Version: {1}", conn.ServerType, conn.ServerVersion));<br />

256 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Console.WriteLine(String.Format("Database: {0}",<br />

conn.Database));<br />

}<br />

catch (Exception e) {<br />

Console.WriteLine(e.Message);<br />

}<br />

}<br />

else<br />

Console.WriteLine("Need a connection string as argument\n e.g:<br />

\"Host=kodiak;Service=9088;Server=demo_on;Database=stores_demo;User<br />

ID=informix;password=;\"\n");<br />

}<br />

}<br />

Example 8-2 shows how to compile and run Example 8-1 on page 256.<br />

Example 8-2 Output of the connect.cs sample<br />

C:\work>csc.exe /R:%INFORMIXDIR%\bin\netf20\<strong>IBM</strong>.Data.informix.dll /nologo<br />

connect.cs<br />

C:\work>connect "Server=demo_on;Database=stores_demo"<br />

Connected<br />

Server Type: <strong>Informix</strong>, Server Version: 11.50.0000 FC6<br />

Database: stores_demo<br />

C:\work><br />

If the connection information for the <strong>Informix</strong> server is stored in the registry, the<br />

only parameter that is required in the connection string is the name of the<br />

database server. The remainder of the information, such as Host or Service, is<br />

taken from the registry.<br />

At compile time, you must pass the assembly as a reference to the csc.exe<br />

compiler using the /R parameter. For example:<br />

/R:%INFORMIXDIR%\bin\netf20\<strong>IBM</strong>.Data.<strong>Informix</strong>.dll<br />

If you want to use the Data Server provider, the reference path is as follows:<br />

/R:”C:\Program Files (x86)\<strong>IBM</strong>\<strong>IBM</strong> DATA SERVER DRIVER\bin\netf20\<strong>IBM</strong>.Data.<strong>Informix</strong>.dll”<br />

Chapter 8. Working with .NET data providers 257


Example 8-3 shows how to compile and execute the sample with Data Server<br />

Provider for .NET.<br />

Example 8-3 Data Server connect.cs sample<br />

C:\work>csc.exe /R:"C:\Program Files (x86)\<strong>IBM</strong>\<strong>IBM</strong> DATA SERVER<br />

DRIVER\bin\netf20\<strong>IBM</strong>.Data.<strong>Informix</strong>.dll" /nologo connect.cs<br />

C:\work>connect "Server=kodiak:9089;Database=stores_demo;User<br />

ID=informix;password=password;"<br />

Connected<br />

Server Type: IDS/NT64, Server Version: 11.50.0000<br />

Database: STORES_DEMO<br />

C:\work><br />

Data Server Provider for .NET includes a connection tool called testconn20.exe<br />

that you can use to test the connection with the database. Example 8-4 shows a<br />

typical output of the testconn20.exe utility.<br />

Example 8-4 Output of the testconn20.exe utility<br />

C:\work>testconn20.exe "server=kodiak:9089; database=stores_demo; uid=informix;<br />

pwd=password;"<br />

Step 1: Printing version info<br />

.NET Framework version: 2.0.50727.3603<br />

DB2 .NET provider version: 9.0.0.2<br />

DB2 .NET file version: 9.7.2.2<br />

Capability bits: ALLDEFINED<br />

Build: 20100514<br />

Factory for invariant name <strong>IBM</strong>.Data.DB2 verified<br />

VSAI assembly version: 9.1.0.0<br />

VSAI file version: 9.7.1.53<br />

Elapsed: 1.015625<br />

Step 2: Validating db2dsdriver.cfg against db2dsdriver.xsd schema file<br />

C:\PROGRA~1\<strong>IBM</strong>\<strong>IBM</strong>DAT~2\cfg\db2dsdriver.cfg against C:\Program<br />

Files\<strong>IBM</strong>\<strong>IBM</strong> DATA SERVER DRIVER\cfg\db2dsdriver.xsd<br />

Elapsed: 0.015625<br />

Step 3: Connecting using "server=kodiak:9089; database=stores_demo;<br />

uid=informix; pwd=password;"<br />

Server type and version: IDS 11.50.0000<br />

Elapsed: 0.46875<br />

Step 4: Selecting rows from informix.systables to validate existance of<br />

packages<br />

SELECT * FROM informix.systables<br />

258 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Elapsed: 0.171875<br />

Step 5: Calling GetSchema for tables to validate existance of schema functions<br />

Elapsed: 0.21875<br />

Test passed.<br />

C:\work><br />

8.3 Developing a .NET application<br />

This section describes the connection string attributes for two <strong>Informix</strong> .NET<br />

providers and provides samples of basic database operations.<br />

8.3.1 Connecting to the database<br />

In this section, we describe the connection string attributes for <strong>Informix</strong> .NET<br />

Provider and Data Server Provider for .NET<br />

<strong>Informix</strong> .NET Provider connection attributes<br />

Table 8-3 lists the connection attributes that <strong>Informix</strong> .NET Provider supports.<br />

Table 8-3 <strong>Informix</strong> .NET Provider connection string attributes<br />

Attribute Description Default<br />

Client Locale,<br />

Client_Locale<br />

Locale used on the application en_us.1252<br />

Connection Lifetime Time in seconds that a connection is<br />

allowed in the pool<br />

Database, DB Database to connect to<br />

Database Locale,<br />

DB_LOCALE<br />

Locale of the database en_US.819<br />

DELIMIDENT If set, any string within double quotes (")<br />

is treated as an identifier, and any string<br />

within single quotes (’) is treated as a<br />

string literal<br />

Enlist Enables or disables automatic enlistment<br />

in a distributed transaction<br />

Chapter 8. Working with .NET data providers 259<br />

0<br />

y<br />

true


Attribute Description Default<br />

Exclusive, XCL if set the database is open in exclusive<br />

mode<br />

Host Name or IP address of the system on<br />

which the <strong>Informix</strong> server is running<br />

Max Pool Size Maximum number of connections<br />

allowed in the pool<br />

Min Pool Size Minimum number of connections allowed<br />

in the pool<br />

Optimize OpenFetchClose,<br />

OPTOFC<br />

Packet Size, Fetch Buffer<br />

Size, FBS<br />

260 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong><br />

Reduces the number of client-server<br />

messages when using cursors<br />

Size in bytes of the buffers used to send<br />

data to or from the server<br />

Password, PWD Password associated with the User ID<br />

Persist Security Info If set the security-sensitive information,<br />

such as the password, is returned as part<br />

of the connection string<br />

No<br />

localhost<br />

100<br />

0<br />

0<br />

32767<br />

false<br />

Pooling Enable Connection Pooling true<br />

Protocol, PRO Communication protocol<br />

Server Name or alias of the <strong>Informix</strong> server<br />

Service Service name or port number used by the<br />

server for incoming connection<br />

Skip Parsing If set, there is no internal SQL parsing it<br />

increases performance but the SQL must<br />

be valid<br />

UserDefinedTypeFormat Changes the mapping of UDTs to either<br />

DbType.String or DbType.Binary<br />

Leave Trailing Spaces If set, disable the automatic trailing of<br />

spaces done in a varchar column<br />

User ID, UID Login account.<br />

false<br />

false


Data Server Provider for .NET connection attributes<br />

Table 8-4 lists the most common connection attributes that Data Server Provider<br />

for .NET uses.<br />

Table 8-4 Data Server Provider for .NET connection string attributes<br />

Attribute Description Default Value<br />

ConnectTimeout,<br />

Connect Timeout<br />

The time (in seconds) to wait for the<br />

database connection to be established.<br />

Connection Lifetime Time in seconds that a connection is<br />

allowed in the pool.<br />

Database, DB Database to connect to.<br />

Enlist Enables or disables automatic enlistment<br />

in a distributed transaction.<br />

Max Pool Size Maximum number of connections<br />

allowed in the pool.<br />

Min Pool Size Minimum number of connections allowed<br />

in the pool.<br />

Password, PWD Password associated with the User ID<br />

Persist Security Info If set the security-sensitive information,<br />

such as the password, is returned as part<br />

of the connection string.<br />

Pooling Enable Connection Pooling within the<br />

.NET Provider<br />

Query Timeout Time to wait for an SQL query response 5<br />

Server Name or alias of the <strong>Informix</strong> server<br />

followed by service name or the port<br />

number<br />

User ID, UID Login account<br />

The configuration parameters for Data Server Provider for .NET and most of the<br />

components are stored in the db2sdriver.cfg file. For a complete list of the<br />

configuration parameters in this file, refer to:<br />

http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.swg.im.dbcli<br />

ent.config.doc/doc/c0054698.html<br />

If the connection string does not contain all the required information, the provider<br />

takes the missing arguments from the db2sdriver.cfg configuration file.<br />

Chapter 8. Working with .NET data providers 261<br />

0<br />

60<br />

true<br />

0<br />

0<br />

false<br />

true


The majority of the connection string attributes of Data Server Provider for .NET<br />

have similar meanings and format as <strong>Informix</strong> .NET Provider string attributes<br />

except the Server attribute.<br />

For <strong>Informix</strong> .NET Provider, the Server keyword contains the name (or alias) of<br />

the <strong>Informix</strong> server, which is normally the same as the value of the<br />

INFORMIXSERVER variable.<br />

For Data Server Provider for .NET, the Server keyword contains the host name<br />

where the <strong>Informix</strong> server is running and the service name or port number that is<br />

used to listen for DRDA client connections.<br />

Example 8-5 shows the Server attribute format. In this example, we connect to<br />

an <strong>Informix</strong> database server that is running in a system named kodiak.ibm.com.<br />

The <strong>Informix</strong> server DRDA alias is using the port number 9089.<br />

Example 8-5 Server attribute for the Data Server Provider for .NET<br />

C:\work>connect<br />

"Server=kodiak.ibm.com:9089;Database=stores_demo;UID=informix;password=password<br />

;"<br />

Connected<br />

Server Type: IDS/NT64, Server Version: 11.50.0000<br />

Database: STORES_DEMO<br />

C:\work><br />

8.3.2 Data type mapping<br />

The data types that are used by the .NET Framework differ from the data types<br />

that are used by the <strong>IBM</strong> <strong>Informix</strong> database. In this section, we describe the<br />

optimal data types to use when accessing data in an <strong>Informix</strong> database. The<br />

optimal data type depends on the .NET method that is used to access the data.<br />

You can use types other than those that we describe here. For example, you can<br />

use the IfxDataReader.GetString method to obtain any <strong>Informix</strong> data type. The<br />

types that we mention here are the most efficient and least likely to change in<br />

value in data conversion.<br />

262 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


<strong>Informix</strong> .NET type mapping<br />

Table 8-5 shows the mapping for the specific <strong>IBM</strong> <strong>Informix</strong> data types.<br />

Table 8-5 Type mapping for <strong>Informix</strong> specific data<br />

<strong>Informix</strong> data type For data reader For data set<br />

BIGINT Int64 Int64<br />

BIGSERIAL Int64 Int64<br />

BLOB IfxBlob Byte[]<br />

BOOLEAN Boolean Boolean<br />

BYTE Byte[] Byte[]<br />

CLOB IfxClob Byte[]<br />

COMPLEX (ROW, LIST) String String<br />

DECIMAL(p


Data Server Provider for .NET type mapping<br />

Table 8-6 shows the type mapping with the Data Server Provider for .NET when<br />

using specific <strong>Informix</strong> data types.<br />

Table 8-6 Type mapping for <strong>Informix</strong> specific data<br />

<strong>Informix</strong> data type Optimal for data reader Optimal for data set<br />

LVARCHAR IfxString String<br />

BLOB, BYTE IfxBlob Byte[]<br />

CLOB, TEXT IfxClob String<br />

BOOLEAN, SMALLINT IfxInt16 Int16<br />

BIGINT, BIGSERIAL, INT8,<br />

SERIAL8<br />

8.3.3 Performing database operations<br />

This section describes the main classes in the <strong>Informix</strong> .NET Provider and<br />

demonstrates how to use these classes with basic examples.<br />

IfxConnection<br />

The IfxConnection object represents a unique connection with the database<br />

server. You can specify the connectivity details about the database when creating<br />

the connection object or by setting the ConnectionString property later.<br />

Because <strong>Informix</strong> .NET Provider uses native resources (that are not managed by<br />

the .NET CLR), always close or dispose any open IfxConnection class when it is<br />

not longer needed.<br />

264 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong><br />

IfxInt64 Int64<br />

DECIMAL(p


Table 8-7 lists the public method of the IfxConnection class.<br />

Table 8-7 IfxConnection public methods<br />

We described the connection string attributes in 8.3.1, “Connecting to the<br />

database” on page 259. Example 8-6 demonstrates how to connect to the<br />

database<br />

Example 8-6 The connect_sample.cs sample<br />

using System;<br />

using System.Data;<br />

using <strong>IBM</strong>.Data.<strong>Informix</strong>;<br />

class sample {<br />

static void Main(string[] args) {<br />

}<br />

Method Description<br />

void Open() Opens a database connection<br />

void Close() Closes the connection to the database<br />

void ChangeDatabase(String) Changes the current database<br />

void EnlistTransaction() Enlists the connection in a DTC transaction<br />

IfxTransaction BeginTransaction()<br />

BeginTransaction(IsolationLevel)<br />

}<br />

IfxConnection conn;<br />

Begins a database transaction<br />

IfxCommand CreateCommand() Creates an instance of an IfxCommand object that<br />

is associated with this IfxConnection<br />

IfxBlob GetIfxBlob() Creates an instance of an IfxBlob object that is<br />

associated with this connection<br />

IfxClob GetIfxClob() Creates an instance of an IfxClob object that is<br />

associated with this connection<br />

try {<br />

conn = new IfxConnection("Server=demo_on;database=stores_demo");<br />

conn.Open();<br />

Console.WriteLine("Connected to "+conn.Database);<br />

conn.Close();<br />

}<br />

catch (Exception e) {<br />

Console.WriteLine(e.Message);<br />

}<br />

Chapter 8. Working with .NET data providers 265


Example 8-7 shows the output of Example 8-6.<br />

Example 8-7 Output of the connect_sample.cs sample<br />

C:\work>csc.exe /R:%INFORMIXDIR%\bin\netf20\<strong>IBM</strong>.Data.<strong>Informix</strong>.dll /nologo<br />

connect_sample.cs<br />

C:\work>connect_sample<br />

Connected to stores_demo<br />

C:\work><br />

IfxCommand<br />

The IfxCommand object represents an SQL statement or stored procedure to<br />

execute against a database server.<br />

Table 8-8 shows methods that the IfxCommand class provides for executing an<br />

SQL statement.<br />

Table 8-8 IfxCommand public methods<br />

Method Description<br />

Int32 ExecuteNonQuery() Executes an SQL statement against the<br />

IfxConnection object<br />

IfxDataReader ExecuteReader()<br />

ExecuteReader(DataCommandBehavior<br />

behavior)<br />

266 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong><br />

Executes the command in the<br />

CommandText property against the<br />

IfxConnection object and builds an<br />

IfxDataReader object<br />

Object ExecuteScalar() Executes the query, and returns the first<br />

column of the first row<br />

void Cancel() Attempts to cancel the execution of a<br />

command<br />

IfxParameter CreateParameter() Creates a new instance of an<br />

IfxParameter object<br />

void Prepare() Creates a prepared (or compiled) version<br />

of the command against the database


Example 8-8 demonstrates how to run a simple DELETE SQL statement.<br />

Example 8-8 The command_sample.cs sample<br />

using System;<br />

using System.Data;<br />

using <strong>IBM</strong>.Data.<strong>Informix</strong>;<br />

class sample {<br />

static void Main(string[] args) {<br />

}<br />

}<br />

IfxConnection conn;<br />

int drows=0;<br />

try {<br />

conn = new IfxConnection("Server=demo_on;database=stores_demo");<br />

conn.Open();<br />

IfxCommand cmmd = conn.CreateCommand();<br />

cmmd.CommandText = "DELETE FROM customer WHERE customer_num = 103";<br />

drows = cmmd.ExecuteNonQuery();<br />

Console.WriteLine("Deleted rows: "+drows.ToString());<br />

conn.Close();<br />

}<br />

catch (Exception e) {<br />

Console.WriteLine(e.Message);<br />

}<br />

Example 8-9 shows the output of Example 8-8.<br />

Example 8-9 Output of the command_sample.cs sample<br />

C:\work>csc.exe /R:%INFORMIXDIR%\bin\netf20\<strong>IBM</strong>.Data.<strong>Informix</strong>.dll /nologo<br />

command_sample.cs<br />

C:\work>command_sample<br />

Deleted rows: 1<br />

C:\work><br />

IfxDataAdapter<br />

The IfxDataAdapter class represents a set of data commands that are used to<br />

communicate between a data set and the database. A data set is a copy of the<br />

database data that is stored in memory.<br />

Chapter 8. Working with .NET data providers 267


Table 8-9 lists the methods that the IfxDataAdapter class provides for accessing<br />

the data.<br />

Table 8-9 IfxDataAdapter public methods<br />

Method Description<br />

Int32 Fill(DataSet) Adds or refreshes rows in the data set<br />

DataTable FillSchema(DataSet,<br />

SchemaType)<br />

IDataParameter<br />

GetFillParameters()<br />

Example 8-10 demonstrates how to retrieve data from the database using the<br />

IfxDataAdapter class. In this example, we retrieve the data rows directly from the<br />

data set.<br />

Example 8-10 The dataadapter_sample.cs sample<br />

using System;<br />

using System.Data;<br />

using <strong>IBM</strong>.Data.<strong>Informix</strong>;<br />

class sample {<br />

static void Main(string[] args) {<br />

IfxConnection conn;<br />

268 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong><br />

conn = new IfxConnection("Server=demo_on;database=stores_demo");<br />

conn.Open();<br />

IfxCommand cmmd = conn.CreateCommand();<br />

cmmd.CommandText = "SELECT * FROM state WHERE code='CA'";<br />

IfxDataAdapter dadap = new IfxDataAdapter();<br />

DataSet dset = new DataSet();<br />

dadap.SelectCommand = cmmd;<br />

dadap.Fill(dset);<br />

Adds a data table to the data set, and<br />

configures the schema to match that in the<br />

database based on the specified SchemaType<br />

Returns the parameters set by the user when<br />

executing a SELECT statement<br />

Int32 Update(DataSet) Executes the SQL statement that is associated<br />

with the InsertCommand, UpdateCommand, or<br />

DeleteCommand for each inserted, updated, or<br />

deleted row in the specified data set<br />

foreach(DataRow dr in dset.Tables[0].Rows) {<br />

Console.WriteLine(String.Format("\tCode\tState\n"));<br />

Console.WriteLine(String.Format("\t{0}\t{1}", dr["code"], dr["sname"]));


}<br />

}<br />

}<br />

conn.Close();<br />

Example 8-11 shows the data that is returned by the data set object.<br />

Example 8-11 Output of the dataadapter_sample.cs sample<br />

C:\work>csc.exe /R:%INFORMIXDIR%\bin\netf20\<strong>IBM</strong>.Data.<strong>Informix</strong>.dll /nologo<br />

dataadapter_sample.cs<br />

C:\work>dataadapter_sample.exe<br />

Code State<br />

C:\work><br />

CA California<br />

IfxDataReader<br />

The IfxDataReader class provides fast read-only, forward-only access to a set of<br />

rows, similar to SQL cursors data. To create an IfxDataReader object, the<br />

application calls the ExecuteReader() method of the IfxCommand object.<br />

The IfxDataReader class is a part of the System.Data.Common.DbDataReader. It<br />

provides all common DbDataReader methods as well as additional methods to<br />

handle <strong>Informix</strong> specific data types.<br />

Table 8-10 contains the additional public methods of the IfxDataReader class.<br />

Table 8-10 Additional methods of IfxDataReader<br />

Method Description<br />

Boolean GetBoolean() Gets the value of the specified column as a Boolean<br />

TimeSpan GetTimeSpan() Gets the time span value of the specified field<br />

IfxBlob GetIfxBlob() Gets the IfxBlob value of the specific field<br />

IfxClob GetIfxClob() Gets the IfxClob value of the specific field<br />

IfxDateTime GetIfxDateTime() Gets the IfxDateTime value of the specific field<br />

IfxDecimal GetIfxDecimal Gets the GetIfxDecimal value of the specific field<br />

Chapter 8. Working with .NET data providers 269


Method Description<br />

IfxMonthSpan GetIfxMonthSpan Gets the IfxMonthSpan value of the specific field<br />

IfxTimeSpan GetIfxTimeSpan Gets the IfxTimeSpan value of the specific field<br />

Refer to <strong>IBM</strong> <strong>Informix</strong> .NET Provider Reference Guide for a complete list of all the<br />

IfxDataReader public methods:<br />

http://publib.boulder.ibm.com/infocenter/idshelp/v115/topic/com.ibm.netpr.doc/n<br />

etpr031023156.htm#netpr031023156<br />

Note: Even if the IfxDataReader.Read() method returns only one row each<br />

time it is called, the provider can retrieve more than one row from the<br />

database. <strong>Informix</strong> .NET Provider does this to increase performance. The<br />

application can set the number of rows that the provider fetches from the<br />

database using the IfxCommand class RowFetchCount property.<br />

Example 8-12 demonstrates how to use a IfxDataReader class to access a<br />

database table.<br />

Example 8-12 The datareader_sample.cs sample<br />

using System;<br />

using System.Data;<br />

using <strong>IBM</strong>.Data.<strong>Informix</strong>;<br />

class sample {<br />

static void Main(string[] args) {<br />

IfxConnection conn;<br />

270 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong><br />

conn = new IfxConnection("Server=demo_on;database=stores_demo");<br />

conn.Open();<br />

IfxCommand cmmd = conn.CreateCommand();<br />

cmmd.CommandText = "SELECT * FROM state WHERE code='CA'";<br />

IfxDataReader drdr;<br />

drdr = cmmd.ExecuteReader();<br />

while (drdr.Read()) {<br />

Console.WriteLine(String.Format("\tCode\tState\n"));<br />

Console.Write(String.Format("\t{0}", drdr.GetString(0)));<br />

Console.WriteLine(String.Format("\t{0}", drdr.GetString(1)));<br />

}<br />

drdr.Close();<br />

conn.Close();


}<br />

}<br />

Example 8-13 shows the output of Example 8-12 on page 270.<br />

Example 8-13 Output of the datareader_sample.cs sample<br />

C:\work>csc.exe /R:%INFORMIXDIR%\bin\netf20\<strong>IBM</strong>.Data.<strong>Informix</strong>.dll /nologo<br />

datareader_sample.cs<br />

C:\work>datareader_sample.exe<br />

Code State<br />

C:\work><br />

CA California<br />

IfxError<br />

The IfxError class collects information that is relevant to a warning or error that<br />

the database returns. You can use the IfxError and IfxErrorCollection<br />

classes to retrieve additional information when an error occurs.<br />

An application can access this information using the properties of the IfxError<br />

object listed in Table 8-11.<br />

Table 8-11 IfxError properties<br />

Property Type Description<br />

Message String Text message<br />

NativeError Int32 <strong>IBM</strong> <strong>Informix</strong> error code<br />

SQLState String ANSI SQL error code<br />

Example 8-14 demonstrates a typical use of the IfxError class. The<br />

IfxException class contains one or more IfxError objects.<br />

Example 8-14 The error_sample.cs sample<br />

using System;<br />

using System.Data;<br />

using <strong>IBM</strong>.Data.<strong>Informix</strong>;<br />

class Connect {<br />

static void Main(string[] args) {<br />

IfxConnection conn;<br />

Chapter 8. Working with .NET data providers 271


}<br />

}<br />

int drows=0;<br />

272 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong><br />

try {<br />

conn = new IfxConnection("Server=demo_on;database=wrong_db");<br />

conn.Open();<br />

Console.WriteLine("Connected");<br />

conn.Close();<br />

}<br />

catch (IfxException e) {<br />

Console.WriteLine("----------------------------");<br />

if (e.Errors.Count > 0) {<br />

IfxError ifxErr = e.Errors[0];<br />

Console.WriteLine("Message :" + ifxErr.Message);<br />

Console.WriteLine("Native error :" + ifxErr.NativeError);<br />

Console.WriteLine("SQL state :" + ifxErr.SQLState );<br />

}<br />

Console.WriteLine(e.StackTrace);<br />

Console.WriteLine("----------------------------");<br />

}<br />

IfxParameter<br />

The IfxParameter class is used to pass parameters to the IfxCommand method.<br />

IfxParameter classes are stored as a collection in a IfxParameterCollection<br />

object.<br />

Table 8-12 contains the public attributes of an IfxParameter object.<br />

Table 8-12 IfxParameter attributes<br />

Property Type Description<br />

DbType DbType Defines the DbType of the parameter<br />

Direction ParameterDirection Defines the direction of the parameter<br />

(Input, Output, or both)<br />

IfxType IfxType Defines the IfxType class of the<br />

parameter<br />

IsNullable Boolean Specifies whether the parameter is<br />

allowed to be null<br />

ParameterName String Name of the parameter, which is a unique<br />

reference in the parameter collection


Example 8-15 shows how to use IfxParameter class to perform an UPDATE<br />

operation.<br />

Example 8-15 The parameter_sample.cs sample<br />

using System;<br />

using System.Data;<br />

using <strong>IBM</strong>.Data.<strong>Informix</strong>;<br />

class sample {<br />

static void Main(string[] args) {<br />

}<br />

Property Type Description<br />

SourceColumn String Specifies the column that is mapped to<br />

the data set<br />

SourceVersion DataRowVersion Defines the DataRowVersion to use when<br />

you load Value<br />

Value Object Defines the value of the parameter<br />

}<br />

IfxConnection conn;<br />

int urows=0;<br />

try {<br />

conn = new IfxConnection("Server=demo_on;database=stores_demo");<br />

conn.Open();<br />

IfxCommand cmmd = conn.CreateCommand();<br />

cmmd.CommandText = "UPDATE state SET sname = ? where code = ?";<br />

IfxParameter pcode = new IfxParameter(“code”, DbType.String);<br />

IfxParameter psname = new IfxParameter(“sname”, DbType.String);<br />

pcode.Value="CA";<br />

psname.Value="CALIFORNIA";<br />

cmmd.Parameters.Add(psname);<br />

cmmd.Parameters.Add(pcode);<br />

urows = cmmd.ExecuteNonQuery();<br />

Console.WriteLine("Updated rows: "+urows.ToString());<br />

conn.Close();<br />

}<br />

catch (Exception e) {<br />

Console.WriteLine(e.Message);<br />

}<br />

Chapter 8. Working with .NET data providers 273


Example 8-16 shows the output of Example 8-15 on page 273.<br />

Example 8-16 Output of the parameter_sample.cs sample<br />

C:\work>csc.exe /R:%INFORMIXDIR%\bin\netf20\<strong>IBM</strong>.Data.<strong>Informix</strong>.dll /nologo<br />

parameter_sample.cs<br />

C:\work>parameter_sample.exe<br />

Updated rows: 1<br />

C:\work><br />

IfxTransaction<br />

The IfxTransaction class represents an SQL transaction to be made at a<br />

database. The application creates an transaction by calling the<br />

BeginTransaction method of the IfxConnection object.<br />

The IfxConnection.BeginTransaction() method returns an IfxTransaction<br />

object. When the application decides how to resolve the transaction, it uses the<br />

Commit and Rollback methods of the IfxTransaction object.<br />

Any IfxCommand that is involved in a transaction must have the transaction<br />

property set to the IfxTransaction object.<br />

Example 8-17 demonstrates how to create a transaction.<br />

Example 8-17 Creating a transaction using the IfxTransaction class<br />

using System;<br />

using System.Data;<br />

using <strong>IBM</strong>.Data.<strong>Informix</strong>;<br />

class sample {<br />

static void Main(string[] args) {<br />

IfxConnection conn;<br />

int drows=0;<br />

274 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong><br />

try {<br />

conn = new IfxConnection("Server=demo_on;database=stores_demo");<br />

conn.Open();<br />

IfxTransaction trans = conn.BeginTransaction();<br />

IfxCommand cmmd = conn.CreateCommand();<br />

cmmd.Transaction = trans;<br />

cmmd.CommandText = "DROP TABLE state";<br />

drows = cmmd.ExecuteNonQuery();


}<br />

}<br />

trans.Rollback();<br />

conn.Close();<br />

}<br />

catch (Exception e) {<br />

Console.WriteLine(e.Message);<br />

}<br />

You can specify the following isolation levels with the BeginTransaction()<br />

method:<br />

► ReadUncommitted<br />

► ReadCommitted<br />

► RepeatableRead<br />

► Serializable<br />

The default Isolation level is ReadCommited.<br />

Example 8-18 demonstrates how to run a distributed transaction.<br />

Example 8-18 The transact_cts.cs sample<br />

using System;<br />

using System.Data;<br />

using <strong>IBM</strong>.Data.<strong>Informix</strong>;<br />

using System.Transactions;<br />

class sample {<br />

static void Main(string[] args) {<br />

IfxConnection conn;<br />

try {<br />

conn = new IfxConnection("Server=demo_on;database=stores_demo");<br />

// Transaction options<br />

TransactionOptions tsopt = new TransactionOptions();<br />

tsopt.IsolationLevel =<br />

System.Transactions.IsolationLevel.RepeatableRead;<br />

tsopt.Timeout = new TimeSpan(0, 60, 0);<br />

using (TransactionScope tscope = new TransactionScope(<br />

TransactionScopeOption.RequiresNew, tsopt,<br />

EnterpriseServicesInteropOption.Full))<br />

{<br />

conn.Open();<br />

Chapter 8. Working with .NET data providers 275


276 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong><br />

IfxCommand cmmd = conn.CreateCommand();<br />

cmmd.CommandText = "DROP TABLE state";<br />

cmmd.ExecuteNonQuery();<br />

// Rollback the distributed transaction not calling Complete()<br />

// tscope.Complete();<br />

}<br />

}<br />

catch (Exception e) {<br />

Console.WriteLine(e.Message);<br />

}<br />

}<br />

}<br />

8.3.4 Handling <strong>Informix</strong> specific data types<br />

In this section, we discuss how to work with <strong>IBM</strong> <strong>Informix</strong> specific data types<br />

such as smart large objects or decimal using <strong>Informix</strong> .NET Provider.<br />

IfxBlob and IfxClob<br />

CLOB and BLOB are <strong>Informix</strong> data types that are used to store large amounts of<br />

character or binary data.The application handles these smart large objects using<br />

the IfxClob and IfxBlob classes.<br />

The method that is implemented on these classes allows random access of its<br />

contents. The application can read or write to certain positions in the large object<br />

without reading or writing through all of the data up to that position.<br />

BLOBs and CLOBs are both smart large object type. Both types share many of<br />

the same methods. BLOBs differ from CLOBs in that the data in a CLOB is<br />

treated as text characters but the data in a BLOB is not. The data in a BLOB is<br />

considered to be binary data, and no translation or conversion of any kind is<br />

performed on it when it is moved to or from the database server.<br />

Properties and methods<br />

Table 8-13 lists the IfxBlob and IfxClob public properties.<br />

Table 8-13 Properties of IfxBlob and IfxClob<br />

Property Type Description<br />

EstimatedSize Int64 Estimates final size of the large object<br />

ExtentSize Int32 Finds the next extent size for this large object (disk<br />

space)


Property Type Description<br />

Flags Int32 Flags for this large object<br />

IsNull Boolean Determines whether the large object is NULL<br />

IsOpen Boolean Determines whether the large object is open<br />

LastAccessTime Int32 Determines the last time that the large object was<br />

accessed<br />

LastChangeTime Int32 Determines the last time that the status was<br />

changed<br />

LastModificationTime Int32 Determines the last time that the large object was<br />

modified<br />

MaxBytes Int64 Defines the maximum size for the large object<br />

Position Int64 Defines the current position on the large object<br />

ReferenceCount Int32 Provides the number of records in the database<br />

that currently contain a reference to this large<br />

object<br />

SBSpace String Defines the Sbspace in which the large object is<br />

stored<br />

Size Int64 Defines the size of the large object in bytes<br />

Table 8-14 lists the available public methods from the IfxClob and IfxBlob<br />

classes.<br />

Table 8-14 Public methods of IfxClob and IfxBlob<br />

Method Description<br />

void Open(mode) Opens a large object in a specific mode<br />

IfxSmartLOBLocator GetLocator() Returns the IfxSmartLOBLocator that is<br />

associated with this instance<br />

Int64 Read(buff), Read(buff,<br />

buffOffset, numBytesToRead,<br />

sLOBOffset, whence)<br />

Int64 Write(buff), Write(buff,<br />

buffOffset, numBytesToWrite,<br />

sLOBOffset, whence)<br />

Reads the complete data or a portion of a<br />

large object as a Byte[] or Char[]<br />

Writes the complete buffer or a portion into<br />

a large object<br />

void Truncate(offset) Truncates everything in the large object<br />

past the position offset<br />

Chapter 8. Working with .NET data providers 277


Method Description<br />

Int64 Seek(offset, whence) Changes the current position within the<br />

large object<br />

void FromFile(filename, appendTosLOB,<br />

fileLocation)<br />

String ToFile(filename, mode,<br />

fileLocation)<br />

void Lock(sLOBOffset, whence, range,<br />

lockMode)<br />

void Unlock(sLOBOffset, whence,<br />

range)<br />

Creating a smart large object<br />

You can use the GetIfxClob() and GetIfxBlob() methods of the<br />

IfxConnection() object to create a large object. To create a large object:<br />

1. Create an instance of a the large object, IfxClob or IfxBlob.<br />

2. Open the large object.<br />

3. Write data into the large object.<br />

4. Execute the SQL Statement using the IfxClob or IfxBlob classes as a<br />

parameter for the statement.<br />

5. Close the large object.<br />

Example 8-19 demonstrates how to update a CLOB column. The code reads a<br />

text file, sample_blob.cs, and uses the contents for the CLOB data.<br />

Example 8-19 The lo_create.cs sample<br />

using System;<br />

using System.IO;<br />

using System.Data;<br />

using <strong>IBM</strong>.Data.<strong>Informix</strong>;<br />

class sample {<br />

static void Main(string[] args) {<br />

IfxConnection conn;<br />

int urows=0;<br />

IfxClob vclob;<br />

char[] vclobBuff;<br />

278 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong><br />

Reads an operating system file and writes<br />

the complete content into the large object.<br />

Writes the contents of the large object to<br />

an operating system file<br />

Locks the complete large object or only a<br />

portion of the large object<br />

Unlocks a large object<br />

void Release() Frees database server resources<br />

void Close() Closes the large object


try {<br />

conn = new IfxConnection("Server=demo_on;Database=stores_demo");<br />

conn.Open();<br />

// Create and Open the Clob<br />

vclob = conn.GetIfxClob();<br />

vclob.Open(IfxSmartLOBOpenMode.ReadWrite);<br />

// Read a text file and insert into the clob<br />

vclobBuff = File.ReadAllText("lo_create.cs").ToCharArray();<br />

vclob.Write(vclobBuff);<br />

// Create the UPDATE Ifxcommand<br />

IfxCommand cmmd = conn.CreateCommand();<br />

cmmd.CommandText = "UPDATE catalog set advert_descr = ? WHERE" +<br />

" catalog_num = ?;";<br />

// Bind the IfxClob value and execute the UPDATE statement<br />

IfxParameter padvt_desc = new IfxParameter(null, vclob);<br />

IfxParameter pcatalog_n = new IfxParameter(null, "10072");<br />

cmmd.Parameters.Add(padvt_desc);<br />

cmmd.Parameters.Add(pcatalog_n);<br />

urows = cmmd.ExecuteNonQuery();<br />

Console.WriteLine("Updated rows: "+urows.ToString());<br />

// Close the IfxClob object<br />

vclob.Close();<br />

conn.Close();<br />

}<br />

catch (Exception e) {<br />

Console.WriteLine(e.Message);<br />

}<br />

}<br />

}<br />

If the application requires more control over the smart large object, it can use the<br />

specific properties of the ifxClob and IfxBlob classes to set up values, such as<br />

in which smart BLOB space the large object should create or the maximum size.<br />

Example 8-20 Illustrates how to use the properties of the IfxBlob class.<br />

Example 8-20 Large object extended properties<br />

...<br />

// Create and Open the Clob<br />

vclob = conn.GetIfxClob();<br />

vclob.EstimatedSize = 5000;<br />

vclob.ExtentSize = 1000;<br />

vclob.Flags = (int) IfxSmartLOBCreateTimeFlags.DontKeepAccessTime |<br />

Chapter 8. Working with .NET data providers 279


...<br />

280 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong><br />

(int) IfxSmartLOBCreateTimeFlags.NoLog;<br />

vclob.MaxBytes = 10000;<br />

vclob.SBSpace = "sbspace";<br />

vclob.Open(IfxSmartLOBOpenMode.ReadWrite);<br />

Selecting a smart large object<br />

Reading a large object using the large object extensions requires the following<br />

steps:<br />

1. Execute the SQL statement, and retrieve the large object column.<br />

2. Open the large object.<br />

3. Read from the large object into an application buffer.<br />

4. Close the large object.<br />

Example 8-21 shows how to read a large object column from a database table.<br />

Example 8-21 The lo_select.cs sample<br />

using System;<br />

using System.Data;<br />

using <strong>IBM</strong>.Data.<strong>Informix</strong>;<br />

class sample {<br />

static void Main(string[] args) {<br />

IfxConnection conn;<br />

IfxClob vclob;<br />

int maxSize = 2000;<br />

char[] vclobBuff = new char[maxSize];<br />

try {<br />

conn = new IfxConnection("Server=demo_on;Database=stores_demo");<br />

conn.Open();<br />

// Select the large object from the database<br />

IfxCommand cmmd = conn.CreateCommand();<br />

cmmd.CommandText = "SELECT * FROM catalog WHERE catalog_num = 10072";<br />

IfxDataReader drdr;<br />

drdr = cmmd.ExecuteReader();<br />

while (drdr.Read()) {<br />

// Get the large object. The clob is the 6th column<br />

vclob = drdr.GetIfxClob(5);<br />

// Open the large object<br />

vclob.Open(IfxSmartLOBOpenMode.ReadOnly);<br />

vclob.Read(vclobBuff, 0, maxSize, 0, IfxSmartLOBWhence.Current);


Console.WriteLine(vclobBuff);<br />

// Close the large object<br />

vclob.Close();<br />

}<br />

}<br />

}<br />

conn.Close();<br />

}<br />

catch (Exception e) {<br />

Console.WriteLine(e.Message);<br />

}<br />

Random access<br />

One of the benefits of smart large objects over a normal large object is the option<br />

of reading partial data.<br />

The Read(buff, buffOffset, BytesToRead, loOffset, whence) method allows<br />

you to position the data pointer anywhere in the large object data and read from<br />

there.<br />

Example 8-22 shows how to read the last 10 bytes of a large object.<br />

Example 8-22 Partial large object read<br />

...<br />

// Read only the last 10 bytes of large object<br />

int bytesToRead = 10;<br />

vclob.Read(vclobBuff, 0, bytesToRead, (-1) * bytesToRead,<br />

IfxSmartLOBWhence.End);<br />

...<br />

Smart large objects support random I/O access. Using the Seek(offset,<br />

whence) method, you can position the data pointer anywhere in the large object<br />

and perform I/O operations with the data.<br />

Example 8-23 demonstrates how to update only a portion of a large object using<br />

the Seek() method.<br />

Example 8-23 A lo_seek.cs sample<br />

using System;<br />

using System.Data;<br />

using <strong>IBM</strong>.Data.<strong>Informix</strong>;<br />

class sample {<br />

static void Main(string[] args) {<br />

Chapter 8. Working with .NET data providers 281


IfxConnection conn;<br />

IfxClob vclob;<br />

int urows=0;<br />

int maxSize = 100;<br />

char[] vclobBuff = new char[maxSize];<br />

try {<br />

282 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong><br />

conn = new IfxConnection("Server=demo_on;Database=stores_demo");<br />

conn.Open();<br />

// Select the large object from the database<br />

IfxCommand cmmd = conn.CreateCommand();<br />

cmmd.CommandText = "SELECT * FROM catalog WHERE catalog_num = 10072";<br />

IfxDataReader drdr;<br />

drdr = cmmd.ExecuteReader();<br />

drdr.Read();<br />

// Get the large object. The clob is the 6th column<br />

vclob = drdr.GetIfxClob(5);<br />

// Open the large object<br />

vclob.Open(IfxSmartLOBOpenMode.ReadWrite);<br />

// Move the pointer 15 bytes from the beginning of the large object.<br />

vclob.Seek(15,IfxSmartLOBWhence.Begin);<br />

// Update the large object.<br />

vclobBuff="//------------//".ToCharArray();<br />

vclob.Write(vclobBuff);<br />

drdr.Close();<br />

// Update the column in the table<br />

cmmd.CommandText = "UPDATE catalog set advert_descr = ? WHERE" +<br />

" catalog_num = ?;";<br />

// Bind the IfxClob value and execute the UPDATE statement<br />

IfxParameter padvt_desc = new IfxParameter(null, vclob);<br />

IfxParameter pcatalog_num = new IfxParameter(null, "10072");<br />

cmmd.Parameters.Add(padvt_desc);<br />

cmmd.Parameters.Add(pcatalog_num);<br />

urows = cmmd.ExecuteNonQuery();<br />

Console.WriteLine("Updated rows: "+urows.ToString());<br />

// Close the large object<br />

vclob.Close();<br />

}<br />

}<br />

conn.Close();<br />

}<br />

catch (Exception e) {<br />

Console.WriteLine(e.Message);<br />

}<br />

Note: Data Server Provider for .NET does not support random I/O access.


IfxDateTime<br />

The IfxDateTime class represents the <strong>Informix</strong> DATETIME data type. The<br />

IfxDateTime class provides support for all the precisions that are allowed in an<br />

<strong>Informix</strong> DATETIME.<br />

The <strong>Informix</strong> DATETIME data type is composed of the following time units:<br />

► Year<br />

► Month<br />

► Day<br />

► Hour<br />

► Minute<br />

► Second<br />

► Fractions of a second<br />

In an <strong>Informix</strong> database, the maximum precision for a DATETIME column is YEAR<br />

TO FRACTION(5). A DATETIME column can be defined with any precision, from a<br />

year to fraction of a second allowing any subset of these units.<br />

Table 8-15 lists the public properties of the IfxDateTime class.<br />

Table 8-15 Public properties of the IfxDateTime class<br />

Property Type Description<br />

Date IfxDateTime A Year to Day IfxDateTime instance<br />

Day Int32 The day portion of the value<br />

EndTimeUnit IfxTimeUnit The end time unit of the instance<br />

Hour Int32 The hour portion of the value<br />

MaxValue IfxDateTime Maximum value allowed for this IfxDateTime<br />

Millisecond Int32 Millisecond unit in this IfxDateTime<br />

MinValue IfxDateTime Smallest value allowed for this IfxDateTime<br />

Minute Int32 Minute unit in this IfxDateTime<br />

Month Int32 Month unit in this ifxDateTime<br />

Now IfxDateTime Current date with a range of Year to Fraction (5)<br />

Second Int32 Second unit of this IfxDateTime<br />

StartTimeUnit IfxTimeUnit Start time unit of this IfxDateTime<br />

Ticks Int64 Ticks from midnight on 1 Jan 0001<br />

Today IfxDateTime Current time with a range of Year to Day<br />

Chapter 8. Working with .NET data providers 283


Property Type Description<br />

Year Int32 Year unit of the value<br />

Table 8-16 lists the public methods of the IfxDateTime class.<br />

Table 8-16 Public methods of the IfxDateTime class<br />

Method Description<br />

Add(IfxTimeSpan or IfxMonthSpan) Current value plus by object passed<br />

AddDays(days) Current value plus days passed<br />

AddMilliseconds(milliseconds) Current value plus milliseconds passed<br />

AddMinutes(minutes) Current value plus minutes passed<br />

AddMonths(months) Current value plus months passed<br />

AddSeconds(seconds) Current value plus seconds passed<br />

AddYears(years) Current value plus years passed<br />

Compare(ifxDT1, ifxDT1) Compare two IfxDateTime instances<br />

CompareTo(obj) Compare two IfxDateTime instances<br />

DaysInMonth(year, month) Number of days in the month of the year<br />

Equals(ifxDT1, ifxDT2) True if ifxDT1 is equal to ifxDT2<br />

GreaterThan(ifxDT1, ifxDT2) True if ifxDT1 is later than ifxDT2<br />

GreaterThanOrEqual(ifxDT1,<br />

ifxDT2)<br />

284 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong><br />

True if ifxDT1 is later or equal than ifxDT2<br />

LessThan(ifxDT1, ifxDT2) True if ifxDT1 is earlier than ifxDT2<br />

LessThanOrEqual(ifxDT1, ifxDT2) True if ifxDT1 is earlier or equal than ifxDT2<br />

NotEquals(ifxDT1, ifxDT2) True if ifxDT1 is different than ifxDT2<br />

Parse(dateTimeStr)<br />

Parse(dateTimeStr, start, end)<br />

Parse(dateTimeStr, format, start,<br />

end)<br />

New IfxDateTime with a value based on<br />

dateTimeStr<br />

ToString(), ToString (format) Value of the instance as a string


To access a DATETIME column in the database, the application uses the<br />

IfxGetDateTime() method from the IfxDataReader() object.<br />

Example 8-24 demonstrates how to select a DATETIME data type from a table.<br />

Example 8-24 The datetime.cs sample<br />

using System;<br />

using System.Data;<br />

using <strong>IBM</strong>.Data.<strong>Informix</strong>;<br />

class sample {<br />

static void Main(string[] args) {<br />

IfxConnection conn;<br />

IfxDateTime vdtime;<br />

try {<br />

conn = new IfxConnection("Server=demo_on;Database=stores_demo");<br />

conn.Open();<br />

// Select the datetime from the database<br />

IfxCommand cmmd = conn.CreateCommand();<br />

cmmd.CommandText = "SELECT * FROM cust_calls WHERE "<br />

+ "customer_num = 106";<br />

IfxDataReader drdr;<br />

drdr = cmmd.ExecuteReader();<br />

drdr.Read();<br />

// Get the IfxDateTime from the recordset, 2nd columnd<br />

vdtime = drdr.GetIfxDateTime(1);<br />

Console.WriteLine("Call:\t"+vdtime);<br />

Console.WriteLine("Hour :\t "+vdtime.Hour);<br />

Console.WriteLine("Minute:\t"+vdtime.Minute);<br />

conn.Close();<br />

}<br />

catch (Exception e) {<br />

Console.WriteLine(e.Message);<br />

}<br />

}<br />

}<br />

Example 8-25 shows the Hour and Minute units extracted from the IfxDateTime<br />

object.<br />

Example 8-25 Output of the datetime.cs sample<br />

C:\work>csc.exe /R:%INFORMIXDIR%\bin\netf20\<strong>IBM</strong>.Data.<strong>Informix</strong>.dll /nologo<br />

datetime.cs<br />

C:\work>datetime<br />

Call: 2008-06-12 08:20<br />

Chapter 8. Working with .NET data providers 285


Hour : 8<br />

Minute: 20<br />

C:\work>c<br />

Arithmetic operations between two IfxDateTime objects might return an<br />

lfxDateSpan() object or an IfxMonthSpan() object, depending on the precision<br />

that is used by the IfxDateTime objects.<br />

Example 8-26 shows the use of the IfxDateSpan() class.<br />

Example 8-26 The datetime2.cs sample<br />

using System;<br />

using System.Data;<br />

using <strong>IBM</strong>.Data.<strong>Informix</strong>;<br />

class sample {<br />

static void Main(string[] args) {<br />

IfxConnection conn;<br />

IfxDateTime vdtime,vrestime;<br />

IfxTimeSpan vtimetaken;<br />

try {<br />

286 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong><br />

conn = new IfxConnection("Server=demo_on;Database=stores_demo");<br />

conn.Open();<br />

// Select the datetime from the database<br />

IfxCommand cmmd = conn.CreateCommand();<br />

cmmd.CommandText = "SELECT * FROM cust_calls WHERE "<br />

+ "customer_num = 106";<br />

IfxDataReader drdr;<br />

drdr = cmmd.ExecuteReader();<br />

drdr.Read();<br />

// Get the IfxDateTime from the recordset<br />

vdtime = drdr.GetIfxDateTime(1);<br />

vrestime = drdr.GetIfxDateTime(5);<br />

// Stores the difference in an IfxTimeSpan object.<br />

vtimetaken=vrestime-vdtime;<br />

Console.WriteLine("Initiated at:\t"+vdtime);<br />

Console.WriteLine("Resolved at:\t"+vrestime);<br />

Console.WriteLine("Minutes taken:\t"+vtimetaken.Minutes);<br />

conn.Close();<br />

}<br />

catch (Exception e) {<br />

Console.WriteLine(e.Message);<br />

}<br />

}<br />

}


IfxDecimal<br />

An IfxDecimal object represents the <strong>Informix</strong> decimal data type. The DECIMAL<br />

data type on an <strong>Informix</strong> database can take two forms:<br />

► DECIMAL(p) floating point<br />

► DECIMAL(p,s) fixed point<br />

The IfxDecimal object in <strong>Informix</strong> .NET Provider supports both versions.<br />

Table 8-17 contains the description of the public properties of an IfxDecimal<br />

object.<br />

Table 8-17 Public properties of the IfxDecimal class<br />

Property Type Description<br />

E IfxDecimal Irrational number e<br />

IsFloating Boolean Whether it is a floating number<br />

IsNull Boolean Whether it is NULL<br />

IsPositive Boolean Whether it is positive<br />

MaxPrecision Byte Maximum precision supported (32)<br />

MaxValue IfxDecimal Largest value allowed<br />

MinusOne IfxDecimal -1<br />

MinValue IfxDecimal Smallest value allowed<br />

Null IfxDecimal Null<br />

One IfxDecimal 1<br />

Pi IfxDecimal Irrational number pi<br />

Zero IfxDecimal 0<br />

Table 8-18 contains the description for the IfxDecimal public methods.<br />

Table 8-18 Public methods of the IfxDecimal object<br />

Method Description<br />

Abs(IfxDec) Absolute value of IfxDec<br />

Add(IfxDec1, IfxDec2) Sum of IfxDec1 and IfxDec2<br />

Ceiling(IfxDec) Smallest integer that is not less than IfxDec<br />

Clone() Creates a duplicate of this instance<br />

Chapter 8. Working with .NET data providers 287


Method Description<br />

Compare(IfxDec1, IfxDec2) Compares two IfxDecimal values<br />

CompareTo(obj) Compares current instance with object<br />

Divide(Dividend, Divisor) Dividing result for Dividend by Divisor<br />

Equals(obj) Equal<br />

Equals(IfxDec1, IfxDec2) True if IfxDec1 is the same as IfxDec2<br />

Floor(IfxDec) Largest integer not larger than IfxDec<br />

GreaterThan(IfxDec1, IfxDec2) True if IfxDec1 > IfxDec2<br />

GreaterThanOrEqual(IfxDec1,IfxDe<br />

c2)<br />

288 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong><br />

True if IfxDec1 >= IfxDec2<br />

LessThan(IfxDec1, IfxDec2) True if IfxDec1 < IfxDec2<br />

LessThanOrEqual(IfxDec1,<br />

IfxDec2)<br />

True if IfxDec1


An application uses the GetIfxDecimal() method from the IfxDataReader()<br />

class to access a DECIMAL column from the database.<br />

Example 8-27 demonstrates how to retrieve a DECIMAL column<br />

Example 8-27 The decimal.cs sample<br />

using System;<br />

using System.Data;<br />

using <strong>IBM</strong>.Data.<strong>Informix</strong>;<br />

class sample {<br />

static void Main(string[] args) {<br />

IfxConnection conn;<br />

IfxDecimal vtax;<br />

try {<br />

conn = new IfxConnection("Server=demo_on;Database=stores_demo");<br />

conn.Open();<br />

// Select the datetime from the database<br />

IfxCommand cmmd = conn.CreateCommand();<br />

cmmd.CommandText = "SELECT * FROM state WHERE "<br />

+ "code = 'CA'";<br />

IfxDataReader drdr;<br />

drdr = cmmd.ExecuteReader();<br />

drdr.Read();<br />

// Get the IfxDecimal from the recordset<br />

vtax = drdr.GetIfxDecimal(2);<br />

Console.WriteLine("Value Sales Tax :\t "+vtax);<br />

Console.WriteLine("Ceiling Sales Tax :\t " + IfxDecimal.Ceiling(vtax));<br />

Console.WriteLine("Negative Sales Tax :\t " + IfxDecimal.Negate(vtax));<br />

conn.Close();<br />

}<br />

catch (Exception e) {<br />

Console.WriteLine(e.Message);<br />

}<br />

}<br />

}<br />

Example 8-28 shows the output of the previous example.<br />

Example 8-28 Output of the decimal.cs sample<br />

C:\work>csc.exe /R:%INFORMIXDIR%\bin\netf20\<strong>IBM</strong>.Data.<strong>Informix</strong>.dll /platform:x86<br />

decimal.cs<br />

Chapter 8. Working with .NET data providers 289


C:\work>decimal<br />

Value Sales Tax : 0.0825<br />

Ceiling Sales Tax : 1.0<br />

Negative Sales Tax : -0.0825<br />

C:\work><br />

8.3.5 Troubleshooting<br />

In this section, we discuss typical errors that occur when using the .NET<br />

providers and how to enable the tracing facility to collect diagnostic information.<br />

Typical errors<br />

If the application fails to connect to the <strong>Informix</strong> database server, verify that<br />

connection string details are correct for the server and version of the .NET<br />

provider that you are using.<br />

Both .NET providers use the ODBC or CLI layer to communicate with the<br />

database server. You can test the connection with these components before<br />

using a .NET provider.<br />

When using <strong>Informix</strong> .NET Provider, always test the connectivity first using the<br />

iLogin utility that is included with Client SDK.<br />

Data Server Provider for .NET includes the Testconn11.exe and Testconn20.exe<br />

executables that you can use to diagnose connectivity and setup problems when<br />

using Data Server Provider for .NET.<br />

Table 8-19 lists typical errors and how to resolved them.<br />

Table 8-19 Typical errors<br />

Error Reason Solution<br />

ERROR [IM009] [<strong>Informix</strong> .NET<br />

provider]<br />

Unable to load translation<br />

shared library (DLL)<br />

System.BadImageFormatExcepti<br />

on: An attempt was made to<br />

load a program with an<br />

incorrect format<br />

290 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong><br />

The <strong>Informix</strong> .NET Provider<br />

failed to load the ODBC<br />

shared library.<br />

A 32-bit application is<br />

attempting to load a 64-bit<br />

<strong>IBM</strong>.Data.<strong>Informix</strong><br />

assembly.<br />

Verify that the values for the<br />

INFORMIXDIR environment variable<br />

and PATH are correct.<br />

INFORMIXDIR should point to the<br />

Client SDK installation directory, and<br />

PATH should contain the<br />

%INFORMIXDIR%\bin directory.<br />

Register the proper version of the<br />

.NET assembly into the GAC using<br />

the gacutil.exe tool.


Error Reason Solution<br />

Unhandled Exception:<br />

System.EntryPointNotFoundExc<br />

eption: Unable to find an<br />

entry point named<br />

'InterlockedIncrement' in DLL<br />

'kernel32.dll'.<br />

Unhandled Exception:<br />

System.DllNotFoundException:<br />

Unable to load DLL<br />

'IfxDotNetIntrinsicModule.dl<br />

l': The specified module<br />

could not be found.<br />

8.3.6 Tracing<br />

Your application can set the following types of tracing when using <strong>Informix</strong> .NET<br />

Provider:<br />

► <strong>Informix</strong> .NET Trace<br />

► SQLIDEBUG<br />

<strong>Informix</strong> .NET Trace<br />

This trace is specific to <strong>Informix</strong> .NET Provider. To use this feature, the<br />

application must use the Trace version of the <strong>IBM</strong>.Data.<strong>Informix</strong> assembly<br />

located in the %INFORMIXDIR%\netf20 directory. The name of shared library is<br />

<strong>IBM</strong>.Data.Trace.dll.<br />

Register the assembly in the GAC and enable the trace by setting the<br />

IFXDOTNETTRACE and IFXDOTNETTRACEFILE environment variables.<br />

Example 8-29 demonstrates how to register the trace library and generate a<br />

.NET trace file.<br />

Example 8-29 Trace setup<br />

C:\work>gacutil /i %INFORMIXDIR%\bin\netf20\<strong>IBM</strong>.Data.IfxTrace.dll /nologo<br />

Assembly successfully added to the cache<br />

C:\work>set IFXDOTNETTRACE=2<br />

A 64-bit application is<br />

attempting to load a 32-bit<br />

<strong>IBM</strong>.Data.Inforimx.dll<br />

assembly.<br />

Failed to load<br />

IfxDotNetIntrinsicModule<br />

assembly that is required by<br />

the 64-bit version of <strong>Informix</strong><br />

.NET Provider.<br />

C:\work>set IFXDOTNETTRACE=trace.txt<br />

C:\work>decimal<br />

Value Sales Tax : 0.0825<br />

Register the proper version of the<br />

.NET assembly into the GAC using<br />

the gacutil.exe tool.<br />

When using the 64-bit version of<br />

<strong>Informix</strong> .NET Provider, the PATH<br />

environment variable needs to define<br />

the %INFORMIXDIR%\bin and<br />

%INFORMIXDIR%\bin\netf20<br />

directories.<br />

Chapter 8. Working with .NET data providers 291


Ceiling Sales Tax : 1.0<br />

Negative Sales Tax : -0.0825<br />

C:\work>dir trace.txt<br />

Volume in drive C is W2003<br />

Volume Serial Number is 50DA-70D7<br />

Directory of C:\work<br />

25/06/2010 13:52 13,172 trace.txt<br />

1 File(s) 13,172 bytes<br />

0 Dir(s) 76,259,311,616 bytes free<br />

C:\work><br />

The .NET trace file contains information about all the .NET classes that are used<br />

and their return values. Example 8-30 shows some of the entries in the .NET<br />

trace file.<br />

Example 8-30 .NET Trace file<br />

...<br />

3532:1 Entry: IfxDecimal.ToString()<br />

3532:1 Exit: IfxDecimal.ToString<br />

IfxDecimal 0.0825<br />

3532:1 Entry: IfxDecimal.ToString()<br />

532:1 Exit: IfxDecimal.ToString<br />

IfxDecimal -1.0<br />

)<br />

3532:1 Entry: IfxDecimal.get_IsNull()<br />

3532:1 Exit: IfxDecimal.get_IsNull<br />

532:1 Exit: IfxDecimal.Multiply<br />

3532:1 Exit: IfxDecimal.Negate<br />

3532:1 Entry: IfxConnection.Close()<br />

3532:1 Entry: IfxConnection.GetLatch<br />

(<br />

String IfxConnection.Close<br />

)<br />

...<br />

292 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


The level of tracing is determine by the value of the IFXDOTNETTRACE variable:<br />

0 No tracing<br />

1 Tracing of API entry and exit, with return code<br />

2 Tracing of API entry and exit, with return code, plus tracing of parameters<br />

to the API<br />

Levels 3 and 4 are for internal use only.<br />

SQLIDEBUG and DRDADEBUG<br />

Refer to “SQLIDEBUG” on page 119 for the description and use of the<br />

SQLIDEBUG.<br />

8.4 Visual Studio Add-In for Visual Studio<br />

This section gives an overview of Visual Studio Add-in. The <strong>IBM</strong> Database<br />

Add-Ins for Visual Studio are a collection of features that integrate into Microsoft<br />

Visual Studio development environment so that you can work with <strong>IBM</strong> data<br />

servers.<br />

Visual Studio Add-in Version 9.5 is compatible with Visual Studio 2005, and it<br />

uses <strong>Informix</strong> .NET Provider to connect to the database server.<br />

Version 9.7 is compatible with Visual Studio 2005 and Visual Studio 2008 and<br />

uses Data Server Provider for .NET.<br />

Although it is not included in the Client SDK bundle, Visual Studio Add-in is<br />

available as a separate product. For more information, refer to:<br />

https://www.software.ibm.com/webapp/iwm/web/reg/download.do?source=swg-vsai<br />

Chapter 8. Working with .NET data providers 293


Visual Studio Add-In provides tools and wizards that simplify the .NET<br />

development for the following common tasks:<br />

► Explore catalog information of the database server.<br />

► Generate Data Definition Language (DDL) for database objects.<br />

► Drag server objects onto .NET application components to generate the<br />

required ADO.NET code automatically.<br />

To use Visual Studio Add-In, you first define the <strong>Informix</strong> server in the Data<br />

Connections group of the Visual Studio environment. Select the Add Connection<br />

to add a new server definition.<br />

In the Add Connection panel, specify the server name, server log on ID and<br />

password, and the database name.<br />

When the database is connected, you can drag the <strong>Informix</strong> tables from the<br />

Server Explorer pane to the .Net data set pane.<br />

For more details about using <strong>IBM</strong> Database Add-Ins and Data Server Provider<br />

for .NET for application development, refer to the <strong>IBM</strong> Information Management<br />

and Visual Studio .NET zone at:<br />

http://www.ibm.com/developerworks/data/zones/vstudio<br />

294 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Chapter 9. Working with PHP<br />

PHP is a powerful server-side scripting language that was invented and that is<br />

designed for creating dynamic web applications with non-static content. The PHP<br />

code can be a stand-alone program or an insert inside Hypertext Markup<br />

Language (HTML) or Extensible Hypertext Markup Language (XHTML). The<br />

PHP syntax is based mostly on and is similar to the C, Java, and Perl<br />

programming language. You can use PHP based on an open-source license.<br />

This chapter discusses the use of PHP with <strong>Informix</strong> as the database server. We<br />

discuss various PHP database extensions that you can use to connect to<br />

<strong>Informix</strong>. We also discuss other components, such as Apache Web Server and<br />

OpenAdmin Tool (OAT), and how to bring these components together. We<br />

describe in detail the use of programming interfaces that are provided by<br />

selected PHP database extensions through the use of various examples.<br />

This chapter includes the following topics:<br />

► <strong>Informix</strong> and PHP extensions<br />

► Setup and configuration<br />

► Developing a PHP application<br />

9<br />

© Copyright <strong>IBM</strong> Corp. 2010. All rights reserved. 295


9.1 <strong>Informix</strong> and PHP extensions<br />

The PHP Data Objects (PDO) extension defines a lightweight, consistent<br />

interface for accessing databases in PHP. Each database driver that implements<br />

the PDO interface can expose database-specific features as regular extension<br />

functions.<br />

<strong>Informix</strong> database can be accessed by PHP using the following PDO drivers:<br />

► PDO_INFORMIX<br />

This driver is also called PHP Driver for <strong>IBM</strong> <strong>Informix</strong>. To compile and use<br />

the driver, you must install <strong>Informix</strong> Client Software Development Kit (Client<br />

SDK). You can download this driver from:<br />

http://pecl.php.net/package/PDO_INFORMIX<br />

► PDO_<strong>IBM</strong><br />

This driver is also know as PHP Driver for Data Server clients. To use this<br />

driver, you must install <strong>IBM</strong> Data Server Driver for ODBC and CLI on the<br />

same computer. You can download this from:<br />

http://pecl.php.net/package/PDO_<strong>IBM</strong><br />

In addition to these two drivers, the following PHP extensions allow you to access<br />

an <strong>IBM</strong> <strong>Informix</strong> database:<br />

► PHP_INFORMIX<br />

This extension provides support only for standard <strong>Informix</strong> data types. This<br />

extension is developed by the open source community and is available at:<br />

http://cvs.php.net/viewvc.cgi/pecl/informix/<br />

► <strong>IBM</strong>_DB2<br />

This extension is available with <strong>IBM</strong> Data Server Driver and is written,<br />

maintained, and supported by <strong>IBM</strong>. It supports the <strong>Informix</strong> and DB2<br />

databases.<br />

Your application development environment, including hardware and software,<br />

determines which PHP drivers and extensions to use. If the platform of your<br />

choice is not supported by <strong>IBM</strong> Data Server Driver or if you are using some of the<br />

data types that are not supported by <strong>IBM</strong> Data Server Driver, then use the<br />

<strong>Informix</strong> driver. The Data Server Driver for ODBC and CLI requires an <strong>Informix</strong><br />

database of Version v11.x or later. If your database server is exclusively <strong>Informix</strong>,<br />

then you can use the <strong>Informix</strong> driver. You can also use both drivers<br />

simultaneously if needed.<br />

296 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


9.2 Setup and configuration<br />

9.2.1 Installing OAT<br />

To develop a PHP application for <strong>Informix</strong>, your application development system<br />

must have the following software:<br />

► PHP drivers and extensions<br />

Choose one of the PHP drivers or extensions that <strong>Informix</strong> supports. The<br />

PHP Driver for <strong>IBM</strong> <strong>Informix</strong> requires Client SDK and the PHP Driver for Data<br />

Server clients requires the <strong>IBM</strong> Data Server Driver for ODBC and CLI. Refer<br />

to 2.2, “Client setup” on page 34 for the details.<br />

► Web server<br />

You can either install Apache Web Server or use OpenAdmin Tool (OAT),<br />

which is a PHP-based web browser administration tool. Installing OAT is an<br />

easier option, because it contains everything that is required for PHP<br />

connectivity. At the time of writing this book, OAT version 2.2.7 has the<br />

following components:<br />

– Apache 2.2.4<br />

– PHP 5.2.4<br />

– PDO_INFORMIX 1.2.6<br />

In this section, we discuss OAT installation and driver configuration. For<br />

information about how to install the latest Apache Web Server, refer to the<br />

following website:<br />

http://httpd.apache.org/<br />

OpenAdmin Tool (OAT) is available for Windows, Linux, and Macintosh OS X<br />

(64-bit only) at:<br />

http://www.openadmintool.org<br />

This website leads you to the <strong>IBM</strong> site, where you must register and log in.<br />

After you complete the download, the installation procedure is as follows:<br />

1. Start the installation with one of the following methods:<br />

– GUI mode<br />

Launch the installation executable using one of the following commands:<br />

On Windows systems: Run install.exe.<br />

On Linux: Run install.bin.<br />

On MAC OS X: Extract the install.zip file, and run install.app.<br />

Chapter 9. Working with PHP 297


– Console mode<br />

Enter one of the following commands:<br />

On Windows systems: install.exe -i console<br />

On Linux: install.bin -i console<br />

2. Accept the license agreement to continue.<br />

3. Select the installation directory. The default directory is as follows:<br />

– For Windows systems: C:\Program Files\OpenAdmin<br />

– For Linux: /opt/OpenAdmin<br />

– For MAC OS X: /Applications/OpenAdmin/<br />

4. Choose an available port number for the web server.<br />

5. For Windows operating system users, provide an Apache service name.<br />

6. Specify the host name, which is the name of the computer where the<br />

database server is located.<br />

7. In the Security Features panel, enable password-protection for OAT<br />

administration pages.<br />

8. In the OAT Administrator login setup panel, enter a user name and password.<br />

9. In the Plug-in page, ensure that the plug-ins that you want to install are<br />

selected. Accept the license agreement.<br />

10.In the Pre-Installation Summary panel, review your selections and proceed<br />

with the installation. When the installation is complete, the following message<br />

displays:<br />

OpenAdmin Tool has been installed successfully. Please visit<br />

http://servername:portnumber/openadmin/ to use the OpenAdmin Tool<br />

Where:<br />

– servername is the name of the system where the web server is running.<br />

This name can be localhost on Windows.<br />

– portnumber is the port number that you provided in step 4.<br />

11.Click Done.<br />

– For Windows systems: You need to reboot. You can access OAT from the<br />

Start � All Programs � OpenAdmin Tool for IDS.<br />

– For Linux and MAC OS X: The OAT configuration page opens in your<br />

default web browser.<br />

For an insight into OAT, read the release notes and the README file that are<br />

bundled with the product.<br />

298 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


9.2.2 Verifying the PDO_INFORMIX setup<br />

We discuss the installation of the PDO_INFORMIX driver in 2.2.3, “Setting up<br />

<strong>IBM</strong> Data Server drivers” on page 43. The PDO_INFORMIX driver is installed<br />

automatically when you install OAT.<br />

We use the PDO_INFORMIX driver and the Apache Web Server that is installed<br />

with OAT in a Windows system for the examples in this chapter.<br />

On successful installation of OAT, the php_pdo_informix.ddl shared library (.so<br />

extension in Linux) is placed in the PHP extension directory. For example, if your<br />

installation directory is C:\Program FIles\OpenAdmin, the shared library is in the<br />

C:\Program Files\OpenAdmin\PHP_5.2.4\ext directory.<br />

To verify that the PHP extensions are working, enter the following URL in a web<br />

browser:<br />

http://localhost:8080/phpinfo.php<br />

9.2.3 Verifying the PDO setup<br />

We discuss the installation of the PDO_<strong>IBM</strong> driver in 2.2.3, “Setting up <strong>IBM</strong> Data<br />

Server drivers” on page 43. Depending on your platform copy, add the .dll or<br />

.so to the OAT extension directory and change the php.ini to include the<br />

extension php_pdo_ibm.dll or php_pdo_ibm.so.<br />

You can see which PDO driver is loaded by the Apache Web Server by typing the<br />

following address in your browser:<br />

http://localhost:8080/phpinfo.php<br />

Chapter 9. Working with PHP 299


9.2.4 Verifying connectivity<br />

You can use a simple PHP program to verify the connectivity to the <strong>Informix</strong><br />

server using the installed <strong>Informix</strong> PHP drivers or extensions.<br />

Example 9-1 shows a simple PHP script that connects to the database server<br />

using the PDO_INFORMIX driver. In the conn_string variable, set the proper<br />

host name, user name, password, and respective locales. The first keyword in<br />

the connection string identifies the PDO driver that is used. The<br />

PDO_INFORMIX driver uses informix, and the PDO_<strong>IBM</strong> driver uses ibm.<br />

Example 9-1 The connect.php program<br />


You can use the same script to test the connectivity using the PDO_<strong>IBM</strong> driver by<br />

just changing the connection string. Example 9-2 shows a typical connection<br />

string using the PD_<strong>IBM</strong> driver.<br />

Example 9-2 PDO_<strong>IBM</strong> connection string<br />

$conn_string = "ibm: DRIVER={<strong>IBM</strong> DB2 ODBC<br />

DRIVER};DATABASE=stores_demo;HOSTNAME=kodiak;PORT=9089;PROTOCOL=TCPIP;";<br />

At this point, you know that your environment is set up properly, and you are<br />

ready to begin using PHP with <strong>Informix</strong>.<br />

9.3 Developing a PHP application<br />

PHP is a powerful, server-side scripting language that was invented and<br />

designed for creating dynamic web applications with non-static content. The PHP<br />

code can be a stand-alone program or an insert inside Hypertext Markup<br />

Language (HTML) or Extensible Hypertext Markup Language (XHTML). The<br />

PHP syntax is based mostly on and similar to C, Java, and Perl. You can use<br />

PHP with an open-source license. You can run the PHP program directly from the<br />

command line.<br />

We chose PHP for our applications for the following reasons:<br />

► Easy to use<br />

PHP is a scripting language that is included directly in HTML. Thus, getting<br />

started is easy. There is no need to compile PHP programs or spend time<br />

learning tools to create PHP. You can simply insert statements and get quick<br />

turnaround as you make changes.<br />

► Fully functional<br />

The PHP language has built-in functions to access your favorite database.<br />

With PHP, your HTML pages can reflect current information from databases.<br />

You can use information for the user who is viewing your HTML web page to<br />

customize the page specifically for that user. You can create classes for<br />

object-oriented programming or use flat file or Lightweight Directory Access<br />

Protocol (LDAP) databases. It also includes a spelling checker, XML<br />

functions, image generation functions, and more.<br />

► Compatible and quick<br />

Because PHP generates plain HTML, PHP is compatible with all web<br />

browsers.<br />

Chapter 9. Working with PHP 301


► Secure<br />

Although PHP is open source, it is a secure environment. Web clients can<br />

only see the pure HTML code. The logic of the PHP program is never<br />

exposed to the client; therefore, security exposures are reduced.<br />

► Open source<br />

PHP is an open-source programming language. It is easy to get started and<br />

find examples from websites. For example:<br />

http://www.sourceforge.net<br />

9.3.1 Connecting to a database<br />

Regardless of which PHP driver you use, PDO_INFORMIX or PDO_<strong>IBM</strong>, you<br />

must decide the type of connection to use for any database connection and the<br />

user type to use for authentication.<br />

Connection type<br />

The following connection type behavior is controlled by the web server:<br />

► Persistent connection<br />

For the persistent connection, the web server leaves the connection to the<br />

database open after the PHP script completes its work. The next attempt to<br />

connect to the database with the same parameters reuses the connection.<br />

► Standard connection<br />

For the standard connection, the database connection is closed when the<br />

script completes its execution.<br />

Here are some considerations for persistent connection:<br />

► When using the persistent connection, the same connection is used for the<br />

next request with the same connection parameters. This connection might<br />

cause connection pooling, depending on the implementation and how you<br />

decide whether the connection is reused. Unintentional connection pooling is<br />

most likely a source of serious problems, even if you use transactions.<br />

► Opening up a persistent connection makes sense only in a web server<br />

environment if the connection is not closed in the same script with a<br />

connection close call. Calling the PHP command line processor on the shell<br />

closes the connection to the <strong>Informix</strong> database server at the end of the<br />

execution of the script.<br />

302 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


► The web server spawns more than one process to handle the incoming web<br />

requests. So, reusing the existing persistent connection is valid only for a<br />

specific web server process. It results in the database server having more<br />

connections open than actual running web server processes.<br />

► Restarting the database server without cleaning up the remaining persistent<br />

connections in the web server environment produces no errors at connection<br />

time when the connection is reused but fails at the first database statement.<br />

This type of error is hard to diagnose.<br />

The user type<br />

The user type is controlled by the database and has to do with authentication at<br />

the database server. You can choose an authentication with user ID and<br />

password in the connection string or a trusted user connect where the database<br />

server does not apply an authentication. This connection is controlled by settings<br />

on operating system resources, such as .rhosts or /etc/hosts.equiv files.<br />

Because you have to specify user names and passwords in the PHP scripts, pay<br />

attention to these files in regard to security. Use encapsulation for files that<br />

contain passwords, and put these files in directories that are secured with the<br />

.htaccess or httpd.conf mechanism of the Apache Web Server.<br />

<strong>Informix</strong> PDO requires, at connection time, a defined set of parameters:<br />

► Database name<br />

► Database server name<br />

We suggest that you use a user ID and password for untrusted user sessions.<br />

Some optional parameters can influence the cursor behavior. In this section, we<br />

focus on the required connection parameters.<br />

Example 9-3 gives an overview about the various parameter settings in an<br />

attempt to connect to the <strong>Informix</strong> database server. The examples shown are for<br />

the PDO_INFORMIX driver. Choose one of the connection statements that<br />

meets your requirements.<br />

Example 9-3 The PDO_INFORMIX driver connection strings<br />

/*--- standard connect ---*/<br />

$dbc = new PDO("informix:; database=sysmaster;<br />

server=ol_svr_custom;","informix", "123456");<br />

/*--- standard connect trusted user ---*/<br />

$dbc = new PDO("informix:; database=sysmaster; server=ol_svr_custom;");<br />

/*--- persistent connect untrusted user ---*/<br />

$dbc = new PDO("informix:; database=sysmaster;<br />

server=ol_svr_custom;","informix","123456",array(PDO::ATTR_PERSISTENT=> true));<br />

Chapter 9. Working with PHP 303


*--- persistent connect trusted user ---*/<br />

$dbc = new PDO("informix:; database=sysmaster;<br />

server=ol_svr_custom;",NULL,NULL,array(PDO::ATTR_PERSISTENT=> true));<br />

The PDO_<strong>IBM</strong> driver is based on the Data Server Driver CLI driver. Thus, it uses<br />

the same connectivity information as the ODBC and CLI driver. You can store this<br />

information, as well as user credentials, in the db2cli.ini file that is located in<br />

the user profile directory. Example 9-4 shows an example db2cli.ini file.<br />

Example 9-4 An example db2cli.ini file<br />

[dsc_dsn]<br />

Protocol=TCPIP<br />

Port=9089<br />

Hostname=kodiak<br />

Database=stores_demo<br />

PWD=password<br />

UID=password<br />

Having the details inside the db2cli.ini file makes it easier to manage the<br />

information that is needed for the connection. You can use either of the<br />

connection strings mentioned in the Example 9-5. The second conn_string uses<br />

the dbscli.ini file shown in Example 9-4 on page 304.<br />

Example 9-5 PDO_<strong>IBM</strong> connection strings<br />

$conn_string = "ibm: DRIVER={<strong>IBM</strong> DB2 ODBC DRIVER};DATABASE=stores_demo;<br />

HOSTNAME=kodiak;PORT=9089;PROTOCOL=TCPIP;";<br />

$conn_string = "ibm: DSN=dsc_dsn";<br />

9.3.2 Performing database operations<br />

<strong>Informix</strong> supports both static and dynamic SQL statements for the client<br />

applications such as PHP programs. In this section, we provide an in-depth<br />

discussion about the abilities of handling dynamic and static SQL of PDO<br />

<strong>Informix</strong>. We focus on the INSERT statement but also give short examples for the<br />

DELETE and UPDATE statements.<br />

304 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Static SQL statements<br />

Example 9-6 shows various methods to execute a static INSERT with <strong>Informix</strong><br />

PDO.<br />

Example 9-6 INSERT, UPDATE, and DELETE using the PDO_INFORMIX driver<br />


In a web application, the input data frequently comes from an HTML form that is<br />

entered by a web user. Example 9-7 shows, based on a simple HTML form, how<br />

the data flows from the HTML over the PHP script into the database table.<br />

Example 9-7 HTML sample<br />

basic html format<br />

<br />

Example 9-8 shows the PHP script that handles the HTML form. The $_POST<br />

array contains all the settings for the buttons and the values for the text fields<br />

from the HTML.<br />

Example 9-8 PHP Script handling the insert<br />


$dbc->query($statement);<br />

$error=$dbc->errorInfo();<br />

if ( $error["1"]) {<br />

printf(" prepare insert failed with %s \n",$error["1"]);<br />

exit(1);<br />

}<br />

?><br />

Example 9-9 shows how to perform an update and a delete using the PDO<br />

<strong>Informix</strong> extension.<br />

Example 9-9 Update a PHP script<br />


Dynamic SQL statements<br />

Dynamic SQL statements allow an <strong>Informix</strong> client side program to build an SQL<br />

statement at run time, so that the content of the statement can be determined by<br />

user input. <strong>Informix</strong> PDO provides several methods to use dynamic SQL. You<br />

must use placeholders, such as “?” or “:parameter” to prepare a statement for<br />

dynamic usage. These placeholders are later substituted with the values.<br />

The “prepare once, execute multiple times” capability of dynamic statements<br />

allows you to specify different values at each execution time. To determine which<br />

statements and clauses allow placeholders, refer to:<br />

http://publib.boulder.ibm.com/infocenter/idshelp/v115/topic/com.ibm.sqls.doc/sqls<br />

.htm<br />

This document also provides a comprehensive reference of <strong>Informix</strong> SQL<br />

statements.<br />

Example 9-10 shows different INSERT statements using <strong>Informix</strong> PDO. To learn<br />

more about using placeholders (“?”) and bind parameters, refer to PHP manual<br />

at:<br />

http://php.net/manual/en/pdostatement.bindparam.php<br />

Example 9-10 INSERT statements using <strong>Informix</strong> PDO<br />


printf(" prepare insert2 failed with %s \n",$error["1"]);<br />

exit(1);<br />

}<br />

/*--- dynamic inserts with : placeholders and bindParam ---*/<br />

$stmt=<br />

$dbc->prepare("INSERT INTO customer VALUES (0,:p1,:p2,:p3,:p4,:p5,:p6,:p7,:p8,:p9)");<br />

$stmt->bindParam(':p1', $_POST["fname"]);<br />

$stmt->bindParam(':p2', $_POST["lname"]);<br />

$stmt->bindParam(':p3', $_POST["company"]);<br />

$stmt->bindParam(':p4', $_POST["address1"]);<br />

$stmt->bindParam(':p5', $_POST["address2"]);<br />

$stmt->bindParam(':p6', $_POST["city"]);<br />

$stmt->bindParam(':p7', $_POST["state"]);<br />

$stmt->bindParam(':p8', $_POST["zipcode"]);<br />

$stmt->bindParam(':p9', $_POST["phone"]);<br />

$stmt->execute();<br />

$error=$dbc->errorInfo();<br />

if ( $error["1"]) {<br />

printf(" prepare insert2 failed with %s \n",$error["1"]);<br />

exit(1);<br />

}<br />

/*--- dynamic inserts with "?" placeholders and bindValue ---*/<br />

$stmt=<br />

$dbc->prepare("INSERT INTO customer VALUES (99,?,?,?,?,?,?,?,?,?)");<br />

$stmt->bindValue(1, $_POST["fname"],PDO::PARAM_STR);<br />

$stmt->bindValue(2, $_POST["lname"],PDO::PARAM_STR);<br />

$stmt->bindValue(3, $_POST["company"],PDO::PARAM_STR);<br />

$stmt->bindValue(4, $_POST["address1"],PDO::PARAM_STR);<br />

$stmt->bindValue(5, $_POST["address2"],PDO::PARAM_STR);<br />

$stmt->bindValue(6, $_POST["city"],PDO::PARAM_STR);<br />

$stmt->bindValue(7, $_POST["state"],PDO::PARAM_STR);<br />

$stmt->bindValue(8, $_POST["zipcode"],PDO::PARAM_STR);<br />

$stmt->bindValue(9, $_POST["phone"],PDO::PARAM_STR);<br />

$stmt->execute();<br />

$error=$dbc->errorInfo();<br />

if ( $error["1"]) {<br />

printf(" prepare insert3 failed with %s \n",$error["1"]);<br />

exit(1);<br />

}<br />

/*--- dynamic inserts with : placeholders and bindValue ---*/<br />

$stmt=<br />

$dbc->prepare("INSERT INTO customer VALUES<br />

(199,:p1,:p2,:p3,:p4,:p5,:p6,:p7,:p8,:p9)");<br />

$stmt->bindValue(':p1', $_POST["fname"],PDO::PARAM_STR);<br />

$stmt->bindValue(':p2', $_POST["lname"],PDO::PARAM_STR);<br />

$stmt->bindValue(':p3', $_POST["company"],PDO::PARAM_STR);<br />

$stmt->bindValue(':p4', $_POST["address1"],PDO::PARAM_STR);<br />

$stmt->bindValue(':p5', $_POST["address2"],PDO::PARAM_STR);<br />

$stmt->bindValue(':p6', $_POST["city"],PDO::PARAM_STR);<br />

$stmt->bindValue(':p7', $_POST["state"],PDO::PARAM_STR);<br />

$stmt->bindValue(':p8', $_POST["zipcode"],PDO::PARAM_STR);<br />

Chapter 9. Working with PHP 309


$stmt->bindValue(':p9', $_POST["phone"],PDO::PARAM_STR);<br />

$stmt->execute();<br />

$error=$dbc->errorInfo();<br />

if ( $error["1"]) {<br />

printf(" prepare4 insert failed with %s \n",$error["1"]);<br />

exit(1);<br />

}<br />

?>l<br />

9.3.3 Handling complex data types<br />

In this section, we discuss how to use complex data types in a PHP program. We<br />

cover row types, collection types (such as SET, LIST, and MULTISET), and the<br />

BLOB and SBLOB data types. We explain how to work with the complex data<br />

types using examples with <strong>Informix</strong> PDO.<br />

Named row types<br />

Example 9-11 shows the Data Definition Language (DDL) to create a ROW type<br />

and the table that uses the ROW type.<br />

Example 9-11 DDL for creating ROW type and table<br />

/*Create a row type and a table by name customer_rtype as below<br />

CREATE ROW TYPE address_rtype (<br />

street_num int,<br />

street_name char(20),<br />

city char(20),<br />

state char(20),<br />

zipcode char(10)<br />

);<br />

CREATE TABLE customer_rtype (<br />

customer_num serial,<br />

lname char(15),<br />

fname char(15),<br />

company char(20),<br />

address address_rtype,<br />

phone char(18)<br />

);<br />

310 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


The PHP script in Example 9-12 shows SQL statements using ROW type. This<br />

script inserts two rows and selects the data from the database with and without a<br />

filter on the row type. It then updates one of the rows and delete the rows from<br />

the table.<br />

Example 9-12 Insert complex types sample<br />


*--- Verification ---*/<br />

$stmt1=$dbc->query(' SELECT customer_num,fname, address::lvarchar FROM customer_rtype<br />

WHERE address = row(1234,"Almeda blvd","Fremont","CA","12345")::address_rtype');<br />

$row=$stmt1->fetch(PDO::FETCH_ASSOC);<br />

while($row) {<br />

print_r($row);<br />

printf("");<br />

$row=$stmt1->fetch(PDO::FETCH_ASSOC);<br />

}<br />

printf(" [ DELETE ] ");<br />

/*--- close the buisness ---*/<br />

$dbc->query(' DELETE FROM address_rowtype ');<br />

$dbc->query(' DELETE FROM customer_rtype ');<br />

?><br />

Example 9-13 shows the output from the SELECT statements to give you an idea<br />

of how the array with row types looks in PHP.<br />

Example 9-13 Output of ROW type example<br />

[ INSERT ]<br />

[ SELECT without row_type filter ]<br />

Array ( [CUSTOMER_NUM] => 1 [FNAME] => Gomes [CITY] => San Fransisco [STATE] => CA<br />

[PHONE] => 408-908-8887 )<br />

Array ( [CUSTOMER_NUM] => 2 [FNAME] => jones [CITY] => Fremont [STATE] => CA [PHONE] =><br />

345-908-8887 )<br />

[ SELECT with filter ]<br />

Array ( [CUSTOMER_NUM] => 2 [STATE] => CA [PHONE] => 345-908-8887 )<br />

[ UPDATE ]<br />

[ SELECT ]<br />

Array ( [CUSTOMER_NUM] => 2 [FNAME] => jones [] => ROW(1234 ,'Almeda blvd ','Fremont<br />

','CA ','12345 ') )<br />

[ DELETE ]<br />

312 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Collection data types<br />

The collection data types are another set of complex data types provided by the<br />

<strong>Informix</strong>. Collection data types include SET, LIST, and MULTISET. In this section,<br />

we cover these collection data types. Example 9-14 shows an example that<br />

inserts into and selects from a table containing collection data types.<br />

Example 9-14 Using collection data types in PHP<br />


$row=$stmt1->fetch(PDO::FETCH_ASSOC);<br />

while($row) {<br />

print_r($row);<br />

printf("");<br />

$row=$stmt1->fetch(PDO::FETCH_ASSOC);<br />

}<br />

?><br />

Example 9-15 shows the output of Example 9-14 on page 313.<br />

Example 9-15 The output of collection data type<br />

[ Insert ]<br />

[ SELECT without filter]<br />

Array ( [LIST] => LIST{-1 ,0 ,-2 ,3 ,0 ,0 ,32767 ,249 } [SET] => SET{-1 ,0 ,-2<br />

,3 } [MULTISET] => MULTISET{-1 ,0 ,0 ,-2 ,3 ,0 } )<br />

Array ( [LIST] => LIST{-1 ,0 ,-2 ,3 ,0 ,0 ,55555 ,249 } [SET] => SET{-11 ,0 ,-2<br />

,3 } [MULTISET] => MULTISET{-1 ,0 ,0 ,-2 ,3 ,0 ,9 ,10 } )<br />

[ SELECT with filter]<br />

Array ( [LIST] => LIST{-1 ,0 ,-2 ,3 ,0 ,0 ,32767 ,249 } [SET] => SET{-1 ,0 ,-2<br />

,3 } [MULTISET] => MULTISET{-1 ,0 ,0 ,-2 ,3 ,0 } )<br />

BLOB and SBLOB data types<br />

With BLOB and SBLOB data types, <strong>Informix</strong> IDS can handle large objects as<br />

binary data in a BYTE data type and text objects in a TEXT data type. The BYTE<br />

and TEXT data types, commonly known as BLOB data types or simple large<br />

objects, provides the capability to store images and entire documents in the<br />

database. BLOB data types can be stored within all the other data in the table<br />

space or in a separate specified BLOB space.<br />

BLOB data types can be used in several operational areas. Commonly,<br />

document retrieval systems and geographic information systems are based on<br />

this data type. To retrieve BLOB data with SQL, you need to define keywords,<br />

which are stored together with the BLOB in the data row. The benefit of storing<br />

large data in the database is, in addition to an easy search using keywords and a<br />

combination of data stored in different rows but belonging together, the<br />

opportunity to backup and restore or delete and update for specific data. Storing<br />

the data in a file in the operating system is much more of a maintenance effort.<br />

314 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


More advanced than the BLOB data types, smart large objects (commonly<br />

known as SBLOB), provide more flexibility for searching data, such as random<br />

I/O access to the data, which was impossible with simple large objects).<br />

There are two types of SBLOBs, BLOB, and CLOB. The BLOB data type is used<br />

to stored binary data when the CLOB data type is used only for character data.<br />

There types require an additional set of functions defined in the server that<br />

provides an API for access. They are stored in an SBLOB space (smart BLOB<br />

space) in the database server.<br />

You must create an sbspace to store the BLOB types in the server. You can<br />

create them with following command:<br />

onspaces -c -S sbspace -p -o 0 -s 4000<br />

We change the catalog table in the stores database to use BLOB and CLOB<br />

instead of BYTE and TEXT using the following command:.<br />

ALTER TABLE catalog MODIFY (cat_descr TEXT, cat_descr CLOB, cat_picture BYTE,<br />

cat_picture BLOB)<br />

Example 9-16 shows how to insert and retrieve from data with SBLOB data<br />

types, that is BLOB and CLOB. The example shows how to insert the large data<br />

from files into a table and how to select the same data back into files in a local file<br />

system.<br />

Example 9-16 Smart large object sample<br />


}<br />

/*--- Get the BLOB from the database back ---*/<br />

$query=$dbc->query("SELECT * FROM catalog where stock_num=302 and<br />

manu_code='KAR' ");<br />

$error=$dbc->errorInfo();<br />

if ( $error["1"]) {<br />

printf(" select blobs failed with %s \n",$error["1"]);<br />

exit(1);<br />

}<br />

$count=1;<br />

$row=$query->fetch(PDO::FETCH_ASSOC);<br />

while ( $row ) {<br />

$file = fopen ("README.$count.txt","w");<br />

$test=fread($row["CAT_DESCR"],100000);<br />

while($test) {<br />

fwrite ( $file, $test) ;<br />

$test=fread($row["CAT_DESCR"],100000);<br />

}<br />

fclose ( $file);<br />

$file = fopen ("PICTURE.$count.jpg","w");<br />

$test1=fread($row["CAT_PICTURE"],100000);<br />

while($test1) {<br />

fwrite ( $file, $test1) ;<br />

$test1=fread($row["CAT_PICTURE"],100000);<br />

}<br />

fclose ( $file);<br />

$count++;<br />

$row=$query->fetch(PDO::FETCH_ASSOC);<br />

}<br />

?><br />

Using TEXT and BYTE (BLOB data types) is similar to SBLOB types. Users can<br />

try Example 9-16 on page 315 and Example 9-17 using TEXT and BYTE instead<br />

of CLOB and BLOB respectively.<br />

The BLOB data to be inserted can be read from the file without placing it in a<br />

variable first, which simplifies the code as shown in Example 9-17.<br />

Example 9-17 Insert BLOB with file<br />


$stmt= $dbc->prepare("INSERT INTO catalog VALUES (0,302,'KAR',?,?,'All sports<br />

Goods')");<br />

$file = fopen ("C:\README.txt","r");<br />

$file1 = fopen ("C:\picture.jpg","r");<br />

$stmt->bindParam(1,$file, PDO::PARAM_LOB);<br />

$stmt->bindParam(2,$file1, PDO::PARAM_LOB);<br />

$stmt->execute();<br />

fclose($file);<br />

fclose($file1);<br />

$error=$dbc->errorInfo();<br />

if ( $error["1"]) {<br />

printf(" execute insert blobs failed with %s \n",$error["1"]);<br />

exit(1);<br />

}<br />

/*---try to get the BLOB from the database back ---*/<br />

$query=$dbc->query("SELECT * FROM catalog where stock_num=302 and<br />

manu_code='KAR' ");<br />

$error=$dbc->errorInfo();<br />

if ( $error["1"]) {<br />

printf(" select blobs failed with %s \n",$error["1"]);<br />

exit(1);<br />

}<br />

$count=1;<br />

$row=$query->fetch(PDO::FETCH_ASSOC);<br />

while ( $row ) {<br />

$file = fopen ("C:\README.$count.txt","w");<br />

$test=fread($row["CAT_DESCR"],100000);<br />

while($test) {<br />

fwrite ( $file, $test) ;<br />

$test=fread($row["CAT_DESCR"],100000);<br />

}<br />

fclose ( $file);<br />

$file = fopen ("C:\PICTURE.$count.jpg","w");<br />

$test1=fread($row["CAT_PICTURE"],100000);<br />

while($test1) {<br />

fwrite ( $file, $test1) ;<br />

$test1=fread($row["CAT_PICTURE"],100000);<br />

}<br />

fclose ( $file);<br />

$count++;<br />

$row=$query->fetch(PDO::FETCH_ASSOC);<br />

}<br />

?><br />

Chapter 9. Working with PHP 317


In Example 9-17 on page 316, the data was selected as a stream in string data<br />

type. Example 9-18 shows how to bind variables to a SELECT. The data is<br />

placed in the variables by column.<br />

Example 9-18 Select BLOB with bind<br />


printf(" prepare update blob columns failed with %s \n",$error["1"]);<br />

exit(1);<br />

}<br />

$descr="This is an PDO descr clob text";<br />

$file= fopen ("C:\picture1.jpg","r");<br />

$stmt->bindParam(1, $descr);<br />

$stmt->bindParam(2, $file);<br />

$stmt->execute();<br />

$error=$dbc->errorInfo();<br />

?><br />

9.3.4 Working with PHP extensions<br />

In addition to the PDO drivers for the PHP PDO extension, there are two PHP<br />

extensions that allow you to connect to an <strong>Informix</strong> database server:<br />

► PHP_INFORMIX<br />

► <strong>IBM</strong>_DB2<br />

These extensions provide a set of additional PHP functions to work with an<br />

<strong>Informix</strong> database. In addition to the normal create, read, update, and write<br />

database operations, they also offer extensive access to the database metadata.<br />

Table 9-1 lists a few of the functions that are included in the <strong>Informix</strong> PHP<br />

extensions as examples.<br />

Table 9-1 PHP extension functions<br />

Function Description<br />

ifx_connect() Opens <strong>Informix</strong> Server connection<br />

ifx_fieldproperties() Lists of SQL field properties<br />

ifxus_open_slob() Opens an SLOB object<br />

ifx_create_blob() Creates an BLOB object<br />

ifx_fetch_row() Gets row as an associative array<br />

ifx_query() Sends <strong>Informix</strong> query<br />

db2_connect() Returns a connection to a database<br />

db2_client_info() Returns information describing DB2 database client<br />

db2_primary_keys() Returns a result set listing primary keys for a table<br />

db2_special_columns() Returns a result set listing the unique row identifier<br />

columns for a table<br />

Chapter 9. Working with PHP 319


Function Description<br />

db2_bind_param() Binds a PHP variable to an SQL statement parameter<br />

db2_commit() Commits a transaction<br />

For a complete list of all the functions that are implemented in the<br />

PHP_INFORMIX and <strong>IBM</strong>_DB2 extensions, refer to:<br />

http://www.php.net/manual/en/ref.ifx.php<br />

http://www.php.net/manual/en/ref.ibm-db2.php<br />

The PHP_INFORMIX extension<br />

A PHP script can connect to an <strong>Informix</strong> database using the ifx_connect()<br />

function that is provided in the PHP_INFORMIX extension.<br />

Example 9-20 shows a simple PHP script that tests connectivity with the<br />

PHP_INFORMIX extension.<br />

Example 9-20 The connect.php script<br />

C:\work>type connect.php<br />

<br />

C:\work>php connect.php stores_demo informix password<br />

Connection succeeded.<br />

C:\work><br />

You can use functions such as ifx_query() and ifx_affected_rows() to run<br />

SQL statements and to retrieve the number of rows affected. Example 9-21<br />

demonstrates how to delete a row from the state table using the ifx_query()<br />

function.<br />

Example 9-21 The delete.php script<br />

C:\work>type delete.php<br />


Deleted 1 records<br />

C:\work><br />

The application can select data from an <strong>Informix</strong> database using the<br />

ifx_prepare() and ifx_fetch_row() functions.<br />

Example 9-22 shows how to select the first three rows from the state table using<br />

a prepared statement and the ifx_fetch_row() function.<br />

Example 9-22 The select.php script<br />

C:\work>cat select.php<br />

<br />

C:\work>php select.php<br />

code = AK sname = Alaska<br />

code = HI sname = Hawaii<br />

code = CA sname = California<br />

C:\work><br />

For more information and examples regarding the PHP_INFORMIX extension,<br />

refer to:<br />

http://www.php.net/manual/en/book.ifx.php<br />

Chapter 9. Working with PHP 321


The <strong>IBM</strong>_DB2 extension<br />

This PHP extension provides access to <strong>IBM</strong> Data Servers, including <strong>IBM</strong> <strong>Informix</strong><br />

and <strong>IBM</strong> DB2.<br />

In the same way as the PDO driver, PDO_<strong>IBM</strong>, the <strong>IBM</strong>_DB2 extension requires<br />

the <strong>IBM</strong> CLI driver to communicate with the database server. The <strong>IBM</strong> CLI driver<br />

is included as part of the <strong>IBM</strong> Data Server Driver for ODBC and CLI package.<br />

This PHP extension provides functions such as db2_connect(), db2_exec(), and<br />

db2_server_info() that you can use to perform typical tasks against an <strong>Informix</strong><br />

database server.<br />

Example 9-23 demonstrates how to use the db2_connect() and<br />

db2_server_info() functions to retrieve metadata information from the database.<br />

Example 9-23 The connect_ibm.php script<br />

C:\work>type "C:\Documents and Settings\Administrator\db2cli.ini"<br />

[dsc_dsn]<br />

Protocol=TCPIP<br />

Port=9089<br />

Hostname=kodiak<br />

Database=stores_demo<br />

C:\work>cat connect_ibm.php<br />

<br />

C:\work>php connect_ibm.php<br />

Connection succeeded.<br />

Database name = IDS/NT64<br />

Datbase version = 11.50.0000<br />

C:\work><br />

322 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


The <strong>IBM</strong>_DB2 extension can use the connection details in the db2cli.ini<br />

configuration file. Refer to the 3.2.2, “<strong>IBM</strong> Data Server Driver for ODBC and CLI”<br />

on page 70 for more information regarding the db2cli.ini configuration file.<br />

You can use several functions to select data from the database. Example 9-24<br />

shows how to use the db2_fecth_object() function to retrieve the first three rows<br />

of the state table as a PHP object.<br />

Example 9-24 The select_ibm.php script<br />

C:\work>cat select_ibm.php<br />

<br />

C:\work>php select_ibm.php<br />

Connection succeeded.<br />

AK, Alaska<br />

HI, Hawaii<br />

CA, California<br />

C:\work><br />

You can find a full description of the <strong>IBM</strong>_DB2 extension at:<br />

http://publib.boulder.ibm.com/infocenter/db2luw/v9/topic/com.ibm.db2.udb.apdv.p<br />

hp.doc/doc/t0023132.htm<br />

Chapter 9. Working with PHP 323


9.3.5 Exception handling<br />

Error handling or exception handling is important for all applications, including<br />

web-based applications. Consider an <strong>Informix</strong> PHP application that shows the<br />

following error message while the user is using the application:<br />

Warning: odbc_connect(): SQL error: [unixODBC][<strong>Informix</strong>][<strong>Informix</strong><br />

ODBCDriver][<strong>Informix</strong>]User (informix) password “123456” is not able to<br />

connect for the database server, Server is down, SQL state 28000 in<br />

SQLConnect in /usr/local/apache2/htdocs/odbc/error/error.php on line 4<br />

In this case, fail in exception handling creates a security exposure. In the this<br />

section, we describe many aspects related to exception handling using <strong>Informix</strong><br />

PDO.<br />

PHP 5 has introduced, as a part of the new object-oriented programming<br />

interface, the exception handling mechanism that is already used for other<br />

programming languages. We strongly suggest that you consider exceptions for<br />

the usage of <strong>Informix</strong> PDO. Additionally, you can advance this interface by<br />

creating, throwing, and catching your own exceptions.<br />

In comparison with the procedural-oriented interface, <strong>Informix</strong> PDO defines the<br />

following methods of expressing an error in a database environment:<br />

► Exceptions raised internally by the PDO based on an error condition<br />

► Database-generated errors, which can be captured and handled by calling the<br />

PDO class errorInfo() or errorCode() function<br />

Example 9-25 shows two exceptions raised by <strong>Informix</strong> PDO functions. One<br />

exception is a connection request to the database that failed because the<br />

specified database does not exist. The other exception is an attempt to start a<br />

transaction twice.<br />

Example 9-25 Without exception handling sample<br />

<br />

Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE=HY000,<br />

SQLDriverConnect: -329 [<strong>Informix</strong>][<strong>Informix</strong> ODBC Driver][<strong>Informix</strong>]Database not<br />

found or no system permission.' in C:\Program<br />

Files\OpenAdmin\Apache_2.2.4\htdocs\excep1.php:2 Stack trace: #0 C:\Program<br />

Files\OpenAdmin\Apache_2.2.4\htdocs\excep1.php(2): PDO->__construct('informix:;<br />

data...', 'informix', '123456') #1 {main} thrown in C:\Program<br />

Files\OpenAdmin\Apache_2.2.4\htdocs\excep1.php on line 2<br />

324 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Fatal error: Uncaught exception 'PDOException' with message 'There is already<br />

an active transaction' in C:\Program<br />

Files\OpenAdmin\Apache_2.2.4\htdocs\excep1.php:4 Stack trace: #0 C:\Program<br />

Files\OpenAdmin\Apache_2.2.4\htdocs\excep1.php(4): PDO->beginTransaction() #1<br />

{main} thrown in C:\Program Files\OpenAdmin\Apache_2.2.4\htdocs\excep1.php on<br />

line 4<br />

If these exceptions are not caught and processed, the application terminates.<br />

Example 9-26 shows the use of the basic exception handler provided by PHP 5<br />

to cover these errors. After an exception is caught, the action that is taken<br />

depends on where the error originates. For example, if the error occurs in<br />

connecting to the database phase and the application cannot continue, the action<br />

is to generate an “out of order” web page with contact details. If the error is a<br />

minor database error, logging the error and retrying the activity is an appropriate<br />

action.<br />

Example 9-26 Simple exception handle code<br />

<br />

Output:<br />

Error: There is already an active transaction.<br />

Chapter 9. Working with PHP 325


The error information that is generated when executing the SQL statements in<br />

the database server is different from the exceptions that are generated by the<br />

<strong>Informix</strong> PDO extension. You can use the <strong>Informix</strong> PDO errorInfo() function to<br />

capture the status of the last executed SQL statement in the database. This<br />

function returns an array with the following elements:<br />

► The SQLSTATE<br />

► The SQLCODE<br />

► The error message<br />

For the details about the meaning of the codes, refer to:<br />

http://publib.boulder.ibm.com/infocenter/idshelp/v115/topic/com.ibm.esqlc.doc/s<br />

ii-11-40709.htm#sii-11-40709<br />

The errorCode() function is available to retrieve the SQL statement status. This<br />

function returns only the SQLSTATE information. Example 9-27 shows how to<br />

use the errorInfo() function and its output.<br />

Example 9-27 ErrorInfo() sample<br />

<br />

Output:<br />

Array<br />

(<br />

[0] => 42S02<br />

[1] => -206<br />

[2] => [<strong>Informix</strong>][<strong>Informix</strong> ODBC Driver][<strong>Informix</strong>]The specified table<br />

(nonexistingtable) is not in the database. (SQLPrepare[-206] at at<br />

ext\pdo_informix\informix_driver.c:118)<br />

)<br />

In addition to using the generic exceptions provided by the PHP 5, you can<br />

extend the exception class of your own exceptions. For example, you can define<br />

different severities for SQL errors. Critical database errors are, for example tables<br />

326 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


that do not exist or the database connections, cannot be established. The<br />

application cannot continue with these critical errors. Non-critical errors, such as<br />

locking errors, can be handled by a retry.<br />

Example 9-28 demonstrates how to define your own exceptions with PHP 5 and<br />

<strong>Informix</strong> PDO. This example extends the standard exception class with two new<br />

database exception classes and, depending on the severity, different actions are<br />

taken.<br />

Example 9-28 Custom exceptions<br />


9.3.6 Troubleshooting<br />

printf("NonCritError!: %s \n",$ncde->getMessage()) ;<br />

} catch (PDOExecption $ncde) {<br />

printf("Error!: %s \n",$e->getMessage()) ;<br />

exit;<br />

}<br />

?><br />

Output:<br />

CritError!: [<strong>Informix</strong>][<strong>Informix</strong> ODBC Driver][<strong>Informix</strong>]The specified table (carr) is not<br />

in the database. (SQLPrepare[-206] at ext\pdo_informix\informix_driver.c:131)<br />

The following common errors can occur in setting the database connectivity:<br />

► Missing environment variable setting<br />

Setting the environment variable INFORMIXDIR is required for starting the<br />

Apache. If this variable is not set properly, the database connection also fails.<br />

Example 9-29 shows the error message when you have improper<br />

INFORMIXDIR set. The message occurs at the first line of any PHP program<br />

which is generally the connection string. If you get this message, verify that<br />

the INFORMIXDIR setting is correct.<br />

Example 9-29 Unspecified error<br />

Error!: SQLSTATE=HY000, SQLDriverConnect: -23101<br />

[<strong>Informix</strong>][<strong>Informix</strong> ODBC Driver][<strong>Informix</strong>]Unspecified System Error =<br />

-23101.<br />

► Mismatched settings<br />

Another important item affecting the connectivity is the setup of the <strong>Informix</strong><br />

runtime environment. <strong>Informix</strong> Connect or Client SDK provides the<br />

connectivity at run time. If the settings between the environment variables and<br />

the sqlhosts do not match, you receive messages similar to the one shown in<br />

Example 9-30.<br />

Example 9-30 Wrong connection information<br />

/usr/local/bin/php pdoconnect.php<br />

Error!: SQLSTATE=HY000, SQLDriverConnect: -25555<br />

[<strong>Informix</strong>] [<strong>Informix</strong> ODBC Driver][<strong>Informix</strong>]Server ol_svr_custom is not<br />

listed as a dbserver name in sqlhosts.<br />

328 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Chapter 10. User-defined routines<br />

In this chapter, we how to create and use user-defined routines (UDRs). A UDR<br />

is a routine that you create that can be invoked in an SQL statement by the<br />

database server or from another UDR. A routine is a collection of program<br />

statements that perform a particular task. By understanding UDRs, you can take<br />

the next step and extend the database server, either a little bit or in steps that<br />

lead to something bigger, such as a bladelet or DataBlade module.<br />

This chapter includes the following topics:<br />

► An overview of UDRs and database extensions<br />

► Developing UDRs<br />

► DataBlades and bladelets<br />

10<br />

Extending the database server requires an understanding of the components<br />

that are required to implement the extension. An extension can be as simple as<br />

one UDR or as complex as a new data type with many supporting routines. We<br />

first discuss UDRs and user-defined types (UDTs) to provide the scope for what<br />

is needed. Then we provide examples.<br />

© Copyright <strong>IBM</strong> Corp. 2010. All rights reserved. 329


10.1 An overview of UDRs and database extensions<br />

<strong>IBM</strong> <strong>Informix</strong> database servers have the built-in ability to retrieve, store,<br />

manipulate, and sort a number of standard data types, some of which are unique<br />

to <strong>Informix</strong> servers. A developer can choose to modify or extend the built-in data<br />

types and to modify or extend how various operations work with the resulting new<br />

data type extensions.<br />

You can extend the data types using the following methods:<br />

► Extend operations that are used to process built-in data types.<br />

► Create complex data types based on built-in data types.<br />

► Create UDTs, both distinct and opaque data types.<br />

► Create new operations to process extended data types.<br />

Database extensions and extended data types allow the developer to make<br />

customized routines and functions transparent, because you have the capability<br />

to actually build it into the database server. The transparency is visible as:<br />

► Better performance through optimized routines, faster queries, and reduced<br />

network traffic.<br />

► Simpler applications in streamlined code and easy to upgrade applications.<br />

► Transaction control with automatic recovery, backup, and rollback capability<br />

that is provided by the server.<br />

► Scalability because database extensions scale automatically with the<br />

database size and user count.<br />

In the context of discussing UDRs and database extensions, we also mention<br />

DataBlade modules. A DataBlade module is a software package that extends the<br />

functionality of the <strong>IBM</strong> <strong>Informix</strong> database server. Each package includes SQL<br />

statements and supporting code written in an external language or in Stored<br />

Procedure Language. A DataBlade module enables the same level of support for<br />

new data types as the database server provides for built-in data types.<br />

DataBlade modules can also use SQL queries or the DataBlade API to access<br />

data types and routines in other DataBlade modules.<br />

Note: Extended Parallel Server and Standard Engine support stored<br />

procedures but not UDRs.<br />

330 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


10.1.1 Considerations for UDRs<br />

A UDR can be written using the <strong>IBM</strong> <strong>Informix</strong> Stored Procedure Language (SPL)<br />

or with an external language. A routine written with SPL is simple to use and<br />

easy to implement. An SPL-based UDR has flow-control extensions (conditional<br />

clauses and while loops) and works with SQL statements. After the routine is<br />

created and is ready to use, the database server parses, optimizes, and stores it<br />

in system catalog tables so that it is ready to execute.<br />

The system catalog tables are used to keep track of the information the database<br />

server uses to manage the database server. UDR-related information is stored in<br />

a small group of catalog tables that provide information about the UDR layouts.<br />

UDRs include the following common catalog tables:<br />

► sysprocedures table<br />

Used to track the name and owner and to indicate whether the UDR is a<br />

user-defined function or a user-defined procedure (functions return values but<br />

procedures do not).<br />

► sysprocauth table<br />

Tracks who can execute the procedure.<br />

► sysprocbody table<br />

Contains the actual code for the SPL routines.<br />

UDRs can also be written with an external language. The body of an<br />

external-language routine allows language-based operations such as flow control<br />

and looping, while also using special <strong>Informix</strong> library calls to access the database<br />

server.<br />

The database server stores information for external-language routines in the<br />

following system catalog tables:<br />

► sysprocedures table<br />

The information kept in this table is same as the SPL UDR.<br />

► sysroutinelangs table<br />

This table tracks the language information.<br />

► syslangauth table<br />

This table tracks the users of the server who can use the particular external<br />

language.<br />

You need to use an appropriate compiler to parse and compile an<br />

external-language routine into an executable format. We discuss this with<br />

Chapter 10. User-defined routines 331


10.1.2 About UDRs<br />

specific examples of the language and API methods that are available for writing<br />

these extensions.<br />

The external languages that can be used are:<br />

► C<br />

To execute SQL statements in C UDRs, you must use the DataBlade API, and<br />

you cannot use ESQL/C. To write routines in C, you need a C compiler. YOu<br />

can find additional information about writing UDRs in C in the <strong>IBM</strong> <strong>Informix</strong><br />

DataBlade API Programmer’s Guide, Version 11.50, SC23-9429, and <strong>IBM</strong><br />

<strong>Informix</strong> DataBlade API Function Reference, Version 11.50, SC23-9428.<br />

► Java<br />

To write Java routines, you must use <strong>IBM</strong> <strong>Informix</strong> database server with<br />

J/Foundation and with the Java Development Kit (JDK) to compile your Java<br />

routines. You can find additional information about how to write Java UDRs in<br />

J/Foundation <strong>Developer's</strong> Guide, Version 10.0, G251-2291.<br />

Table 10-1 lists the UDR types that are supported by SPL, C, and Java in <strong>IBM</strong><br />

<strong>Informix</strong> database server.<br />

Table 10-1 Supported UDR tasks by languages<br />

UDR task SPL routines C routines Java routines<br />

Cast function Yes Yes Yes<br />

Cost function No Yes No<br />

End-user routine Yes Yes Yes<br />

Iterator function No Yes Yes<br />

Negator function Yes Yes Yes<br />

Opaque data type support No Yes Yes<br />

Parallelizable UDR No Yes Yes<br />

Statistics function No Yes Yes<br />

Selectivity function No Yes No<br />

User-defined aggregate Yes Yes Some<br />

Operator function Yes Yes Yes<br />

Operator-Class function Yes Yes Yes<br />

332 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


The following terms are used in this table:<br />

► Cast: A routine to convert from one data type to another. Built-in data types<br />

have automatic casts between most data types. For UDTs, casting must be<br />

defined from scratch.<br />

► Cost function: A routine that informs the optimizer of cost factors for execution<br />

of a particular UDR.<br />

► End-user function: A routine that is used to encapsulate multiple SQL<br />

statements into one function.<br />

► Iterator function: A routine that is designed to return to its calling SQL<br />

statement several times, returning a value each time.<br />

► Negator function: A routine used for a NOT condition that involves a Boolean<br />

UDR.<br />

► Opaque data type support: When you create a new data type, you must<br />

provide several basic support functions for your UDT. The following functions<br />

are required:<br />

– Text input and output routines<br />

– Binary send and receive routines<br />

– Text import and export routines<br />

– Binary import and export routines<br />

► Parallel UDR: A routine that can run in parallel within parallel queries.<br />

► Statistics function: A routine to create distribution statistics for a UDT.<br />

► Selectivity function: A routine to determine the percentage of rows for which a<br />

Boolean UDR is expected to return true.<br />

► User-defined aggregate: A SQL invoked routine that takes values selected<br />

and returns information about those rows (a summarizing method).<br />

► Operator function: A routine that is used within expressions with a symbol,<br />

such as “+,-,,=”. Built-in data type operators cannot be extended. All UDTs<br />

require some operators to function within an SQL context.<br />

► Operator-Class function: A set of operators that the server associates with<br />

how to build an access method (that is, an index), how to arrange values in<br />

the access method, how to select values based on operator function, and<br />

ways to allow the query optimizer to consider using the access method to<br />

return results for a query.<br />

For more details about any of these functions and for details about functionality<br />

that we do not discuss here, see <strong>IBM</strong> <strong>Informix</strong> User-Defined Routines and Data<br />

Types <strong>Developer's</strong> Guide, Version 11.50, SC23-9438.<br />

Chapter 10. User-defined routines 333


Invoking a UDR<br />

You can invoke a UDR implicitly or explicitly. Implicit invocation is the result of an<br />

operator function, an implicit cast, or some type of query processing. For this<br />

book, we mainly discuss explicit invocation. You can use either EXECUTE<br />

PROCEDURE or EXECUTE FUNCTION statements to run a UDR.<br />

When the database server executes an SQL statement that contains a UDR, it<br />

loads the UDR executable code as a shared-object into memory. It determines<br />

which shared-object file to load from the externalname column of the row in the<br />

sysprocedures system catalog table that describes the UDR. The sysprocedures<br />

entry is created when you register the UDR, as a result of the CREATE<br />

FUNCTION or CREATE PROCEDURE statement.<br />

In more general terms, when you invoke a UDR, the database server parses the<br />

statement into syntactic parts, call the system catalog to resolve the routine<br />

parts, generate a query plan, and then execute the query. If the query involves<br />

more than one database, each database requires that all the UDRs and UDTs<br />

must be registered in the participating databases.<br />

10.1.3 Considerations for extending data types<br />

A significant aspect of UDR is the support for an extended data type. <strong>IBM</strong><br />

<strong>Informix</strong> database servers have several built-in data types. Why do we need<br />

more?<br />

An extended data type is a new data type that has different core properties, new<br />

functionality, and new operator methods that go beyond a basic data type.<br />

As an example, consider a datetime data type. Imagine, as a programmer if you<br />

had to add “a day and a half” to a specific datetime event. Intuitively, we<br />

recognize that the value “‘day and a half” is an interval of time, but the database<br />

serve does not recognize this construct as an interval. We need to convert it<br />

manually to a usable interval, and then add it to a datetime value.<br />

With a UDR, an unconventional interval name such as this can be passed<br />

through a function, which translates it to an “normal” interval automatically,<br />

applies the addition operation, and returns a datetime value with the result. To do<br />

this, we apply a functional behavior change, which extends the data type. The<br />

result of processes such as this can simplify a repeating data task and make the<br />

development task easier.<br />

334 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


A quick review of the data type hierarchy is useful. Figure 10-1 shows a summary<br />

of these data types.<br />

Figure 10-1 Hierarchy of data types in <strong>Informix</strong> servers<br />

The extended data types can be either UDR types or complex data types. We are<br />

especially interested in UDTs, which can be described as follows:<br />

► Distinct: Internally, this data type is stored the same as a source data type,<br />

but it is overlaid with different casts and functions defined beyond the basic<br />

source type. The server sees distinct types as different from the source type.<br />

It is necessary to tell the server:<br />

– Source data type information and how the internal structure is defined.<br />

– The functions of how this data type interacts with its internal structure.<br />

– The operations that are valid with this distinct data type.<br />

– Any secondary access methods on how to handle this type.<br />

– Cast functions to move data in and out of the distinct type are automatic.<br />

► Opaque: A fundamental, user-defined data type. It cannot be broken into<br />

smaller pieces, although it can serve as the building block for other data<br />

types. The internal structure of the opaque data type is invisible to the server.<br />

When you define and use an opaque type, the developer must provide all of<br />

the following:<br />

– How the internal structure is defined.<br />

– The functions that enable routines to interact with its internal structure.<br />

– The operations that are valid with this distinct data type.<br />

– Any secondary access methods on how to handle this type.<br />

– Cast functions to move data in and out of the distinct type need to be<br />

provided.<br />

Chapter 10. User-defined routines 335


10.2 Developing UDRs<br />

To develop a UDR, plan it first and then write the routine. We follow the<br />

recommendations given in the UDR and Data Types Developers Guide for<br />

planning our routines:<br />

► Use a sensible name.<br />

► Avoid modal arguments (an argument in the function determines how the<br />

function will work).<br />

► Always declare routine parameter data types.<br />

► Declare the type that is returned when the routine is returning a value<br />

The source for an external routine resides in a separate text file. To prepare UDR<br />

source code:<br />

► You will compile the C-language UDR and store the executable version in a<br />

shared-object (.so or .o on UNIX) file.<br />

► Compile the Java-language UDR and store the executable version in a .jar<br />

file.<br />

You must install shared object files and .jar files on all database servers that<br />

need to run the UDRs, including database servers involved in Enterprise<br />

Replication (ER) and High-Availability Data Replication (HDR). The shared object<br />

files and .jar files need to be installed under the same absolute path name.<br />

Tip: Although not required, use the DataBlade Developer’s Kit (DBDK) to help<br />

write UDRs is advantageous. DBDK books and software can help enforce<br />

standards that facilitate migration between different versions of the database<br />

server. Because external-language routines are external to the database, be<br />

aware that you must compile the UDR source code and store it where the<br />

database server can access it when the routine is invoked.<br />

For information about C UDRs, refer to <strong>IBM</strong> <strong>Informix</strong> DataBlade API<br />

Programmer’s Guide, Version 11.50, SC23-9429 and <strong>IBM</strong> <strong>Informix</strong> DataBlade<br />

API Function Reference, Version 11.50, SC23-9428. For information about Java<br />

UDRs, refer to the J/Foundation <strong>Developer's</strong> Guide, Version 10.0, G251-2291.<br />

10.2.1 UDR examples in SQL<br />

You can use <strong>Informix</strong> Stored Procedure Language (SPL) statements to write<br />

routines and then store these SPL routines in the database. SPL extends SQL<br />

and helps to reduce SQL coding by minimizing the visible code in large SQL<br />

336 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


operations. It has the advantage that it is run as a server-side routine, the<br />

executable code stays inside the engine, and it is optimized only as needed. The<br />

end result is lower application startup costs and better performance. As an SQL<br />

extension, SPL can do flow control, such as looping and branching. SPL routines<br />

can also execute routines written in C or other external languages, and other<br />

UDR routines can execute SPL routines.<br />

In this section, we provide examples of UDRs written in SQL. As we do so,<br />

consider the following rules for SQL UDRs:<br />

► If you use any parameters, they must be declared as built-in or user-defined<br />

data types.<br />

► An SPL routine does not have access to the user state of its execution<br />

sequence. If the routine is going to be called more than once and if you want<br />

to retain information about previous executions in the transaction, use an SPL<br />

routine that states WITH RESUME as a part of the RETURN statement for<br />

multiple executions of the same SPL routine within the same routine<br />

sequence.<br />

► When an SPL routine is executed, the parameters (also known as the<br />

dependency list) is checked. If it is determined that an item in the dependency<br />

list needs reoptimization, optimization occurs at this point. If an item needed<br />

in the execution of the SQL statement is missing (for example, a column or<br />

table is dropped), an error is returned.<br />

► UDRs can be overloaded, meaning that a function can have more than one<br />

way to operate, depending on the list of data types that are provided as<br />

parameters. There is a precedence hierarchy to decide how the parameter list<br />

is executed. A precedence hierarchy to decide the execution sequence of the<br />

parameters can be important if you have more than one UDR with the same<br />

name but a different parameter list. For more information, see <strong>IBM</strong> <strong>Informix</strong><br />

User-Defined Routines and Data Types <strong>Developer's</strong> Guide, Version 11.50,<br />

SC23-9438.<br />

Using a stored procedure method for a UDR is simple, as long as you can<br />

recognize the incoming and outgoing parameters properly. The incoming<br />

parameters, which are provided in the function definition, must have data types<br />

defined when the parameter is first created and declared. The parameter values,<br />

which are to be returned from the function, also should have declared data types.<br />

By following this general rule, you can avoid many of the initial problems you can<br />

get with SPL UDRs.<br />

For the routines with SPL, we use the <strong>Informix</strong> stores sample database, defined<br />

as stores@demo_on.<br />

Chapter 10. User-defined routines 337


One variable in, one result out<br />

For this example, we want a function that provides a count of all the orders that<br />

are received in a numerical month (N) from the orders table of the stores<br />

database. This example demonstrates what happens when selecting an<br />

aggregating value, once.<br />

Example 10-1 shows the function code and ways to invoke the function to get<br />

output.<br />

Example 10-1 CREATE FUNCTION new_orders (month_num INT)<br />

CREATE FUNCTION new_orders ( month_num INT )<br />

RETURNING INT ;<br />

DEFINE nrows INT;<br />

SELECT COUNT(order_date) INTO nrows FROM orders<br />

WHERE month(order_date)=month_num;<br />

RETURN nrows;<br />

END FUNCTION;<br />

# -- Execute it as a function:<br />

EXECUTE FUNCTION new_orders(5);<br />

(expression)<br />

7<br />

# -- Execute it as a select statement.<br />

# -- Note that we have to force “first 1” as a criteria so we can assure we are<br />

# -- only getting one value. Otherwise we would get an error.<br />

SELECT FIRST 1 new_orders(5) FROM orders;<br />

(expression)<br />

7<br />

One variable in, several results out<br />

Example 10-2 performs three SELECT statements, and each statement does an<br />

aggregation, returning one value from each select. It returns three values and<br />

labels each value in the returned result. This example shows how to aggregate<br />

three separately selected value returns in one call and still not use a cursor.<br />

Example 10-2 Selecting three and returning three<br />

CREATE FUNCTION new_orders ( month_num INT )<br />

RETURNING INT as TotalOrders,INT as ShippedOrders,INT as Backorders;<br />

DEFINE nrows INT;<br />

DEFINE mrows INT;<br />

DEFINE b_rows INT;<br />

338 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


SELECT COUNT(ship_date) INTO mrows FROM orders<br />

WHERE month(ship_date)=month_num;<br />

SELECT COUNT(order_date) INTO nrows FROM orders<br />

WHERE MONTH(order_date)=month_num;<br />

SELECT COUNT(order_date) INTO b_rows FROM orders<br />

WHERE MONTH(order_date)=month_num AND ship_date IS NULL;<br />

RETURN nrows,mrows,b_rows;<br />

END FUNCTION;<br />

# -- Since we are returning three values with labels, calling the execute<br />

# -- function is the most appropriate way to make our SQL call.<br />

EXECUTE FUNCTION new_orders(5);<br />

totalorders shippedorders backorders<br />

7 3 1<br />

Using the WITH RESUME clause to return a cursor result<br />

Example 10-3 collects better details for the new orders. To return a detailed<br />

listing of orders made, it uses the WITH RESUME clause in the function. In this<br />

case, we assume (and expect) more than one row is returned. So, the WITH<br />

RESUME clause is needed.<br />

Example 10-3 A WITH RESUME ROUTINE that uses a cursor<br />

CREATE FUNCTION new_orders ( month_num INT )<br />

RETURNING INT as Num, INT as ord_num;<br />

DEFINE ord_num INT;<br />

DEFINE Num INT;<br />

LET Num=1;<br />

FOREACH cursor1 FOR<br />

SELECT order_num INTO ord_num FROM orders<br />

WHERE month(order_date)=month_num<br />

RETURN Num, ord_num WITH RESUME;<br />

LET Num=Num+1;<br />

END FOREACH;<br />

END FUNCTION;<br />

EXECUTE FUNCTION new_orders(5);<br />

------num ord_num-----<br />

1 1001<br />

2 1002<br />

3 1003<br />

4 1004<br />

Chapter 10. User-defined routines 339


10.2.2 UDRs in Java<br />

5 1005<br />

6 1006<br />

7 1007<br />

Multi-table select using a cursor<br />

Example 10-4 performs a multi-table join with a summary expression return and<br />

a group by. We ask for all the orders placed in a specific month, the name of the<br />

person placing the order, and the total amount for each order.<br />

Example 10-4 A multi-table select using a cursor<br />

CREATE FUNCTION new_orders ( month_num INT )<br />

RETURNING INT as Ord_Num, char(15) as ord_fname,<br />

char(15) as ord_lname, money(8,2) as Amt;<br />

DEFINE ord_num INT;<br />

DEFINE ord_fname char(15);<br />

DEFINE ord_lname char(15);<br />

DEFINE Amt money(8,2);<br />

FOREACH cursor1 FOR<br />

SELECT o.order_num, c.fname,c.lname,sum(i.quantity*i.total_price)<br />

INTO ord_num, ord_fname, ord_lname, Amt<br />

FROM orders o, customer c, items i<br />

WHERE month(order_date)=month_num<br />

AND o.customer_num=c.customer_num<br />

AND i.order_num=o.order_num<br />

group by o.order_num,c.fname,c.lname<br />

RETURN ord_num, ord_fname, ord_lname, Amt WITH RESUME;<br />

END FOREACH;<br />

END FUNCTION;<br />

You must distinguish between JDBC and Java Virtual Machine (JVM)<br />

applications. You can use JDBC to write stand-alone applications. If you want to<br />

connect with to databases that support Java, you typically write stand-alone<br />

JDBC applications, because these applications require specific driver methods to<br />

communicate with other database servers. When you write a Java UDR, you<br />

must use the <strong>IBM</strong> <strong>Informix</strong> JDBC Driver, which is based on the JDBC 2.0 API.<br />

The generated code is processed by a JVM that runs as a process inside <strong>IBM</strong><br />

<strong>Informix</strong> Server. The generated code (.jar file) is stored in an sbspace and can<br />

also refer to a .jar file in a storage location outside of the server.<br />

Java allows you to create UDRs, cast support functions, aggregates, and opaque<br />

data type support routines. However, Java routines cannot handle row or<br />

collection data types.<br />

340 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


For ordinary UDR with <strong>IBM</strong> <strong>Informix</strong> database servers, you can use the Java<br />

Developers Kit (version 1.5 at this writing). A JVM comes pre-installed with the<br />

<strong>IBM</strong> <strong>Informix</strong> database server (with J/Foundation). To confirm it is present, make<br />

sure that you have an existing directory path to the<br />

INFORMIXDIR/extend/kraratoa directory.<br />

Java-based UDR, when developed, is placed into a Java archive (.jar) file. The<br />

.jar file is stored inside an sbspace, or it can have additional supporting files on<br />

the file system. If the .jar file is large or perhaps proprietary, you can leave it on<br />

the file system. Store smaller .jar files or files that you might want to update<br />

frequently in the sbspace.<br />

Configuration<br />

Make sure that you use the JVM system that came with your server engine, and<br />

make sure the onconfig file and environment variables are set to accurate<br />

working paths. The environment settings for our testing setup had the following<br />

variables in the environment:<br />

JRE_HOME=/usr/lib/jvm/java/jre<br />

JAVA_BINDIR=/usr/lib/jvm/java/bin<br />

JAVA_HOME=/usr/lib/jvm/java<br />

SDK_HOME=/usr/lib/jvm/java<br />

JJDK_HOME=/usr/lib/jvm/java<br />

JAVA_ROOT=/usr/lib/jvm/java<br />

The JAVA_ROOT environment variable is mostly determined by the developer. It is<br />

the path to the file system directory where you are developing your .jar files:<br />

CLASSPATH=location_for_your_java_classes:.:.:.<br />

The INFORMIXDIR/etc/ONCONFIG file also has a small group of parameters that<br />

must have verified settings. The following parameters are standard:<br />

JVPJAVAHOME $INFORMIXDIR/extend/krakatoa/jre<br />

JVPHOME $INFORMIXDIR/extend/krakatoa<br />

JVPPROPFILE $INFORMIXDIR/extend/krakatoa/.jvpprops<br />

JVPJAVALIB /bin<br />

JVPJAVAVM jvm<br />

The JVPJAVALIB and JVPJAVAVM parameters in the onconfig file are important for<br />

development. The following parameter specifies the name of the log file to which<br />

Java problems are written (make sure the path exists):<br />

JVPLOGFILE $INFORMIXDIR/jvp.log<br />

If you are going to use external .jar files, you must add them to JVPCLASSPATH:<br />

JVPCLASSPATH $INFORMIXDIR/extend/krakatoa/krakatoa.jar:$INFORMIXDIR/extend/krakatoa/jdbc.jar<br />

Chapter 10. User-defined routines 341


Note: The paths for .jar files that are added to JVPCLASSPATH are visible<br />

only after you add them to the onconfig file and restart the database engine.<br />

Routine examples in Java<br />

In the examples that follow, we create our Java routines in /work/, which defines<br />

the UNIX directory that we use for our working CLASSPATH. You must change<br />

the directory path in some of the code expressions if you use a different directory.<br />

After you compile the code, the source code is not used for execution, but keep it<br />

in a safe place in case you want to improve it later.<br />

A function extension<br />

This example illustrates a simple way to extend functionality. This routine<br />

provides an SQL function to “multiply a value times 10.” The developing<br />

procedure is as follows:<br />

1. Create a simple class file named Times.java in the working JVPCLASSPATH<br />

directory. Example 10-5 shows the source code.<br />

Example 10-5 A Java function to multiply a value times 10<br />

/*Times.java */<br />

public class Times {<br />

public static int TimesTen(int x) {<br />

return x * 10;<br />

}<br />

}<br />

2. At a command prompt, compile the file using the following command:<br />

javac Times.java<br />

3. Compress it into a .jar file:<br />

jar cvf Times.jar Times.class<br />

As this runs, it shows output similar to the following:<br />

added manifest<br />

adding: Times.class(in = 245) (out= 187)(deflated 23%)<br />

4. Register the routine:<br />

Start dbaccess to connect to the database and run the following SQL to<br />

register and add the .jar file into our sbspace:<br />

execute procedure sqlj.install_jar ("file://work/Times.jar" , "Times_jar");<br />

Routine executed.<br />

342 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


5. With the .jar file in storage and accessible, from dbaccess, we create a<br />

function that calls our routine in the .jar file. See Example 10-6.<br />

Example 10-6 Calling routine<br />

create function times_ten(value int) returning int<br />

with (class = "jvp")<br />

external name "Times_jar:Times.TimesTen"<br />

language JAVA;<br />

6. The procedure is ready to run. Test it in dbaccess:<br />

EXECUTE function times_ten(13)<br />

(expression)<br />

130<br />

For an alternate method, try:<br />

SELECT ship_charge, times_ten(ship_charge) X10 FROM orders;<br />

A Java UDR with two input parameters<br />

This example demonstrates how to create a Java routine with multiple input<br />

parameters. Java language and <strong>IBM</strong> <strong>Informix</strong> servers express decimals in<br />

different ways. This example creates a new sales tax function, Salestax, that<br />

includes a new Java function and the existing Times_ten function created in “A<br />

function extension” on page 342.<br />

We need to include an external standard Java library that has a math class. You<br />

might find that multiplying decimal values in Java is different than what you might<br />

be used to. In addition, Java uses a different naming convention than <strong>Informix</strong><br />

data types. If you get the class wrong or the library is incorrect, things simply do<br />

not work, and you will get errors.<br />

Chapter 10. User-defined routines 343


We use the following procedure to create the salestax function:<br />

1. Create a Java class called Tax.java, using an editor such as vi.<br />

Example 10-7 shows the source code.<br />

Example 10-7 The Tax.java class<br />

/*Tax.java*/<br />

import java.math.BigDecimal;<br />

public class Tax {<br />

public static BigDecimal salestax(BigDecimal x,BigDecimal xtax )<br />

{<br />

BigDecimal ratePlusOne = xtax.add(BigDecimal.valueOf(1));<br />

BigDecimal afterTax = x.multiply(ratePlusOne);<br />

afterTax = afterTax.setScale(2, BigDecimal.ROUND_HALF_UP);<br />

return (afterTax);<br />

}<br />

}<br />

2. Compile the file. At a command prompt, run the following command:<br />

javac Tax.java<br />

3. Compress the file, and add it to the existing .jar file (named Times.jar).<br />

jar cvf Times.jar Tax.class<br />

As this runs, it shows a line similar to the following:<br />

added manifest<br />

adding: Tax.class(in = 546) (out= 318)(deflated 41%)<br />

4. Add the updated .jar file to sbspace.<br />

For this example, we want to update an existing function that already exists in<br />

the sbspace .jar file. Because we cannot replace an existing function in a<br />

sbspace .jar file directly, update an sbspace .jar function, we must replace<br />

the entire .jar file. To do this, we must remove (drop) the sbspace .jar file,<br />

then replace it with an updated version from our working path.<br />

A .jar file in an sbspace must be empty to drop the .jar file. Drop all the<br />

UDRs in the .jar file to empty it. Otherwise, you receive the following error<br />

message:<br />

“Invalid jar removal. All dependent UDRs not dropped”.<br />

Our Times_jar file exists in the database. To drop the function, we start<br />

dbaccess, connect to the database, then run the following command:<br />

DROP FUNCTION times_ten;<br />

Now, we can remove the .jar file:<br />

EXECUTE PROCEDURE sqlj.remove_jar ("Times_jar");<br />

344 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


5. Add the updated .jar file into sbspace. Run the following SQL:<br />

EXECUTE PROCEDURE sqlj.install_jar ("file://work/Times.jar" , "Times_jar");<br />

6. The updated .jar file is now in sbspace storage. Re-create the dropped<br />

Times_ten function:<br />

create function times_ten(value int) returning int<br />

with (class = "jvp")<br />

external name "Times_jar:Times.TimesTen"<br />

language JAVA;<br />

7. Add the new function to call on the same .jar file:<br />

create function salestax(value decimal,xtax decimal)<br />

returning decimal(8,2)<br />

with (class = "jvp")<br />

external name "Times_jar:Tax.salestax"<br />

language JAVA;<br />

8. Now, can test the expanded function from dbaccess:<br />

EXECUTE FUNCTION salestax(250.00,.065);<br />

(expression)<br />

266.25<br />

As an alternative test using SQL, try:<br />

SELECT o.order_num,<br />

salestax (sum(i.quantity*i.total_price), .065) Amt_w_Tax<br />

FROM orders o, items i WHERE month(order_date)=5<br />

AND i.order_num=o.order_num group by o.order_num<br />

Creating a routine that uses external Java APIs<br />

This example demonstrates how to create a Java UDR that requires support from<br />

one or more Java APIs that lie outside the database server. The import<br />

references in the code indicate that an external Java API exists to help support<br />

the UDR. The references on the import list remain outside the database server.<br />

The JVM runs using the .jar file calls in the sbspace storage location and sends<br />

calls to the external Java functions based on the import reference in the .jar file.<br />

Note that the import reference does not have a full directory path. Any Java API<br />

or .jar file that is not residing in an sbspace is external to the instance. To help<br />

the server instance find external .jar files, you must supply all JAR API path<br />

locations in the onconfig file.<br />

Note: The onconfig file must be updated so the JVM knows the directory path<br />

for any supporting APIs. The full path location for the supporting Java file<br />

specified on an import list must be included in JVPCLASSPATH.<br />

Chapter 10. User-defined routines 345


For our example, JVPCLASSPATH is set to:<br />

/usr3/11.50/extend/krakatoa/krakatoa_g.jar:/usr3/11.50/extend/krakatoa/jdbc_g.j<br />

ar:/usr3/11.50/extend/krakatoa/jre/lib/rt.jar:/work/mailapi.jar:/work/activatio<br />

n.jar:/work/smtp.jar<br />

For our example to work, the engine needs the Java mail API classes. The files<br />

that are required are mailapi.jar, activation.jar, and smtp.jar, which are<br />

available at:<br />

http://java.sun.com/products/javamail/downloads/index.html<br />

To create the sendmail routine:<br />

1. Install the downloaded .jar files, and add .jar files with full path to<br />

JVPCLASSPATH.<br />

In this example, the paths are /work/mailapi.jar, /work/activation.jar,<br />

and /work/smtp.jar.<br />

2. Create the file MailClient.java as shown in Example 10-8. You have to<br />

update the italicized references in the example with your own information.<br />

Example 10-8 An SQL based sendmail() UDR<br />

---- MailClient.java --import<br />

javax.mail.*;<br />

import javax.mail.internet.*;<br />

import java.io.*;<br />

import java.util.Properties;<br />

public class MailClient<br />

{<br />

public static void send(String to, String text)<br />

{<br />

try<br />

{<br />

MailClient client = new MailClient();<br />

346 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong><br />

Properties props = System.getProperties();<br />

props.put("mail.smtp.host", "smtp.server.com");<br />

Session session = Session.getDefaultInstance(props, null);<br />

Message message = new MimeMessage(session);<br />

message.setFrom(new InternetAddress("Name_showing@fromfield"));<br />

message.addRecipient(Message.RecipientType.TO, new InternetAddress(to));<br />

message.setSubject("Message from the database");<br />

message.setText(text);<br />

Transport.send(message);<br />

}<br />

catch(Exception e)<br />

{<br />

e.printStackTrace(System.out);


}<br />

}<br />

}<br />

---- MailClient.java ---<br />

3. Compile and compress your file:<br />

javac MailClient.java<br />

jar cvf MailClient.jar MailClient.class<br />

4. Install the .jar file into the sbspace:<br />

EXECUTE PROCEDURE sqlj.install_jar ("file://work/MailClient.jar" ,<br />

"MailClient_jar");<br />

Make sure JVPCLASSPATH is set as indicated in step 1.<br />

5. Create the sendmail procedure from dbaccess:<br />

CREATE PROCEDURE sendemail(to LVARCHAR, message LVARCHAR)<br />

WITH (class = "jvp")<br />

EXTERNAL NAME "MailClient_jar:MailClient.send"<br />

LANGUAGE JAVA;<br />

6. Test the procedure:<br />

EXECUTE PROCEDURE sendemail('dba@mybiz.com','Error deleting from table');<br />

Troubleshooting tips<br />

Sometimes you might have trouble getting a Java UDR to run. The following<br />

points of exposure for errors are possible:<br />

► At the time of a Java compile<br />

If you get an error here, the issue relates to a Java language problem, most<br />

likely resulting from syntax or a Java method. Consult a Java Programming<br />

Language Guide for assistance.<br />

► At the .jar installation point or later<br />

Check the jvp.log at the path in the onconfig file specified by the JVPLOG<br />

parameter. You should see no errors at the time of install, and no errors at run<br />

time. When you start the server instance the JVM starts, .jar files load into<br />

the process memory as needed. The MSGPATH file (online.log) often<br />

reveals the success or failure of JVM and .jar file loading. If the files cannot<br />

load, they cannot run.<br />

► UDR runtime errors<br />

If there are errors, study the Java error messages returned, and determine<br />

the cause for whatever did not resolve.<br />

Troubleshooting can be a trial and error approach. When you have an<br />

understanding of how the provided UDR examples work, do them over again,<br />

Chapter 10. User-defined routines 347


10.2.3 UDRs in C<br />

and break something in the Java code. Go through the example with slightly<br />

broken syntax and review the results. For example, in the BigDecimal code<br />

example, change BigDecimal to Float or Double, and work through the example<br />

again.<br />

The C programming language allows you to create UDRs, cast support functions,<br />

aggregates, and opaque data type support routines. C can also handle row and<br />

collection data types. Working with C UDR adds an extra layer of difficulty<br />

because these routines have to be compiled using a compiler, specific to the<br />

system and operating system where you have products installed. Compiled C is<br />

not stored in sbspace, but rather it is stored outside the server.<br />

In addition to compiler difficulties, it is a good idea to develop and test UDRs on a<br />

development server and not in a production environment. C UDR code runs as a<br />

database server process that works closely with internal structures. The routine<br />

should not do anything that would negatively affect the database server. A poorly<br />

designed C UDR is likely to crash the server. If you plan to work with C UDRs,<br />

the following resources are good reference books:<br />

► <strong>IBM</strong> <strong>Informix</strong> User-Defined Routines and Data Types <strong>Developer's</strong> Guide,<br />

Version 11.50, SC23-9438<br />

► <strong>IBM</strong> <strong>Informix</strong> DataBlade API Programmer’s Guide, Version 11.50, SC23-9429<br />

► <strong>IBM</strong> <strong>Informix</strong> DataBlade API Function Reference, Version 11.50, SC23-9428<br />

If you are interested in using C++ Datablade modules, the <strong>IBM</strong> <strong>Informix</strong><br />

Developer Zone that provides the latest recommendations on C++ programming<br />

options at:<br />

http://www.ibm.com/software/data/developer/informix<br />

Routine examples in C<br />

In this section, we undertake a few examples written in C. With Java, we have<br />

portability that extends across platforms, but some of our functionality is limited.<br />

C is flexible because it can extend the database by way of data types, new<br />

functions, and new operators. For each database across an enterprise, the<br />

extensibility that you provide through C must be specifically compiled with each<br />

operating system. For the examples in this section, we use a Solaris system.<br />

A simple function using C<br />

For our first example, we start with a function similar to what we did in our Java<br />

example, a multiplying function. For each of our C examples, we must include the<br />

DataBlade API files (referenced in the example as mi.h and milib.h). The<br />

348 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


DataBlade APIs provide the interface to allow C language calls to interface with<br />

<strong>IBM</strong> <strong>Informix</strong> database SQL calls. To prevent a conflict with our times_ten Java<br />

UDR function, we name this example times_five.<br />

To create this routine:<br />

1. Create the text file that holds the C code. Example 10-9 shows the source file<br />

times.c.<br />

Example 10-9 A C UDR that multiplies times five<br />

#include <br />

#include "mi.h"<br />

#include "milib.h"<br />

mi_integer* TimesFive(mi_integer value);<br />

mi_integer* TimesFive(mi_integer value)<br />

{<br />

return (mi_integer *) (value * 5);<br />

}<br />

2. Compile and link the C code.<br />

The compile command (cc or gcc) depends on the operating system. The first<br />

way to identify your compiler is to examine the text of man cc (on UNIX), or<br />

check the command for your operating system compiler in the<br />

INFORMIXDIR/release/en_us/0333/ids_machine_notes_vers.txt file.<br />

At a minimum, your compile line for UDR preparation usually includes:<br />

-DMI_SERVBUILD -KPIC -I$INFORMIXDIR/incl/public -I/$INFORMIXDIR/incl<br />

Where<br />

– -DMI_SERVBUILD is the flag to indicate that this is a server-oriented C UDR<br />

application which uses the DataBlade API (required).<br />

– -KPIC is the flag to indicate that the symbol table is dynamic (for UNIX and<br />

Linux only).<br />

– -I$INFORMIXDIR/incl/public and -I/$INFORMIXDIR/incl are the location<br />

of the mi_ libs.<br />

The compile command for our code sample (on Solaris) is:<br />

cc -DMI_SERVBUILD -KPIC -I$INFORMIXDIR/incl/public -I/$INFORMIXDIR/incl -o<br />

times.o -c times.c<br />

Run the link command to put the compiled object file into our Blade library file:<br />

ld -dy -G -Bsymbolic -o times.bld times.o<br />

Chapter 10. User-defined routines 349


3. Set the bld file permissions as user informix:<br />

chmod 555 ./times.bld<br />

4. In dbaccess, after connecting to the database, create the times_five<br />

function:<br />

CREATE FUNCTION times_five(value int) RETURNING int<br />

WITH (handlesnulls)<br />

EXTERNAL NAME "/work/times.bld(TimesFive)"<br />

LANGUAGE C;<br />

Adjust the external work path as needed.<br />

5. Test the routine:<br />

execute function times_five(20);<br />

(expression)<br />

100<br />

In Java UDR, the .jar file serves as a library (collection-repository) for all of the<br />

compiled routines. In C, a collection of compiled routines is stored in a shared<br />

library (.so or .o) file. On Windows, a shared object file has a .dll extension<br />

(dynamic link library).<br />

Creating a C routine using large object column<br />

The next example explores the use of working with a large object column<br />

reference. Without a text search DataBlade, searching a character large object<br />

(CLOB) file for a particular value can be a laborious SQL task. This example<br />

shows how to access a CLOB file, copy the CLOB contents into an LVARCHAR,<br />

and search for a specific text item, while using a simple function. We create a C<br />

file that handles two parameters. The first parameter is a CLOB column<br />

reference, the second parameter is the LVARCHAR text value for our search. It<br />

returns a count for the number of successful finds.<br />

To implement this search routine:<br />

1. Create the CLOB column search routine source file un.c as shown in<br />

Example 10-10.<br />

Example 10-10 A UDR for searching a CLOB<br />

#include <br />

#include <br />

#include <br />

#include <br />

#include <br />

#include <br />

typedef unsigned char byte;<br />

mi_integer contains(MI_LO_HANDLE* loptr, mi_lvarchar* pattern, MI_FPARAM* fp);<br />

350 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


mi_integer contains(MI_LO_HANDLE* loptr, mi_lvarchar* value, MI_FPARAM* fp)<br />

{<br />

mi_unsigned_integer crc = (mi_fp_argisnull(fp, 1) == MI_TRUE) ? 0 :<br />

(mi_unsigned_integer)1;<br />

MI_CONNECTION *conn;<br />

MI_LO_SPEC *lo_spec = NULL;<br />

MI_LO_FD lo_fd;<br />

MI_LO_STAT *lo_stat = NULL;<br />

char *buff = NULL;<br />

char *pattern = NULL;<br />

mi_integer buffsize = 4096;<br />

mi_integer found=0;<br />

mi_integer result=0;<br />

pattern = mi_lvarchar_to_string(value);<br />

if ((conn = mi_open(NULL, NULL, NULL)) == NULL) return (mi_integer) -1;<br />

if ((buff = (char*)mi_alloc(buffsize)) == NULL) return (mi_integer) -2;<br />

if ((lo_fd = mi_lo_open(conn, loptr, MI_LO_RDONLY)) == MI_ERROR)<br />

return (mi_integer) -3;<br />

do {<br />

if ((result = mi_lo_read(conn, lo_fd, buff, buffsize)) == MI_ERROR)<br />

break;<br />

if (result == 0)<br />

break;<br />

if (strstr(buff,pattern)!=NULL)<br />

{<br />

found=1;<br />

break;<br />

}<br />

if (result < buffsize)<br />

break;<br />

} while(1);<br />

mi_lo_close(conn,lo_fd);<br />

if (buff)<br />

mi_free(buff);<br />

return (mi_integer)found;<br />

}<br />

2. Compile and link the C routine. We use the following Solaris compile line:<br />

cc -DMI_SERVBUILD -KPIC -I$INFORMIXDIR/incl/public<br />

-I$INFORMIXDIR/incl/public -I$INFORMIXDIR/incl/esql -I/$INFORMIXDIR/incl -o<br />

un.o -c un.c<br />

Here is the link line:<br />

ld -dy -G -Bsymbolic -o un.bld un.o<br />

3. Set the bld file permissions as user informix:<br />

chmod 555 ./un.bld<br />

Chapter 10. User-defined routines 351


4. Create the function in dbaccess.<br />

create function contains(clob,lvarchar)<br />

returns integer<br />

external name '/work/un.bld(contains)'<br />

language C;<br />

5. Set up for testing. Create a table and populate it with our c file.<br />

CREATE TABLE tclob (c1 INT, c2 CLOB);<br />

INSERT INTO tclob VALUES (1,filetoclob('un.c','server'));<br />

6. Test the routine:<br />

SELECT c2 FROM tclob;<br />

SELECT CONTAINS(c2,'pattern') FROM tclob;<br />

SELECT CONTAINS(c2,'nopattern') FROM tclob;<br />

SELECT c1 FROM tclob WHERE CONTAINS(c2,'buff')=1;<br />

Troubleshooting tips<br />

To track down the cause of problems with C UDRs, the most affective approach<br />

is to use a debugger. To debug your UDR, use a debugger that can attach to the<br />

active server process and access the symbol tables of the dynamically loaded<br />

shared object files. On UNIX and Linux, the debugger and dbx utilities meet these<br />

criteria. To start a debugger, enter the following command at the shell prompt, in<br />

which pid is the process identifier of the CPU or virtual processor:<br />

debugger -pid<br />

This command starts the debugger on the server virtual-processor process<br />

without starting a new instance of the virtual processor. For more information<br />

about available debugger commands, see the debugger manual page, and learn<br />

more in the information center:<br />

http://publib.boulder.ibm.com/infocenter/idshelp/v115/index.jsp?topic=/com.ibm.<br />

dapip.doc/sii111026637.htm<br />

10.3 DataBlades and bladelets<br />

Your initial collection of UDRs increases over time. It might not be long until you<br />

have UDRs, special functions, and stored procedure UDRs that reduce work<br />

complexity and provide great functionality. If you choose not to write your own<br />

DataBlade, you can still choose from a nice selection of DataBlade modules. Any<br />

DataBlade module you use provides functions that might increase the usefulness<br />

of business data dramatically or that might perhaps generate income for you—as<br />

a software developer that develops and sells licensed DataBlades.<br />

352 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


10.3.1 Configuration<br />

<strong>IBM</strong> <strong>Informix</strong> has several books on the subject of planning, designing, and<br />

implementing DataBlades. With a taste of the programming examples presented<br />

earlier in this chapter, you might be ready to take the next step and program a<br />

DataBlade in C or Java. From a technical perspective, <strong>IBM</strong> <strong>Informix</strong> DataBlade<br />

Developers Kit User's Guide, Version 4.20, G229-6366 is specifically oriented to<br />

the development of DataBlade modules. It provides detailed help for<br />

programming DataBlade modules in Java and C.<br />

If you want to work with a DataBlade before you decide whether you have a need<br />

to write your own, the sections that follow provide an overview of the DataBlades<br />

that are available with <strong>IBM</strong> <strong>Informix</strong> Server.<br />

Configuration for a Datablade module requires the following steps:<br />

1. Prepare the database serve.<br />

2. Install the DataBlade.<br />

3. Register the DataBlade.<br />

Conceptually, the process is the same, regardless of the operating system and<br />

hardware. Small differences exist in interface or command lines, which we will<br />

point out.<br />

Prepare the database<br />

Database preparation involves setting up environment variables and making sure<br />

the database you are going to use with a DataBlade is set to a logged database<br />

in advance.<br />

The environment settings required are as follows:<br />

► On UNIX and Linux: LD_LIBRARY_PATH, INFORMIXSERVER, and<br />

ONCONFIG<br />

► On Windows: INFORMIXSERVER and ONCONFIG<br />

When you get to the step for BladeManager usage, you also require an<br />

environment setting for LD_LIBRARY_PATH.<br />

Although a logged database is not required for every DataBlades, a logged<br />

database can help avoid concurrency problems and thus is recommended. Also,<br />

while it is the case that not all DataBlade modules require a logged database,<br />

some of them do require logged sbspace. Keep this in mind as you install and<br />

configure the DataBlade that you select.<br />

Chapter 10. User-defined routines 353


Installing the DataBlade<br />

Any DataBlades that are installed with <strong>IBM</strong> <strong>Informix</strong> Servers are installed in<br />

separate subdirectories under the INFORMIXDIR/extend directory. Several<br />

subdirectories for DataBlades are established when the <strong>IBM</strong> <strong>Informix</strong> Server is<br />

installed. There might be some variation to the list, based on your exact version<br />

and operating system.<br />

Example 10-11 shows the subdirectory listing for 11.50.UC6 on Linux with<br />

J/Foundation.<br />

Example 10-11 A sample INFORMIXDIR/extend subdirectory<br />

opt/<strong>IBM</strong>/informix/extend:> ls<br />

binaryudt.1.0 ifxmngr LLD.1.20.UC2 spatial.8.21.UC3<br />

bts.2.00 ifxrltree.2.00 mqblade.2.0 web.4.13.UC4<br />

ifxbuiltins.1.1 krakatoa Node.2.0 wfs.1.00.UC1<br />

If you do not see the DataBlade directory reference for the one you want, you<br />

must acquire it by way of a download or CD.<br />

Installation on UNIX is simply a matter of uncompressing the new DataBlade<br />

module into a temporary directory. After the files are expanded, run the<br />

installation script, ./install. The ./install script creates a new module<br />

directory under the INFORMIXDIR/extend directory. Some file expansions can<br />

result in more than one new module. If there is more than one module, you must<br />

run the ./install script for each one.<br />

Installation on Windows systems requires that you go to the installation location<br />

and run setup.exe. Select the Typical installation option. The other dialog<br />

verification is the INFORMIXDIR location. With those items confirmed, the<br />

software is installed. When the installation is complete, the module directory is<br />

installed in the INFORMIXDIR\extend directory.<br />

Registering the DataBlade<br />

With a DataBlade directory in place, the active database server is not aware of<br />

the DataBlade directories until the software is registered in the database.<br />

Registration is the process of executing the SQL statements that create the<br />

DataBlade module database objects and identify the DataBlade module shared<br />

object file or dynamic link library to the database server.<br />

354 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


With the release of 11.50.XC4, <strong>IBM</strong> <strong>Informix</strong> provides the following distinct<br />

methods for DataBlade registration:<br />

► BladeManager<br />

Available with the first release of datablades, the BladeManager is an<br />

interface that automates the registration process by performing a series of<br />

SQL steps in the database engine.<br />

► sysbldprepare()<br />

This command is an <strong>Informix</strong> function for DataBlade registration. At its<br />

simplest, you can run the command inside dbaccess with your target<br />

database open to install a DataBlade. It has a few restrictions that are<br />

described in <strong>IBM</strong> <strong>Informix</strong> DataBlade Module Installation and Registration<br />

Guide, Version 4.20, G229-6368. To register the bts DataBlade with this<br />

interface, use the following command:<br />

EXECUTE FUNCTION sysbldprepare('bts.*','create');<br />

To register a DataBlade module using BladeManager:<br />

1. Start BladeManager:<br />

– On UNIX or at the MS-DOS prompt, the BladeManager is started with the<br />

blademgr command.<br />

– To start BladeManager on a Windows system, select Start � Programs �<br />

<strong>Informix</strong> program group name � BladeManager or double-click the<br />

BladeManager icon in the <strong>Informix</strong> program group.<br />

If the BladeManager fails to start, it is either not installed or you do not have<br />

the environment variables set, as noted in the previous section.<br />

2. Set confirmations.<br />

If you want an automatic confirmation after each step, turn the prompt on:<br />

set confirm on<br />

Commands run when you press the carriage return.<br />

3. Connect to an <strong>Informix</strong> instance:<br />

show servers<br />

set server demo_on < Use you own server name for demo_on><br />

If you want to connect as a different user, try:<br />

set user <br />

At the password prompt, enter your password. Validation does not occur until<br />

connection, on the next step.<br />

Chapter 10. User-defined routines 355


To connect to a database, run one of the following commands:<br />

list stores<br />

register module_name database_name<br />

unregister module_name database_name<br />

The module_name represents the name of the DataBlade module directory.<br />

These names typically follow the form of the DataBlade module name<br />

followed by the version number.<br />

When BladeManager registers a DataBlade module, it executes a series of SQL<br />

CREATE statements to register each database object in the module. You must<br />

have resource permissions on the database to register the DataBlade. In<br />

addition, if your server has implemented the ONCONFIG EXTEND role, you<br />

must be granted the EXTEND role by user informix.<br />

If the registration of a module fails, BladeManager returns the database to its<br />

prior state. To see the SQL statements that failed, look at the corresponding log<br />

file and check the procedure in Appendix A. Troubleshooting Registration<br />

Problems of <strong>IBM</strong> <strong>Informix</strong> DataBlade Module Installation and Registration Guide,<br />

Version 4.20, G229-6368, for possible solutions.<br />

Occasionally, DataBlade modules have more than one interface. If there are<br />

additional modules, there are also dependencies. You have to make sure that<br />

each of the interfaces are registered correctly in order for the DataBlade to work.<br />

BladeManager automatically checks for dependencies and registers any<br />

dependencies it might need. If the BladeManager cannot do the registration, it<br />

will prompt you to do so manually.<br />

Important: BladeManager does not verify the integrity of DataBlade modules<br />

that have additional interfaces, nor does it not check for the presence of<br />

required database objects.<br />

Datablade modules written in the Java language can only be registered in <strong>IBM</strong><br />

<strong>Informix</strong> Servers with J/Foundation database servers.<br />

356 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


10.3.2 <strong>IBM</strong> <strong>Informix</strong> provided DataBlades<br />

Table 10-2 the DataBlades that are available with <strong>IBM</strong> <strong>Informix</strong> database servers.<br />

Table 10-2 <strong>Informix</strong> provided DataBlades<br />

<strong>IBM</strong> <strong>Informix</strong><br />

DataBlade<br />

module name Description Special notes<br />

Large Object<br />

Locator<br />

A foundation Datablade module for large<br />

objects management that can be used by<br />

other modules that create or store<br />

large-object data.<br />

MQ DataBlade Allows <strong>IBM</strong> <strong>Informix</strong> database<br />

applications to communicate with other<br />

MQSeries® applications with MQ<br />

messaging.<br />

Binary DataBlade This module includes binary data types to<br />

store binary-encoded strings that can be<br />

indexed for quick retrieval.<br />

Basic Text Search Permits text search of words and phrases<br />

in an unstructured document repository<br />

stored in a column of a table.<br />

Node DataBlade This module is for the hierarchical data<br />

type, to represent hierarchical data within<br />

a relational database.<br />

Web Feature<br />

Service<br />

J/Foundation<br />

krakatoa<br />

This module is an add-on to allow Open<br />

Geospatial Consortium (OGC) web<br />

feature service as a presentation layer for<br />

the Spatial and Geodetic DataBlade<br />

modules<br />

A library of classes and interfaces that<br />

allow programmers to create and execute<br />

Java UDRs that access <strong>Informix</strong> database<br />

servers<br />

ifxbuilt-ins This is not really a DataBlade, but it sets<br />

up definitions and functions for the<br />

standard data types offered in the informix<br />

server.<br />

ifxmngr.2.00 This is the API that supports the<br />

BladeManager.<br />

Available on<br />

standard install<br />

(LLD.1.20.UC2)<br />

Available on<br />

standard install<br />

(mqblade.2.0)<br />

Available on<br />

standard install.<br />

(binaryudt.1.0)<br />

Available on<br />

standard install.<br />

(bts.2.00)<br />

Available on<br />

standard install.<br />

(Node.2.0)<br />

Available on<br />

standard install.<br />

(wfs.1.00.UC1)<br />

Available as a part<br />

of <strong>Informix</strong> Server<br />

with J/Foundation<br />

Available on<br />

standard install<br />

(ifxbuiltins.1.1)<br />

Available on<br />

standard UNIX<br />

install<br />

Chapter 10. User-defined routines 357


<strong>IBM</strong> <strong>Informix</strong><br />

DataBlade<br />

module name Description Special notes<br />

ifxrltree.2.00 This is a foundational, multidimensional,<br />

index called “Region tree” (R-tree) (also<br />

known as Range Tree). This blade is<br />

needed for both spatial and time related<br />

data management.<br />

Image Foundation This module is a foundation DataBlade<br />

which provides a base on which new or<br />

specialized image types and image<br />

processing technologies can be added or<br />

changed. Because the foundation is open,<br />

secure, and scalable, it provides a clear<br />

path toward reusing and repurposing<br />

valuable image assets.<br />

Excalibur Text<br />

Search<br />

358 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong><br />

This module enables provides extensive<br />

text-searching capabilities; It supports<br />

full-text indexing, including extensive<br />

fuzzy-search logic for indexing scanned<br />

text. Can search document types<br />

including: ASCII, Word, Excel, HTML,<br />

PowerPoint, WordPerfect, and PDF.<br />

Includes an adaptive pattern recognition<br />

process (APRP) and capabilities such as<br />

multiple stop-word lists, proximity<br />

searching and synonym lists.<br />

Geodetic This blade supports global space- and<br />

time based queries. It is designed to treat<br />

earth as a globe rather than a flat plane.<br />

Supports client-side Geographic<br />

Information Systems (GIS) software.<br />

Spatial This blade transforms locations and<br />

traditional 2-d map data into useful<br />

information. Uses SQL-based spatial data<br />

types and functions that can be used<br />

directly through standard SQL queries or<br />

with client-side Geographic Information<br />

Systems (GIS) software.<br />

Available on<br />

standard install<br />

No charge<br />

download<br />

License fee applies<br />

License fee applies<br />

No charge<br />

download


<strong>IBM</strong> <strong>Informix</strong><br />

DataBlade<br />

module name Description Special notes<br />

TimeSeries This module supports data for managing<br />

time-series and temporal data. A “time<br />

series” is any set of data that is accessed<br />

in sequence by time and can be<br />

processed and analyzed in a<br />

chronological order.<br />

Video Foundation This blade allows you to incorporate video<br />

servers, external control devices,<br />

compression codes, and cataloging tools<br />

to manage video content and metadata or<br />

information about the content. Allows<br />

metadata elements in the database, while<br />

allowing video content to be maintained<br />

on disk, video tape, video server, or other<br />

external storage devices.<br />

Web This module supports most web server<br />

APIs and has a web client application to<br />

build and run SQL queries to work with<br />

your database. Enables customized web<br />

applications. Allows you to track<br />

persistent session variables between<br />

AppPages.<br />

10.3.3 Developing a bladelet routine<br />

License fee<br />

applies.<br />

License fee<br />

applies.<br />

License fee applies<br />

We can define a bladelet as a small, unofficial DataBlade module. It is meant to<br />

be useful (and complete with source code) from the time you set it up, but it<br />

becomes your own application (with no support or warranty). If you have tried out<br />

our UDR development examples, you have a bladelet.<br />

As you might have observed from having to drop and re-create the JAR API in<br />

the server in our earlier example, you can understand that if you have a large<br />

number of UDRs and have gone to the trouble of creating user-defined data<br />

types, the whole package of tasks that are required to set up, change, or update<br />

a DataBlade object inside the server might not be a convenient task.<br />

On a large scale, if you have API dependencies, dozens of UDRs, and other<br />

DataBlade related objects, you will want to move them and install them as a<br />

package. <strong>IBM</strong> <strong>Informix</strong> provides a Windows-based interface for this, which has<br />

the ability to do the package preparation work for you. The package preparation<br />

Chapter 10. User-defined routines 359


interface, called BladeSmith, allows you to populate a properties definition<br />

dictionary.<br />

When the properties are all defined and you proceed, BladeSmith creates,<br />

assembles, and arranges a directory structure with a complete tree layout of all<br />

the components that are required and handled in a DataBlade registration<br />

process. The resulting directory tree layout and assembly pieces provide a<br />

prepared package that is ready to ship to an operating system of your choice.<br />

Likewise, any language source code that is output for the preparation task is<br />

parcelled out for the appropriate component nodes also.<br />

The dispensation for the BladeSmith file components and directory structure is<br />

laid out based on the type of component node, as described in Table 10-3.<br />

Table 10-3 BladeSmith file package creation layout<br />

Component node What is generated<br />

Source All source code in the coding languages you use for your<br />

DataBlade module objects<br />

Client Client code (ActiveX or Java)<br />

Server Server code in the coding language you specified for BladeSmith<br />

Individual language Source code for the represented language (C, Java, or SPL)<br />

For further information about creating datablade objects using BladeSmith<br />

generating files, refer to:<br />

http://publib.boulder.ibm.com/infocenter/idshelp/v115/index.jsp?topic=/com.ibm.<br />

dbdk.doc/sii-smith-27272.htm<br />

For further information or examples of existing bladelets and downloads<br />

developed by users, refer to:<br />

http://www.ibm.com/developerworks/data/zones/informix/library/samples/db_downlo<br />

ads.html<br />

There is also a downloads page that features bladelets at the International<br />

<strong>Informix</strong> Users Group site called “ORDBMS - Object-Relational Database<br />

Extensibility, DataBlades” at:<br />

http://www.iiug.org/software/index_ORDBMS.html<br />

360 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Chapter 11. Working with Ruby on Rails<br />

This chapter contains information about how to develop applications against an<br />

<strong>IBM</strong> <strong>Informix</strong> database using the Ruby programming language and the Ruby on<br />

Rails web development framework.<br />

In this chapter, we discuss the following topics:<br />

► A brief overview of Ruby on Rails<br />

► Setup and configuration<br />

► Database operations<br />

► Using the Rails Adapter with Ruby <strong>Informix</strong><br />

► Using the Rails Adapter with <strong>IBM</strong>_DB<br />

11<br />

© Copyright <strong>IBM</strong> Corp. 2010. All rights reserved. 361


11.1 A brief overview of Ruby on Rails<br />

Ruby is a open source programming scripting language with a focus on simplicity<br />

and productivity. Ruby is similar to other scripting languages like Perl or Python<br />

with the difference that Ruby is an object-oriented language. Ruby is both<br />

technology- and platform-independent. You can find implementations of the Ruby<br />

run time on C, Java, and even .NET, making Ruby a useful option for any<br />

scripting need.<br />

For more information about the Ruby language, refer to:<br />

http://www.ruby-lang.org/en/about/<br />

Rails is an open source Ruby framework for developing database-backed web<br />

applications. Rails expands the object-orientated core design of Ruby, helping<br />

developers to build websites and applications with minimum coding efforts.<br />

Rails is based on two key principles:<br />

► Convention over configuration (CoC), where developers need to focus only<br />

on the exceptions to the conventions. Every other aspect of the application,<br />

from design to implementation, is done automatically by the defined<br />

conventions.<br />

The conventions define rules such as use a plural for the table names. For<br />

example, if the application uses an entity called Book, the table that stores<br />

this entity must be called Books, and if it stores details about a Person, the<br />

table must be called People.<br />

► Don’t Repeat Yourself (DRY). Information is located in one place only.<br />

Database object definitions, documentation, and configuration scripts all are<br />

kept in one location and are consulted when information about them is<br />

required.<br />

For more information, refer to:<br />

http://rubyonrails.org/documentation<br />

362 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


11.1.1 Architecture of Ruby on Rails<br />

Ruby on Rails is built with the Model, View, Controller (MVC) architecture that is<br />

typically used in web-based GUI programming. This architecture has three main<br />

concepts:<br />

► Model<br />

The business logic of the system, which encompasses the persistence layer<br />

because it interacts with a database back end.<br />

► View<br />

The GUI interface of the model that is visible to the user. One Model can have<br />

many views.<br />

► Controller<br />

The action taken by the user using the view. The controller takes inputs from<br />

the user through the view and executes the business logic encapsulated in<br />

the model.<br />

The Rails framework provides a set of utilities and components that are designed<br />

to facilitate the development of web applications:<br />

► Rake is a build tool that is bundled with the Ruby programming language. It is<br />

the equivalent to the make command on UNIX.<br />

► WEBrick is the web server that is bundled with Ruby on Rails.<br />

► ActiveRecord is the object-relational mapper of Rails and provides for<br />

persistence. It presents the database table as a class, which in Rails is called<br />

model.<br />

► Action Controller is the component that manages the controllers in a Rails<br />

application. It also processes and dispatches incoming requests.<br />

► Action View manages the views in a Rails application.<br />

11.1.2 Ruby Driver and Rails Adapter<br />

<strong>IBM</strong> <strong>Informix</strong> supports database access for client applications written in the Ruby<br />

programming language and web application development with the Rail<br />

framework.<br />

Ruby Driver<br />

To use an database with Ruby, the application requires a Ruby driver. This driver<br />

provides the layer that connect the Ruby run time with the database server.<br />

Chapter 11. Working with Ruby on Rails 363


The following drivers allow Ruby to connect to an <strong>IBM</strong> <strong>Informix</strong> database:<br />

► The Ruby <strong>Informix</strong> driver is an open source project supported by the open<br />

source community. It allows Ruby to connect to any <strong>IBM</strong> <strong>Informix</strong> database<br />

server. The Ruby driver is developed using the <strong>IBM</strong> <strong>Informix</strong> ESQL/C<br />

language that provides full support for all the <strong>Informix</strong> database features and<br />

data types. Because it uses the <strong>Informix</strong> Client Software Development Kit<br />

(Client SDK) libraries,<br />

► Ruby Driver for <strong>IBM</strong> Data Servers driver (<strong>IBM</strong>_DB) is provided, supported,<br />

and developed by <strong>IBM</strong> as an open source project. The Ruby driver is bundled<br />

together with the Rails Adapter in the Rails Adapter/Driver for <strong>IBM</strong> Data<br />

Servers package.<br />

Rails Adapter<br />

A Rails Adapter is a Ruby script that allows you to use a specific Ruby driver<br />

within the Rails framework. It provides the required Ruby objects, for example the<br />

ActiveRecord object, that enable the full use of the Ruby driver inside the Rails<br />

framework.<br />

<strong>IBM</strong> <strong>Informix</strong> supports the following Rails adapters:<br />

► informix_adapter.rb, used in conjunction with the Ruby <strong>Informix</strong> driver.<br />

Requires Client SDK libraries for the communication with the <strong>Informix</strong><br />

database server.<br />

► ibm_db_adapter.rb, used with the Ruby Driver for <strong>IBM</strong> Data Servers.<br />

Requires the <strong>IBM</strong> Data Server Driver for ODBC and CLI package.<br />

Both adapters are available from the Ruby repository as Ruby gems. Ruby gems<br />

are self-contained packages that contain all the libraries, source files, and scripts<br />

needed for the Ruby component.<br />

11.2 Setup and configuration<br />

This section describes how to set up and configure both Ruby drivers and Rails<br />

adapters for use with an <strong>IBM</strong> <strong>Informix</strong> database.<br />

11.2.1 Ruby <strong>Informix</strong> driver<br />

The Ruby <strong>Informix</strong> driver is available for download at the SourceForge website at:<br />

http://rubyforge.org/projects/ruby-informix<br />

364 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


You can use the Ruby gem utility to download the Ruby <strong>Informix</strong> driver<br />

automatically from the Ruby repository and install it in the Ruby environment.<br />

Run the following command from your Ruby session to install the Ruby <strong>Informix</strong><br />

driver:<br />

gem install ruby-informix<br />

Because the driver shared library, informixc.so, is built during the installation<br />

process, the environment should contain the correct settings for compiling<br />

ESQL/C applications. Refer to Chapter 4, “Working with ESQL/C” on page 125<br />

for more information about ESQL/C settings.<br />

You can find more information about the installation process in the README file<br />

inside the gem directory. See Example 11-1 for the list of files that are included<br />

with the Ruby <strong>Informix</strong> driver.<br />

Example 11-1 The gem directory<br />

Directory of C:\work\Ruby187\lib\ruby\gems\1.8\gems\ruby-informix-0.7.3<br />

03/07/2010 19:34 .<br />

03/07/2010 19:34 ..<br />

03/07/2010 19:19 8,383 Changelog<br />

03/07/2010 19:19 1,470 COPYRIGHT<br />

03/07/2010 19:29 ext<br />

03/07/2010 19:35 lib<br />

03/07/2010 19:19 4,500 README<br />

03/07/2010 19:19 test<br />

3 File(s) 14,353 bytes<br />

5 Dir(s) 76,168,769,536 bytes free<br />

Configuration<br />

The Ruby <strong>Informix</strong> uses the same connectivity information as other Client SDK<br />

components. It uses the INFORMIXDIR environment variable to locate the<br />

libraries and resources such as error message files or configuration files.<br />

By default, the Ruby driver connects to the database server specified in the<br />

INFORMIXSERVER environment variable. Same as the other Client SDK<br />

components, the information regarding the INFORMIXSERVER value is stored<br />

on the sqlhosts file or the Windows registry. For more information, refer to<br />

“Connectivity on UNIX” on page 27.<br />

The shared library search path variables, for example, LD_LIBRARY_PATH or<br />

SHLIB_PATH, must contain the $INFORMIX/libl and $INFORMIX/lib/esql<br />

directories. Otherwise, the Ruby driver might fail to load the ESQL/C libraries that<br />

it requires for work.<br />

Chapter 11. Working with Ruby on Rails 365


Data types<br />

The Ruby <strong>Informix</strong> driver provides the data types to be used against an <strong>IBM</strong><br />

<strong>Informix</strong> database. The driver provides specific types such as<br />

<strong>Informix</strong>::IntervalYTM or <strong>Informix</strong>::Slob to handle specific <strong>Informix</strong> types.<br />

Table 11-1 shows the data type mapping between the Ruby <strong>Informix</strong> driver and<br />

the <strong>Informix</strong> database.<br />

Table 11-1 Ruby <strong>Informix</strong> data type mapping<br />

<strong>Informix</strong> data type Ruby data type<br />

SMALLINT, INT, INT8, FLOAT, SERIAL<br />

and SERIAL8<br />

CHAR, NCHAR, VARCHAR,<br />

NVARCHAR<br />

Verifying connectivity<br />

Ruby includes an interactive shell called irb that you can use to run simple Ruby<br />

statements. The irb is located in the bin directory of the Ruby installation.<br />

The driver name used inside the Ruby scripts to reference the Ruby <strong>Informix</strong><br />

driver is informix.<br />

To test whether the Ruby driver can connect to a database, you must load the<br />

Ruby driver and then create a connection using the Ruby <strong>Informix</strong> object.<br />

366 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong><br />

Numeric<br />

String<br />

DATE Date<br />

DATETIME TIME<br />

INTERVAL <strong>Informix</strong>::IntervalYTM, <strong>Informix</strong>::IntervalDTS<br />

DECIMAL, MONEY BigDecimal<br />

BOOL TrueClass, FalseClass<br />

BYTE, TEXT StringIO, String<br />

CLOB, BLOB <strong>Informix</strong>::Slob


Example 11-2 demonstrates how to load the Ruby <strong>Informix</strong> driver and connect to<br />

an <strong>IBM</strong> <strong>Informix</strong> database. The fist command, require 'informix', tells the<br />

Ruby run time to load the Ruby <strong>Informix</strong> driver. After that, it creates a Ruby<br />

<strong>Informix</strong> connection object and prints the database version information.<br />

Example 11-2 Testing connection with Ruby informix<br />

C:\work>irb<br />

irb(main):001:0> require 'informix'<br />

=> true<br />

irb(main):002:0> db=<strong>Informix</strong>.connect('stores_demo','informix','password')<br />

=> #<br />

irb(main):003:0> puts db.version<br />

<strong>IBM</strong> <strong>Informix</strong> Dynamic Server Version 11.50.FC6<br />

=> nil<br />

irb(main):004:0><br />

11.2.2 Data Server Ruby driver<br />

The Data Server Ruby driver uses the Data Server CLI driver to connect the<br />

<strong>Informix</strong> database. It uses the DRDA protocol so the version of the <strong>IBM</strong> <strong>Informix</strong><br />

database server must be 11.10 or 11.50.<br />

The driver is included with <strong>IBM</strong> Data Server Driver and is also available to<br />

download directly from the RubyForge website:<br />

http://rubyforge.org/projects/rubyibm/<br />

You can install the complete package using the Ruby gem utility by running the<br />

following command from a Ruby session:<br />

gem install ibm_db<br />

For information about the build and setup process for Data Server Driver, consult<br />

the README file in the driver directory.<br />

Example 11-3 shows the Data Server Ruby driver directory.<br />

Example 11-3 The ibm_db gem directory<br />

Directory of C:\work\Ruby187\lib\ruby\gems\1.8\gems\ibm_db-0.10.0-x86-mswin32<br />

03/07/2010 17:30 .<br />

03/07/2010 17:30 ..<br />

03/07/2010 17:30 6,063 CHANGES<br />

03/07/2010 17:30 ext<br />

03/07/2010 17:30 1,656 init.rb<br />

03/07/2010 18:06 lib<br />

Chapter 11. Working with Ruby on Rails 367


03/07/2010 17:30 1,088 LICENSE<br />

03/07/2010 17:30 299 MANIFEST<br />

03/07/2010 17:30 13,402 README<br />

03/07/2010 17:30 test<br />

5 File(s) 22,508 bytes<br />

5 Dir(s) 76,167,290,880 bytes free<br />

You can find additional information regarding the Ruby driver for <strong>IBM</strong> Data<br />

Servers at:<br />

http://publib.boulder.ibm.com/infocenter/db2luw/v9r5/topic/com.ibm.db2.luw.apdv<br />

.ruby.doc/doc/t0052765.html<br />

On some platforms, such as Windows operating system platforms, the shared<br />

library for the Ruby driver is already included in the package. Therefore, there is<br />

no need for a C build environment.<br />

Example 11-4 shows the Ruby driver directory from Data Server Client on a<br />

Windows system after the installation.<br />

Example 11-4 Windows system Data Server Ruby directory<br />

C:\work>dir "C:\Program Files\<strong>IBM</strong>\<strong>IBM</strong> DATA SERVER DRIVER\ruby"<br />

Volume in drive C is W2003<br />

Volume Serial Number is 50DA-70D7<br />

Directory of C:\Program Files\<strong>IBM</strong>\<strong>IBM</strong> DATA SERVER DRIVER\ruby<br />

17/05/2010 02:16 .<br />

17/05/2010 02:16 ..<br />

30/05/2009 11:09 198,144 ibm_db-0.10.0-mswin32.gem<br />

1 File(s) 198,144 bytes<br />

2 Dir(s) 76,167,372,800 bytes free<br />

C:\work><br />

Configuration<br />

The Data Server Ruby driver uses the Data Server ODBC/CLI driver for the<br />

connection to the database.<br />

The configuration details are the same as with the ODCB/CLI driver. These<br />

details are usually kept in the db2profile.ini file. Refer to 2.2.3, “Setting up <strong>IBM</strong><br />

Data Server drivers” on page 43 for detailed information about Data Server<br />

Driver configuration.<br />

368 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


11.2.3 Rails adapters<br />

Data types<br />

There are no specific Ruby objects to use <strong>Informix</strong> data types. Data Server Ruby<br />

driver supports the same <strong>Informix</strong> data types as Data Server Driver for CLI.<br />

Verifying connectivity<br />

We use an irb session to test the connectivity against an <strong>IBM</strong> <strong>Informix</strong> database<br />

server.<br />

The reference name of the Data Server Ruby driver is ibm_db. You must load this<br />

driver before creating the Ruby connection object.<br />

Example 11-5 shows how to load the Ruby driver and how to connect to the<br />

<strong>Informix</strong> server.<br />

Example 11-5 Testing connection with data server Ruby driver<br />

C:\work>irb<br />

irb(main):001:0> require 'mswin32/ibm_db'<br />

=> true<br />

irb(main):002:0> db=<strong>IBM</strong>_DB.connect 'dsc_dsn','informix','password'<br />

=> #<br />

irb(main):003:0><br />

First, load the Ruby driver with require 'mswin32/ibm_db'. Then, open the<br />

connection using the <strong>IBM</strong>_DB::connect method.<br />

Note: Because we use the Windows version of the Ruby driver, we must prefix<br />

the driver name with the mswin32 directory.<br />

You can also made a dsn-less connection by specifying all the required<br />

parameters in the connection string as follows:<br />

<strong>IBM</strong>_DB.connect 'DRIVER={<strong>IBM</strong> DB2 ODBC DRIVER};DATABASE=stores_demo;<br />

HOSTNAME=kodiak;PORT=9089;PROTOCOL=TCPIP;UID=informix;PWD=password;', '', ''<br />

The Ruby <strong>Informix</strong> Rails Adapter provides the Ruby ActiveRecord object that<br />

makes the use of the Ruby driver to work on the Rails framework possible.<br />

The Rails Adapter for the Ruby <strong>Informix</strong> driver is a free download that is available<br />

at:<br />

http://rubyforge.org/projects/rails-informix/<br />

Chapter 11. Working with Ruby on Rails 369


The Rails Adapter can be installed automatically as a Ruby gem using the gem<br />

utility. Example 11-6 shows how to install the Ruby <strong>Informix</strong> adapter.<br />

Example 11-6 Installing the Ruby <strong>Informix</strong> adapter<br />

C:\work>gem install activerecord-informix-adapter -v 1.1.1<br />

Successfully installed activerecord-informix-adapter-1.1.1<br />

1 gem installed<br />

Installing ri documentation for activerecord-informix-adapter-1.1.1...<br />

Installing RDoc documentation for activerecord-informix-adapter-1.1.1...<br />

C:\work><br />

The configuration of the adapter depends on the version of Rails that is installed<br />

in the Ruby environment. On versions older than 2.x, you need to copy the<br />

informix_adapter.rb adapter script file into the connection_adapters directory.<br />

Example 11-7 shows the connection_adapter directory with both Rails adapters<br />

installed.<br />

Example 11-7 The connection _adapter directory<br />

Directory of<br />

C:\work\Ruby187\lib\ruby\gems\1.8\gems\activerecord-1.15.6\lib\active_record\co<br />

nnection_adapters<br />

3/07/2010 18:02 .<br />

3/07/2010 18:02 ..<br />

3/07/2010 17:01 abstract<br />

3/07/2010 17:01 5,235 abstract_adapter.rb<br />

3/07/2010 17:01 6,957 db2_adapter.rb<br />

3/07/2010 17:01 27,749 firebird_adapter.rb<br />

3/07/2010 17:01 30,751 frontbase_adapter.rb<br />

3/07/2010 17:30 70,854 ibm_db_adapter.rb<br />

3/07/2010 20:06 9,916 informix_adapter.rb<br />

3/07/2010 17:01 13,774 mysql_adapter.rb<br />

3/07/2010 17:01 11,531 openbase_adapter.rb<br />

3/07/2010 17:01 25,897 oracle_adapter.rb<br />

3/07/2010 17:01 21,513 postgresql_adapter.rb<br />

3/07/2010 17:01 13,162 sqlite_adapter.rb<br />

3/07/2010 17:01 22,087 sqlserver_adapter.rb<br />

3/07/2010 17:01 22,622 sybase_adapter.rb<br />

13 File(s) 282,048 bytes<br />

3 Dir(s) 76,166,725,632 bytes free<br />

370 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


When using versions of Rails older than 2.x, it is also required to include the<br />

reference name of the Ruby driver in the RAILS_CONNECTION_ADAPTER<br />

parameter in the ActiveRecord Ruby script (see Example 11-8).<br />

Example 11-8 The active_record file<br />

C:\work\Ruby187\lib\ruby\gems\1.8\gems\activerecord-1.15.6\lib>grep informix<br />

active_record.rb<br />

RAILS_CONNECTION_ADAPTERS = %w( mysql postgresql sqlite firebird sqlserver<br />

db2 oracle sybase openbase frontbase informix ibm_db )<br />

C:\work\Ruby187\lib\ruby\gems\1.8\gems\activerecord-1.15.6\lib><br />

After creating a Rails project, you must update the project configuration file that<br />

contains the database information, database.yml, with the connection details of<br />

the <strong>IBM</strong> <strong>Informix</strong> database. This file is located in the /config directory<br />

and has three sections:<br />

► Development<br />

► Test<br />

► Production<br />

These sections point to databases on the respective environments. The<br />

database connectivity properties include:<br />

► adapter: The Ruby driver used. You do not have to give the complete version.<br />

► database: Database to which to connect.<br />

► username and password: To connect to the <strong>Informix</strong> server.<br />

► server: The system on which the <strong>Informix</strong> server is running.<br />

► port: The DRDA port on the <strong>Informix</strong> server.<br />

Example 11-9 shows a typical database.yml file with the details for an <strong>IBM</strong><br />

<strong>Informix</strong> database. The Rails application is named stores7, and we connect to<br />

an <strong>Informix</strong> server called demo_on.<br />

We use the Ruby <strong>Informix</strong> driver reference name for the adapter parameter<br />

informix. The server parameter identifies the <strong>Informix</strong> server to connect to. The<br />

information about the <strong>Informix</strong> server, such as host and port, is retrieved from the<br />

sqlhosts file or Windows registry.<br />

Example 11-9 The database.yml file for the Ruby informix Adapter<br />

C:\work\stores7\config>type database.yml<br />

development:<br />

adapter: informix<br />

database: stores7<br />

pool: 5<br />

timeout: 5000<br />

Chapter 11. Working with Ruby on Rails 371


server: demo_on<br />

username: informix<br />

password: password<br />

# Warning: The database defined as 'test' will be erased and<br />

# re-generated from your development database when you run 'rake'.<br />

# Do not set this db to the same as development or production.<br />

test:<br />

adapter: mysql<br />

database: stores7<br />

username: root<br />

password:<br />

host: localhost<br />

production:<br />

adapter: informix<br />

database: stores7<br />

pool: 5<br />

timeout: 5000<br />

server: demo_on<br />

username: informix<br />

password: password<br />

C:\work\stores7\config><br />

Rails Adapter for <strong>IBM</strong> Data Server<br />

The Rails Adapter for the <strong>IBM</strong> Data Server Ruby driver is bundled with the Ruby<br />

driver. It is installed when the Ruby driver is installed.<br />

In the same way as with the Ruby <strong>Informix</strong> Rails Adapter, if the Rails Adapter for<br />

<strong>IBM</strong> Data Server is installed on a version of Rails older than 2.x, the adapter<br />

script (informix_adapter.rb) must be copied in the connection_adapter<br />

directory, and the RAILS_CONNECTION_ADAPTER parameter in the<br />

active_record.rb Ruby script has to be updated.<br />

The database configuration file for a Rails project, database.yml, has to be<br />

updated with the details for the <strong>Informix</strong> server.<br />

Example 11-10 shows a database.yml file that is used in a Rails project that<br />

connects to an <strong>IBM</strong> <strong>Informix</strong> database.<br />

Example 11-10 The database.yml file for the Rails Adapter for <strong>IBM</strong> Data Servers<br />

C:\work\stores7\config>type database.yml<br />

development:<br />

adapter: ibm_db<br />

372 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


database: stores7<br />

pool: 5<br />

timeout: 5000<br />

host: kodiak<br />

port: 9089<br />

username: informix<br />

password: password<br />

# Warning: The database defined as 'test' will be erased and<br />

# re-generated from your development database when you run 'rake'.<br />

# Do not set this db to the same as development or production.<br />

test:<br />

adapter: mysql<br />

database: stores7<br />

username: root<br />

password:<br />

host: localhost<br />

C:\work\stores7\config><br />

The adapter parameter is set to the reference name of the Data Server Ruby<br />

driver ibm_db. It also contains the host name and the port parameter with the<br />

details about the DRDA <strong>Informix</strong> instance. These details are the same as used in<br />

the Data Server driver for ODBC/CLI.<br />

For a list of all the parameters, refer to:<br />

http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.swg.im.dbcli<br />

ent.ruby.doc/doc/t0052780.html<br />

11.3 Database operations<br />

This section provides examples of using both Ruby drivers to perform basic<br />

operations against an <strong>IBM</strong> <strong>Informix</strong> database server. It also demonstrates how to<br />

use the Rails Adapter to create basic web applications.<br />

Chapter 11. Working with Ruby on Rails 373


Using Ruby <strong>Informix</strong> driver<br />

In this section, we discuss the basic database operation using the Ruby <strong>Informix</strong><br />

driver.<br />

Connection to the database<br />

Example 11-11 shows how to connect to an <strong>Informix</strong> database. The database<br />

name, user name, and password are passed as the parameters in the command<br />

line.<br />

Example 11-11 The ifx_connect.rb output<br />

C:\work>type ifx_connect.rb<br />

# load the informix driver<br />

require 'informix'<br />

# Connect to the database<br />

db = <strong>Informix</strong>.connect(ARGV[0],ARGV[1],ARGV[2])<br />

# print database information<br />

print "Connected to #{db.version}"<br />

db.close<br />

C:\work>ruby ifx_connect.rb stores_demo informix password<br />

Connected to <strong>IBM</strong> <strong>Informix</strong> Dynamic Server Version 11.50.FC6<br />

C:\work><br />

Getting information about a table<br />

Example 11-12 demonstrates how to use the Ruby connection object to retrieve<br />

metadata information about the state table. It uses the columns() method of the<br />

<strong>Informix</strong> connection object to retrieve a Ruby array with all the metadata<br />

information.<br />

Example 11-12 The ifx_metadata.rb output<br />

C:\work>cat ifx_metadata.rb<br />

# load the informix driver<br />

require 'informix'<br />

# Connect to the database<br />

db = <strong>Informix</strong>.connect(ARGV[0])<br />

# print database information<br />

print "Connected to #{db.version}\n"<br />

db.columns(ARGV[1]).each {<br />

|name| name.each {|elem| print " #{elem[0]} #{elem[1]}\n"}<br />

}<br />

db.close<br />

C:\work>ruby ifx_metadata.rb stores_demo state<br />

Connected to <strong>IBM</strong> <strong>Informix</strong> Dynamic Server Version 11.50.FC6<br />

precision 0<br />

374 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


type 0<br />

scale 0<br />

length 2<br />

xid 0<br />

nullable true<br />

name code<br />

stype CHAR<br />

...<br />

Executing a simple SQL statement<br />

Using the Ruby driver, you can run an SQL statement directly from the Ruby<br />

connection object or through a prepared statement object.<br />

Example 11-13 demonstrates how to run a simple SQL statement using a<br />

prepared statement Ruby object. The execute() method returns the number of<br />

affected rows.<br />

Example 11-13 The ifx_execute.rb output<br />

C:\work>cat ifx_execute.rb<br />

# load the informix driver<br />

require 'informix'<br />

# Connect to the database<br />

db = <strong>Informix</strong>.connect(ARGV[0])<br />

# print database information<br />

print "Connected to #{db.version}\n"<br />

# create a prepare object with the SQL passed<br />

stmt = db.prepare(ARGV[1])<br />

# Execute the prepared statement<br />

rc=stmt.execute()<br />

print "Result=#{rc}"<br />

db.close<br />

C:\work>ruby ifx_execute.rb stores_demo "DELETE from STATE where CODE='AR'"<br />

Connected to <strong>IBM</strong> <strong>Informix</strong> Dynamic Server Version 11.50.FC6<br />

Result=1<br />

C:\work><br />

Chapter 11. Working with Ruby on Rails 375


If the SQL statement returns only one row, you can use the execute() method to<br />

retrieve that value (see Example 11-14).<br />

Example 11-14 The ifx_execute.rb output<br />

C:\work>ruby ifx_execute.rb stores_demo "SELECT sname FROM state WHERE<br />

code='CA'"<br />

Connected to <strong>IBM</strong> <strong>Informix</strong> Dynamic Server Version 11.50.FC6<br />

Result=snameCalifornia<br />

C:\work><br />

Using parameters<br />

Example 11-15 shows how to prepare and execute a parametrized INSERT<br />

statement using the Ruby driver.<br />

Example 11-15 The ifx_parameters output<br />

C:\work>cat ifx_insert.rb<br />

# load the informix driver<br />

require 'informix'<br />

# Connect to the database<br />

db = <strong>Informix</strong>.connect('stores_demo')<br />

# print database information<br />

print "Connected to #{db.version}\n"<br />

# create a prepare object with the SQL passed<br />

stmt = db.prepare('INSERT INTO state(code,sname) VALUES (?,?)')<br />

# Execute the statement using parameters<br />

rc=stmt.execute(ARGV[0],ARGV[1])<br />

# Execute the prepared statement<br />

print "Result=#{rc}"<br />

db.close<br />

C:\work>ruby ifx_insert.rb AR Arizona<br />

Connected to <strong>IBM</strong> <strong>Informix</strong> Dynamic Server Version 11.50.FC6<br />

Result=1<br />

C:\work><br />

376 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Selecting data from the database<br />

When selecting multiple records from the database the application must create a<br />

cursor object to fetch the selected rows. Example 11-16 illustrates how to return<br />

information using an <strong>Informix</strong> cursor.<br />

Example 11-16 The ifx_cursor.rb output<br />

C:\work>cat ifx_cursor.rb<br />

# load the informix driver<br />

require 'informix'<br />

# Connect to the database<br />

db = <strong>Informix</strong>.connect('stores_demo')<br />

# display database information<br />

print "Connected to #{db.version}\n"<br />

# Create a Cursor object<br />

cur = db.cursor(ARGV[0])<br />

# Open the cursor and fetch some rows<br />

cur.open.each {|rows|<br />

puts rows*" = "<br />

}.close<br />

# Close connection<br />

db.close<br />

C:\work>ruby ifx_cursor.rb "SELECT FIRST 3 sname FROM state"<br />

Connected to <strong>IBM</strong> <strong>Informix</strong> Dynamic Server Version 11.50.FC6<br />

Alaska<br />

Hawaii<br />

California<br />

C:\work><br />

Using the Ruby <strong>Informix</strong> IfxSlob class<br />

The Slob class is the Ruby interface for handling smart large objects. It provides<br />

methods for every action applicable with a smart large object. By using the<br />

<strong>Informix</strong>::Slob class, it is possible to perform the same operations against a<br />

smart large object as with other programming languages and drivers. The Slob<br />

methods such as Seek() or Lock() allow random I/O to individuals part of the<br />

large object that can only be achieved using this Ruby driver.<br />

Chapter 11. Working with Ruby on Rails 377


Example 11-17 shows how to select a BLOB from a database table. It retrieves<br />

the catalog_advert CLOB column from the catalog table and prints out the<br />

content of the large object and the size of the large object.<br />

Example 11-17 The ifx_blob.rb output<br />

C:\work>cat ifx_blob.rb<br />

# load the informix driver<br />

require 'informix'<br />

# Connect to the database<br />

db = <strong>Informix</strong>.connect("stores_demo")<br />

# Creates an <strong>Informix</strong> Slob object<br />

slob = <strong>Informix</strong>::Slob<br />

# Opens a cursor to retrieve<br />

cur = db.cursor("SELECT catalog_num,advert_descr FROM catalog WHERE<br />

catalog_num=?")<br />

cur.open(ARGV[0]).each {|rows|<br />

slob = rows[1].open<br />

print "Number = #{rows[0]}\n"<br />

# Reads the blob data as a String<br />

print "Clob data= #{rows[1].read(rows[1].size)}\n"<br />

print "Clob Size= #{rows[1].size}\n"<br />

# Close the Slob object<br />

slob.close<br />

}<br />

# Close database connection<br />

db.close<br />

C:\work><br />

C:\work>ruby ifx_blob.rb 10001<br />

Number = 10001<br />

Clob data= Brown leather. Specify first baseman's or infield/outfield style.<br />

Clob Size= 98<br />

C:\work>ruby ifx_blob.rb 10027<br />

Number = 10027<br />

Clob data=<br />

Double or triple crankset with choice of chainrings or chunky bacon. For double<br />

crankset...<br />

Clob Size= 154<br />

C:\work>ruby ifx_blob.rb 10031<br />

Number = 10031<br />

Clob data= No buckle so no plastic touches your chin. Meets both ANSI and<br />

Snell...<br />

Clob Size= 123<br />

C:\work><br />

378 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


For examples and a full description of all the method implemented by the<br />

<strong>Informix</strong>::Slob class, refer to:<br />

http://ruby-informix.rubyforge.org/doc/classes/<strong>Informix</strong>/Slob.html<br />

Using the Ruby <strong>Informix</strong> INTERVAL<br />

The Ruby <strong>Informix</strong> driver provides a specific class to deal with the <strong>Informix</strong><br />

INTERVAL data type.<br />

Example 11-18 shows how to define and use the <strong>Informix</strong>::Interval class. In<br />

this example we create an Interval Year to Month with one year and one month<br />

as the value. The code performs a simple arithmetic operation adding the Interval<br />

to the current date.<br />

Example 11-18 The ifx_interval.rb output<br />

# Creates an <strong>Informix</strong> Interval object<br />

minterval = <strong>Informix</strong>::Interval.year_to_month(1, 1)<br />

print "Interval \t=#{minterval}\n"<br />

today = Date.today<br />

print "Current date \t=#{today}\n"<br />

print"Interval+today\t=#{minterval + today}\n"<br />

C:\work>ruby ifx_interval.rb<br />

Interval =1-01<br />

Current date =2010-07-04<br />

Interval+today =2011-08-04<br />

C:\work><br />

You can fine the full documentation about all the methods supported by the Ruby<br />

<strong>Informix</strong> driver at:<br />

http://ruby-informix.rubyforge.org/doc/<br />

Using Data Server Ruby driver<br />

In this section, we discuss the basic database operation using the Data Server<br />

Ruby driver.<br />

Connecting to the database<br />

The syntax for opening a connection with an <strong>Informix</strong> database server using the<br />

Data Server Ruby driver differs from the syntax used by the Ruby <strong>Informix</strong> driver.<br />

Chapter 11. Working with Ruby on Rails 379


Example 11-19 shows a simple Ruby script that creates a connection object and<br />

opens the connection. In the example code we also retrieve information about<br />

the <strong>Informix</strong> server using the <strong>IBM</strong>_DB::server_info class.<br />

Example 11-19 The dsc_connect.rb script<br />

C:\work>cat dsc_connect.rb<br />

# load the informix driver<br />

require 'mswin32/ibm_db'<br />

# Connect to the database<br />

db = <strong>IBM</strong>_DB.connect(ARGV[0],ARGV[1],ARGV[2])<br />

info = <strong>IBM</strong>_DB.server_info(db)<br />

# display database information<br />

print "Connected to #{info.DBMS_NAME} #{info.DBMS_VER}"<br />

C:\work>ruby dsc_connect.rb testdsc informix password<br />

Connected to IDS/NT64 11.50.0000<br />

C:\work><br />

The Data Server Ruby driver is based on calls to the CLI driver, this means it<br />

takes the connection details from the db2cli.ini configuration file.<br />

Example 11-20 shows the contents of the db2cli.ini file that we used for this<br />

test.<br />

Example 11-20 The db2cli.ini file<br />

C:\work>type "c:\Documents and Settings\Administrator\db2cli.ini"<br />

[dsc_dsn]<br />

Protocol=TCPIP<br />

Port=9089<br />

Hostname=kodiak<br />

Database=stores_demo<br />

PWD=password<br />

UID=informix<br />

C:\work><br />

380 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Executing an SQL statement<br />

Example 11-21 demonstrates how to execute an SQL statement using the<br />

prepare() and execute() methods of the <strong>IBM</strong>_DB driver. Both methods,<br />

prepare() and execute(), require the connection and statement objects as<br />

parameters.<br />

Example 11-21 The dsc_execute.rb output<br />

C:\work>cat dsc_execute.rb<br />

# load the informix driver<br />

require 'mswin32/ibm_db'<br />

# Connect to the database<br />

db = <strong>IBM</strong>_DB.connect(ARGV[0],'','')<br />

info = <strong>IBM</strong>_DB.server_info(db)<br />

# display database information<br />

print "Connected to #{info.DBMS_NAME} #{info.DBMS_VER}\n"<br />

# create a prepare object with the SQL passed<br />

stmt = <strong>IBM</strong>_DB.prepare(db,ARGV[1])<br />

# Execute the prepared statement<br />

rc=<strong>IBM</strong>_DB.execute(stmt)<br />

print "Result=#{rc}"<br />

C:\work>ruby dsc_execute.rb dsc_dsn "DELETE from STATE WHERE code='NW'"<br />

Connected to IDS/NT64 11.50.0000<br />

Result=true<br />

C:\work><br />

Parametrized SQL statement<br />

When using parameters for an SQL statement, the application can use the<br />

execute() method. You can provide the parameters as a second argument for<br />

the method call.<br />

Example 11-22 insert a new record into the state table with the values passed to<br />

the script through the command line.<br />

Example 11-22 The dsc_param.rb output<br />

C:\work>cat dsc_param.rb<br />

# load the informix driver<br />

require 'mswin32/ibm_db'<br />

# Connect to the database<br />

db = <strong>IBM</strong>_DB.connect('dsc_dsn','','')<br />

info = <strong>IBM</strong>_DB.server_info(db)<br />

# display database information<br />

print "Connected to #{info.DBMS_NAME} #{info.DBMS_VER}\n"<br />

sql = 'INSERT INTO state(code, sname) VALUES (?,?)'<br />

Chapter 11. Working with Ruby on Rails 381


# create a prepare object<br />

stmt = <strong>IBM</strong>_DB.prepare(db,sql)<br />

# display Statement and parameters<br />

print "SQL=#{sql}\n"<br />

# Execute the prepared statement<br />

rc=<strong>IBM</strong>_DB.execute(stmt,[ARGV[0],ARGV[1]])<br />

print "Result=#{rc}"<br />

C:\work><br />

C:\work>ruby dsc_param.rb "NW" "NewState"<br />

Connected to IDS/NT64 11.50.0000<br />

SQL=INSERT INTO state(code, sname) VALUES (?,?)<br />

Result=true<br />

C:\work><br />

Selecting data<br />

The Data Server Ruby driver has several methods that allow retrieving data from<br />

the database, such as fetch_array(), fetch_assoc(), and fetch_row().<br />

Example 11-23 shows a simple Ruby script that returns the first two columns of<br />

an SQL SELECT statement passed through the command line. The script uses<br />

the fecth_array() method to retrieve the rows as an array object.<br />

Example 11-23 Select data using fetch_array()<br />

C:\work>cat dsc_fetch.rb<br />

# load the informix driver<br />

require 'mswin32/ibm_db'<br />

# Connect to the database<br />

db = <strong>IBM</strong>_DB.connect(ARGV[0],'','')<br />

info = <strong>IBM</strong>_DB.server_info(db)<br />

# display database information<br />

print "Connected to #{info.DBMS_NAME} #{info.DBMS_VER}\n"<br />

# create a prepare object with the SQL passed<br />

stmt = <strong>IBM</strong>_DB.prepare(db,ARGV[1])<br />

# Execute the prepared statement<br />

<strong>IBM</strong>_DB.execute(stmt)<br />

while row = <strong>IBM</strong>_DB.fetch_array(stmt)<br />

puts "#{row[0]}:#{row[1]}"<br />

end<br />

C:\work>ruby dsc_fetch.rb dsc_dsn "SELECT FIRST 3 code,sname FROM state"<br />

Connected to IDS/NT64 11.50.0000<br />

AK:Alaska<br />

HI:Hawaii<br />

CA:California<br />

C:\work><br />

382 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Using smart large objects<br />

The Data Server Ruby driver handles smart large objects as normal data types. It<br />

does not support all the smart features that are normally available with other<br />

drivers. However, it simplifies the code that is needed to deal with these data<br />

types.<br />

Example 11-24 retrieves a CLOB column from the catalog table and displays the<br />

contents.<br />

Example 11-24 The dsc_blob.rb file<br />

C:\work>cat dsc_blob.rb<br />

# load the informix driver<br />

require 'mswin32/ibm_db'<br />

# Connect to the database<br />

db = <strong>IBM</strong>_DB.connect('dsc_dsn','','')<br />

info = <strong>IBM</strong>_DB.server_info(db)<br />

# display database information<br />

print "Connected to #{info.DBMS_NAME} #{info.DBMS_VER}\n"<br />

# create a prepare object with the SQL passed<br />

sql = "SELECT catalog_num,advert_descr FROM catalog WHERE catalog_num=?"<br />

stmt = <strong>IBM</strong>_DB.prepare(db,sql)<br />

# Execute the prepared statement<br />

<strong>IBM</strong>_DB.execute(stmt,ARGV)<br />

while row = <strong>IBM</strong>_DB.fetch_array(stmt)<br />

puts "#{row[0]}:#{row[1]}"<br />

end<br />

C:\work>ruby dsc_blob.rb 10001<br />

Connected to IDS/NT64 11.50.0000<br />

10001:Brown leather. Specify first baseman's or infield/outfield style.<br />

Specify right- or left-handed.<br />

C:\work><br />

You can find additional documentation about the methods for the Ruby for <strong>IBM</strong><br />

Data Server at:<br />

http://rubyibm.rubyforge.org/docs/driver/2.0.0/doc/<br />

You can also find information in the <strong>IBM</strong> DB2 Information Center:<br />

http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.swg.im.dbcli<br />

ent.ruby.doc/doc/c0052760.html<br />

Chapter 11. Working with Ruby on Rails 383


11.4 Using the Rails Adapter with Ruby <strong>Informix</strong><br />

In this section, we demonstrate how to create a basic web application using the<br />

Rails framework with the Ruby <strong>Informix</strong> Adapter.<br />

One of the key concepts of Rails is Convention over Configuration, meaning that<br />

you must follow the convention rules when designing your database so that the<br />

Rails framework can generate code automatically to handle typical operations<br />

with the database.<br />

The following convention rules are required by the Rails framework:<br />

► Table name must be a plural name for the entity it contains. For example, if<br />

the table contains information about books, it should be called Books.<br />

► The table must contains an unique primary key column and should be called<br />

ID.<br />

► You must create an <strong>Informix</strong> SQL SEQUENCE for each of the tables used for<br />

both Ruby drivers. The name of the sequence must be tablename_seq.<br />

You can find additional information about Rails conventions at:<br />

http://guides.rubyonrails.org/<br />

11.4.1 Creating database objects<br />

The following examples use the orders and items tables from the stores7<br />

database. Due to the convention rules used on Rails, we must modify the<br />

schema of the tables to follow the Rails conventions.<br />

Example 11-25 shows the SQL script we use to change the name of the two<br />

tables, create views to incorporate the ID column, and create the SQL sequence<br />

required for object reference.<br />

Example 11-25 The setup.sql script<br />

-- Orders table<br />

RENAME TABLE orders TO order;<br />

CREATE VIEW orders(<br />

id,<br />

order_date,<br />

customer_num,<br />

ship_instruct,<br />

backlog,<br />

po_num,<br />

ship_date,<br />

ship_weigh,<br />

384 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


ship_charge,<br />

paid_date) AS<br />

SELECT * FROM order;<br />

CREATE SEQUENCE orders_seq;<br />

-- Items table<br />

RENAME TABLE items TO item;<br />

CREATE VIEW items (<br />

id,<br />

order_num,<br />

stock_num,<br />

manu_code,<br />

quantity,<br />

total_price) AS<br />

SELECT * FROM item;<br />

CREATE SEQUENCE items_seq;<br />

11.4.2 Creating the Rails application<br />

You must create a Rails application using Rails commands before adding any<br />

objects or definitions.<br />

Example 11-26 shows the output of the rail stores command.<br />

Example 11-26 Output of the rail stores command<br />

C:\work>rails stores<br />

create<br />

create app/controllers<br />

create app/helpers<br />

create app/models<br />

create app/views/layouts<br />

create config/environments<br />

create components<br />

create db<br />

create doc<br />

create lib<br />

create lib/tasks<br />

create log<br />

create public/images<br />

create public/javascripts<br />

create public/stylesheets<br />

...<br />

Chapter 11. Working with Ruby on Rails 385


For more information, refer to:<br />

http://rubyonrails.org/documentation<br />

11.4.3 Modifying the database configuration file<br />

The database.yml file must include the connection details of the database.<br />

Example 11-27 shows the database configuration file used by our application.<br />

Example 11-27 The database.yml file<br />

C:\work\stores>type config\database.yml<br />

development:<br />

adapter: informix<br />

database: stores7<br />

pool: 5<br />

timeout: 5000<br />

server: demo_on<br />

username: informix<br />

password: password<br />

# Warning: The database defined as 'test' will be erased and<br />

# re-generated from your development database when you run 'rake'.<br />

# Do not set this db to the same as development or production.<br />

test:<br />

adapter: mysql<br />

database: stores7<br />

username: root<br />

password:<br />

host: localhost<br />

production:<br />

adapter: informix<br />

database: stores7<br />

pool: 5<br />

timeout: 5000<br />

server: demo_on<br />

username: informix<br />

password: password<br />

C:\work\stores><br />

386 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


11.4.4 Creating the Rails model and controllers<br />

To make Rails aware of the database tables, you create model and controller in<br />

your application. We use the model and controller Ruby script to create model<br />

and controller for the two tables used in our application.<br />

Example 11-28 shows the batch script used to generate the model and controller<br />

for the Items and Orders table.<br />

Example 11-28 The objects.cmd script<br />

ruby script\generate model Order<br />

ruby script\generate controller Order<br />

ruby script\generate model Item<br />

ruby script\generate controller Item<br />

Example 11-29 shows the output of each of the commands in the objects.cmd<br />

batch script.<br />

Example 11-29 Output of the objects.cmd script<br />

C:\work\stores>ruby script\generate model Order<br />

exists app/models/<br />

exists test/unit/<br />

exists test/fixtures/<br />

create app/models/order.rb<br />

create test/unit/order_test.rb<br />

create test/fixtures/orders.yml<br />

exists db/migrate<br />

create db/migrate/004_create_orders.rb<br />

C:\work\stores>ruby script\generate controller Order<br />

exists app/controllers/<br />

exists app/helpers/<br />

create app/views/order<br />

exists test/functional/<br />

create app/controllers/order_controller.rb<br />

create test/functional/order_controller_test.rb<br />

create app/helpers/order_helper.rb<br />

C:\work\stores>ruby script\generate model Item<br />

exists app/models/<br />

exists test/unit/<br />

exists test/fixtures/<br />

create app/models/item.rb<br />

create test/unit/item_test.rb<br />

create test/fixtures/items.yml<br />

Chapter 11. Working with Ruby on Rails 387


388 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong><br />

exists db/migrate<br />

create db/migrate/005_create_items.rb<br />

C:\work\stores>ruby script\generate controller Item<br />

exists app/controllers/<br />

exists app/helpers/<br />

create app/views/item<br />

exists test/functional/<br />

create app/controllers/item_controller.rb<br />

create test/functional/item_controller_test.rb<br />

create app/helpers/item_helper.rb<br />

C:\work\stores><br />

After the objects are created, you must modify the controller Ruby file for each<br />

object to build the object scaffold. We use Rails 1.2.6 on our examples. Rails 2.x<br />

does not support dynamic scaffolding. This means it cannot retrieve the<br />

information for the table column dynamically. In this case, the scaffold for the<br />

objects must be created manually while creating the model object. We add the<br />

instruction scaffold: object_name to each of the files for creating scaffold.<br />

Example 11-30 shows the Ruby script file for the Item and Order controllers.<br />

Example 11-30 Controller script<br />

C:\work\stores>cat app/controllers/order_controller.rb<br />

class OrderController < ApplicationController<br />

scaffold :Order<br />

end<br />

C:\work\stores>cat app/controllers/item_controller.rb<br />

class ItemController < ApplicationController<br />

scaffold :Item<br />

end<br />

C:\work\stores><br />

For more information about the changes in Rails 2.x, refer to:<br />

http://rubyonrails.org/documentation


11.4.5 Starting the Rails web server<br />

To start the Rails web server use the ruby script/server command.<br />

Example 11-31 demonstrates how to start the server.<br />

Example 11-31 Rails web server<br />

C:\work\stores>ruby script/server<br />

=> Booting WEBrick...<br />

=> Rails application started on http://0.0.0.0:3000<br />

=> Ctrl-C to shutdown server; call with --help for options<br />

[2010-07-05 10:40:00] INFO WEBrick 1.3.1<br />

[2010-07-05 10:40:00] INFO ruby 1.8.7 (2010-01-10) [i386-mingw32]<br />

[2010-07-05 10:40:00] INFO WEBrick::HTTPServer#start: pid=1092 port=3000<br />

11.4.6 Demonstrating website application<br />

At this point, Rails should have constructed the application for you, and you can<br />

browse and change the information for your table.<br />

We can open a web browser and navigate to the local web server to browse the<br />

the Order and Item tables:<br />

http://127.0.0.1:3000/item<br />

http://127.0.0.1:3000/order<br />

Chapter 11. Working with Ruby on Rails 389


Figure 11-1 shows the Listing items page. The page contains links to perform all<br />

the typical operations that are associated with a database table (select, insert,<br />

update, and delete).<br />

Figure 11-1 Item listing web page<br />

Figure 11-2 shows the New Item page with all the fields from the Item table ready<br />

to be used to insert a new record into the table.<br />

Figure 11-2 Item New web page<br />

390 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Figure 11-3 shows the Listing Orders page.<br />

Figure 11-3 List Order webpage<br />

The web applications development with Ruby on Rails was designed to be an<br />

effortless task. With just four commands and a little configuration, we created a<br />

website that can handle the common table operations for a database application.<br />

11.5 Using the Rails Adapter with <strong>IBM</strong>_DB<br />

In this section, we demonstrate how to create a basic web application using the<br />

Rails framework with the <strong>IBM</strong>_DB Adapter. The sample program is a simple<br />

telephone directory application for a user to list, add, update, and delete phone<br />

entries.<br />

Rails can be used to generate the Data Definition Language (DDL) for the<br />

database objects. We show how to create tables with Ruby on Rails.<br />

Chapter 11. Working with Ruby on Rails 391


11.5.1 Creating the Rails application<br />

Use the rails command to create the Rails application. We create our<br />

application sample in the C:\RailsProjects directory.<br />

Example 11-32 shows how to create a rails application and the rails command<br />

output of our application.<br />

Example 11-32 Creating a Rails application<br />

C:\RailsProjects>rails sample<br />

create<br />

create app/controllers<br />

create app/helpers<br />

create app/models<br />

create app/views/layouts<br />

create config/environments<br />

create config/initializers<br />

...<br />

11.5.2 Modifying the database configuration file<br />

Update the database.yml database configuration file with the database<br />

connectivity details.<br />

Example 11-33 shows the configuration file for our development database. The<br />

name of the adapter, ibm_db, correspond to the Ruby Adapter for <strong>IBM</strong> Data<br />

Servers.<br />

Example 11-33 The database.yml file<br />

development:<br />

adapter: ibm_db<br />

database: ruby<br />

username: informix<br />

password: Ifmx4you<br />

host: kefka.lenexa.ibm.com<br />

port: 9089<br />

# Warning: The database defined as "test" will be erased and<br />

# re-generated from your development database when you run "rake".<br />

# Do not set this db to the same as development or production.<br />

test:<br />

production:<br />

392 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


11.5.3 Creating model, control, and view<br />

Ruby on Rails worked on a Model, Control, View architecture. You can create<br />

model, control, and view components in stages. Here, we show a quick way of<br />

using the scaffold command to have Rails create the complete application,<br />

including all the directories and necessary files.<br />

The telephone table of our application use strings for first name, last name, and<br />

phone number. This table layout forms the model for our application. We specify<br />

this model right on the scaffold command as shown in Example 11-34.<br />

We invoke the command from the root directory of our project with the ruby<br />

script\generate script. The syntax for the scaffold options is:<br />

scaffold .. <br />

The output shows that Rails creates the necessary models, views and<br />

controllers. This command also generates the script to create the tables that are<br />

necessary to associate with the model.<br />

Example 11-34 Creating a scaffold<br />

C:\RailsProjects\sample>ruby script\generate scaffold phonedir<br />

first_name:string last_name:string phone:string<br />

exists app/models/<br />

exists app/controllers/<br />

exists app/helpers/<br />

create app/views/phonedirs<br />

exists app/views/layouts/<br />

exists test/functional/<br />

exists test/unit/<br />

create test/unit/helpers/<br />

exists public/stylesheets/<br />

create app/views/phonedirs/index.html.erb<br />

...<br />

dependency model<br />

exists app/models/<br />

exists test/unit/<br />

exists test/fixtures/<br />

create app/models/phonedir.rb<br />

create test/unit/phonedir_test.rb<br />

create test/fixtures/phonedirs.yml<br />

create db/migrate<br />

create db/migrate/20100704234009_create_phonedirs.rb<br />

Chapter 11. Working with Ruby on Rails 393


11.5.4 Migrating the model<br />

Ruby on Rails calls the creation of the database objects backing the model as<br />

migration. The scaffold command created a migrate script for creating the table<br />

attached to the model.<br />

Example 11-35 shows the db/migrate/20100704234009_create_phonedirs.rb<br />

migration file that is created by the scaffold command. This script has both<br />

create and drop sections, which means that you can roll back any migration. We<br />

created a model by the name phonedir. Ruby on Rails then created the table<br />

phonedirs, which is a plural form of the model name, which is the Ruby on Rails<br />

naming convention.<br />

Example 11-35 The phonedir migration file<br />

class CreatePhonedirs < ActiveRecord::Migration<br />

def self.up<br />

create_table :phonedirs do |t|<br />

t.string :first_name<br />

t.string :last_name<br />

t.string :phone<br />

t.timestamps<br />

end<br />

end<br />

def self.down<br />

drop_table :phonedirs<br />

end<br />

end<br />

Use the rake utility to migrate the file and create table in the database. The rake<br />

utility is a Ruby build script with capabilities similar to the make utility. You can use<br />

the rake utility to generate the database schema using a migration file.<br />

Example 11-36 shows how to run the rake script to create the model in the<br />

database.<br />

Example 11-36 Creating model<br />

C:\RailsProjects\sample>rake db:migrate<br />

(in C:/RailsProjects/sample)<br />

== CreatePhonedirs: migrating ================================================<br />

-- create_table(:phonedirs)<br />

-> 0.0781s<br />

== CreatePhonedirs: migrated (0.0781s) =======================================<br />

394 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Example 11-37 uses the <strong>Informix</strong> dbschema utility to export the table schema to<br />

check the tables created Ruby on Rails migration. We started with an empty<br />

database and the output shows that two tables were created:<br />

► schema_migrations<br />

Ruby on Rails uses this table to keep track of the various version of the table,<br />

which allows you to roll back to the previous version.<br />

► phonedirs<br />

In this application table, Ruby added a few columns that we did not specify:<br />

– id: This serial column is for the primary key required by Ruby on Rails.<br />

– created_at and updated_at: Ruby on Rails uses these optionally.<br />

Example 11-37 The dbschema on database Ruby output<br />

% dbschema -d ruby<br />

DBSCHEMA Schema Utility INFORMIX-SQL Version 11.50.FC7<br />

grant dba to "informix";<br />

...<br />

create table "informix".schema_migrations<br />

(<br />

version varchar(255) not null<br />

);<br />

...<br />

create table "informix".phonedirs<br />

(<br />

id serial not null ,<br />

first_name varchar(255),<br />

last_name varchar(255),<br />

phone varchar(255),<br />

created_at datetime year to fraction(5),<br />

updated_at datetime year to fraction(5),<br />

primary key (id)<br />

);<br />

...<br />

create unique index "informix".unique_schema_migrations on "informix"<br />

.schema_migrations (version) using btree ;<br />

Chapter 11. Working with Ruby on Rails 395


11.5.5 Starting the Rails web server<br />

Example 11-38 shows how to start the Rails WEBrick server from the root<br />

directory. The http port number is 3000.<br />

Example 11-38 Starting the WEBrick server<br />

C:\RailsProjects\sample>ruby script\server<br />

=> Booting WEBrick<br />

=> Rails 2.3.8 application starting on http://0.0.0.0:3000<br />

=> Call with -d to detach<br />

=> Ctrl-C to shutdown server<br />

[2010-07-04 17:25:22] INFO WEBrick 1.3.1<br />

[2010-07-04 17:25:22] INFO ruby 1.9.1 (2010-01-10) [i386-mingw32]<br />

[2010-07-04 17:25:22] INFO WEBrick::HTTPServer#start: pid=292 port=3000<br />

11.5.6 Checking the application from website<br />

You can start the web application using the local web server address:<br />

http://localhost:3000/phonedirs<br />

Figure 11-4 shows the initial screen that our application opened with<br />

http://localhost:3000/phonedirs.<br />

Figure 11-4 Initial screen of the application<br />

396 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


We add one phone entry to our directory as shown in Figure 11-5.<br />

Figure 11-5 Creating a new phone listing<br />

Figure 11-6 shows that a phone entry is added.<br />

Figure 11-6 Listing phonedir after the new entry<br />

For more information regarding the development with Ruby and Ruby on Rails,<br />

refer to:<br />

http://rubyonrails.org/documentation<br />

Chapter 11. Working with Ruby on Rails 397


398 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Chapter 12. <strong>Informix</strong> 4GL Web Services<br />

In this chapter, we introduce the new Web Services feature of <strong>IBM</strong> <strong>Informix</strong> 4GL.<br />

This chapter provides an overview and configuring and building Web Services<br />

using <strong>Informix</strong> 4GL.<br />

In this chapter, we discuss the following topics:<br />

► Basic concepts<br />

► Setup and configuration<br />

► <strong>Informix</strong> 4GL Web Services tools<br />

► Developing a web service with I4GL<br />

► Consuming a web service with I4GL<br />

► Troubleshooting<br />

12<br />

© Copyright <strong>IBM</strong> Corp. 2010. All rights reserved. 399


12.1 Basic concepts<br />

In this section, we provide an introduction of the products and technologies that<br />

we discuss in this chapter.<br />

12.1.1 <strong>IBM</strong> <strong>Informix</strong> 4GL<br />

<strong>Informix</strong> 4GL is a programming language developed by <strong>IBM</strong> for interacting with<br />

<strong>Informix</strong> database servers. It provides a rich environment for easy development<br />

of relational database applications. <strong>Informix</strong> 4GL provides all the component<br />

needed to develop character based applications using an <strong>Informix</strong> database, for<br />

example, project management, reports, debugger, and so on.<br />

<strong>Informix</strong> 4GL supports compilers that can convert the I4GL applications to C<br />

language or to generate platform-independent pseudo code that can be executed<br />

using a I4GL runner.<br />

For more information about <strong>Informix</strong> 4GL, refer to the 4GL Reference Manual at:<br />

http://publib.boulder.ibm.com/infocenter/ifxhelp/v0/index.jsp?topic=/com.ibm.to<br />

ols.doc/4gl.html<br />

12.1.2 Service-oriented architecture and Web Services<br />

Service-oriented architecture (SOA) is an architectural style that provides<br />

methods for systems development and integration, allowing applications<br />

developed with different technologies or programing languages to exchange data<br />

with one another.<br />

This exchange of data is accomplished through the use of Web Services. Web<br />

services are saleable functions that can be accessed independent of platforms<br />

and programming languages. These functions take a set of inputs and return a<br />

set of outputs to accomplish a specific task.<br />

Refer to the Service Oriented Architecture — SOA portal for more information:<br />

http://www.ibm.com/software/solutions/soa/<br />

12.1.3 Web Services development<br />

You can create a web service with any web-aware technology. Java is the most<br />

common language that is used for Web Services development. However, you can<br />

create Web Services with other language and technologies, such as C or .NET<br />

400 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


<strong>IBM</strong> provides the following options for SOA development:<br />

► <strong>IBM</strong> SOA Sandbox<br />

► <strong>IBM</strong> Rational® Application Developer<br />

► eKit: Enterprise Architect for SOA<br />

You can develop a web service that requires the use of an <strong>IBM</strong> <strong>Informix</strong> database<br />

using the following languages:<br />

► Java, using any of the JDBC drivers for an <strong>Informix</strong> database<br />

► Any .NET language, using any of the <strong>Informix</strong> .NET providers available<br />

► <strong>IBM</strong> <strong>Informix</strong> 4GL<br />

12.1.4 <strong>Informix</strong> 4GL and Web Services<br />

12.1.5 Components<br />

Starting form version 7.50 of <strong>IBM</strong> <strong>Informix</strong>, 4GL developers can manage and<br />

create Web Services using the 4GL language.<br />

One of the key benefits of using <strong>Informix</strong> 4GL is the easy interaction with the<br />

<strong>Informix</strong> database server. The use of SQL statements to access database<br />

objects does not require any specific code as with other programming languages,<br />

because SQL is embedded in the I4GL language.<br />

The ability to create Web Services directly with I4GL allows the reuse of existing<br />

code. Existing solutions that are developed with I4GL can be converted to web<br />

solutions without much effort.<br />

With <strong>Informix</strong> 4GL, you can publish existing I4GL functions as Web Services and<br />

use existubg Web Services from any I4GL application.<br />

<strong>Informix</strong> 4GL uses the Axis2 web service wrapper API to implement the interface<br />

that is required to communicate between the web server and the <strong>Informix</strong> 4GL<br />

libraries.<br />

A typical I4GL web service solution includes the following components:<br />

► Apache AXIS2C server<br />

► Web service<br />

► <strong>Informix</strong> 4GL<br />

► <strong>Informix</strong> Database Server<br />

Chapter 12. <strong>Informix</strong> 4GL Web Services 401


A web service can perform the following operations:<br />

► Create is the process of creating the web service and publishing it to make it<br />

available to consumers.<br />

The term used in <strong>Informix</strong> 4GL for this task is Publish.<br />

► Consume is the process of using the web service, providing input parameters,<br />

and retrieving the result as output parameters for the function.<br />

The term used in <strong>Informix</strong> 4GL for this task is Subscribe.<br />

Axis2 C functions are used for both operations as the wrapper code between the<br />

web service and <strong>Informix</strong> 4GL.<br />

12.2 Setup and configuration<br />

In this section, we discuss the setup and configuration needed to develop Web<br />

Services with <strong>Informix</strong> 4GL.<br />

12.2.1 Prerequisites and supported platforms<br />

The following prerequisites are required to use Web Services with <strong>Informix</strong> 4GL:<br />

► Apache Axis2/C version 1.5.1 (bundled with <strong>Informix</strong> 4GL)<br />

► Apache Axis2/Java version 1.3.1 (bundled with <strong>Informix</strong> 4GL)<br />

► <strong>IBM</strong> <strong>Informix</strong> database server version 10 or later<br />

► Java Runtime Environment (JRE) 1.5 or later<br />

► Perl 5.8.8<br />

<strong>IBM</strong> <strong>Informix</strong> 4GL 7.50 is supported in the following platforms:<br />

► HP-IA 11.23 and 11.31<br />

► AIX 5.3 and 6.1<br />

► Solaris 5.9 or 5.10<br />

► Red Hat Enterprise Linux 4 and 5<br />

► SUSE Linux Enterprise Server 10<br />

Note: The Web Services feature was added to <strong>Informix</strong> 4GL version 7.50.xC1<br />

but was available only for Linux platforms. Since version 7.50.xC3, all the<br />

platforms listed previously are supported.<br />

402 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


12.2.2 Environment<br />

The utilities for using Web Services with <strong>Informix</strong> 4GL are installed in the same<br />

directory as <strong>Informix</strong> 4GL.<br />

We do not discuss how to install and set up <strong>Informix</strong> 4GL in this book. For more<br />

information, refer to:<br />

http://publib.boulder.ibm.com/infocenter/idshelp/v115/topic/com.ibm.4gl_install<br />

.doc/fgl_ing_010.htm<br />

To use any of the I4GL Web Services tools, you must set the variables listed in<br />

Table 12-1 in the development environment. These variables define the location<br />

of those 4GL, Java, and Axis2 resources that you need for application<br />

development and deployment.<br />

Table 12-1 Environment variables<br />

Variable Description<br />

AXIS2C_HOME Specifies the Axis2 installation directory<br />

CLASSPATH Path to the required Java classes<br />

DBPATH Path for support files. Must be $INFORMIXDIR/etc<br />

INFORMIXDIR Directory where the 4GL files are installed<br />

INFORMIXSERVER Default database server<br />

INFORMIXSQLHOSTS Optional: Specifies the location of the sqlhosts<br />

file, which contains database connectivity<br />

information<br />

JAVA_HOME Must be set to point to JRE 1.5 or later<br />

Load Library Path<br />

for example: LD_LIBRARY_PATH<br />

Specifies which directories to search for client or<br />

shared <strong>IBM</strong> <strong>Informix</strong> general libraries<br />

PATH Specifies which directories to search for<br />

executable programs. Must include the following<br />

path:<br />

$INFORMIXDIR/bin and $JAVA_HOME/bin<br />

SOA_ERR_LOG Optional: Specifies the directory where the log file<br />

(w4glerr.log) is created, defaults to /tmp<br />

PROGRAM_DESIGN_DBS Optional: Database used for storing web service<br />

definitions, defaults to syspgm4gl<br />

Chapter 12. <strong>Informix</strong> 4GL Web Services 403


Example 12-1 shows a typical shell script to set up these variables.<br />

Example 12-1 The setup.ksh script<br />

AXIS2C_HOME=$INFORMIXDIR/AXIS2C<br />

AXJDIR=$INFORMIXDIR/AXIS2C/AXIS2JARS<br />

CLASSPATH=$AXJDIR/wsdl4j-1.6.2.jar:$AXJDIR/backport-util-concurrent-2.2.jar:$AX<br />

JDIR/XmlSchema.jar:$AXJDIR/XmlSchema-1.3.1.jar:$AXJDIR/xbean-2.2.0.jar:$AXJDIR/<br />

axiom-dom-1.3.1.jar:$AXJDIR/axiom-impl-1.3.1.jar:$AXJDIR/axiom-api-1.3.1.jar:$A<br />

XJDIR/neethi-1.3.1.jar:$AXJDIR/axis.jar:$AXJDIR/commons-logging.jar:$AXJDIR/wsd<br />

l2ws.jar:$AXJDIR/commons-discovery.jar:$AXJDIR/jaxrpc.jar:$AXJDIR/saaj.jar:$AXJ<br />

DIR/wsdl4j.jar:$AXJDIR/axis2-java2wsdl-1.3.1.jar:$AXJDIR/axis2-codegen-1.3.1.ja<br />

r:$AXJDIR/axis2-kernel-1.3.1.jar<br />

DBPATH=$INFORMIXDIR/etc<br />

LD_LIBRARY_PATH=$INFORMIXDIR/AXIS2C/lib:$LD_LIBRARY_PATH<br />

export AXIS2C_HOME AXJDIR CLASSPATH DBPATH LD_LIBRARY_PATH<br />

Some of the I4GL Web Services utilities, such as w4gl, keep design and<br />

configuration information in a database on the <strong>Informix</strong> database server. The<br />

default name for this database is syspgm4gl. The database is created the first<br />

time the w4gl tool is invoked. You can specify your own database name using the<br />

environment variable PROGRAM_DESIGN_DBS.<br />

12.3 <strong>Informix</strong> 4GL Web Services tools<br />

This section describes the tools that are available within <strong>Informix</strong> 4GL to publish,<br />

deploy, package, and subscribe Web Services.<br />

12.3.1 The w4glc Web Services compiler<br />

The w4glc Web Services compiler is a script based on Perl. The w4glc compiler<br />

performs all the required task to use Web Services within 4GL, from the creation<br />

process to deploying and packaging.<br />

The w4glc script is used by other I4GL utilities in a non-interactive way. Any error<br />

or failure that is generated during the execution of the script is written to the<br />

SOA_ERR_LOG log file.<br />

To execute the w4glc utility, use the following syntax:<br />

w4glc {-option} <br />

The w4glc utility does not keep any information in the database. It uses only<br />

configuration files. The configuration file is a text file that specifies the details<br />

about the I4GL function that is created as a web service. It contains information<br />

404 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


such as the location of the 4GL source files, input and output parameters, and<br />

database connectivity information.<br />

Table 12-2 lists the parameters that are available with the w4glc utility.<br />

Table 12-2 The w4glc utility parameter list<br />

Option Description<br />

check Reads the configuration file and performs basic checks, such<br />

as ensuring that the identified source files exist<br />

compile Compiles generated intermediate code<br />

deploy Deploys the web service on the AXIS2C server<br />

force Overwrites the existing service with identical name<br />

generate Generates the intermediate code for publish/subscribe<br />

help Provides basic help information<br />

keep Retains intermediate source files for troubleshooting<br />

package Bundles a web service for production deployment<br />

silent Generates code without on-screen display<br />

version Prints the version number<br />

Example 12-2 shows the output for the generate option.<br />

Example 12-2 The w4glc utility generate output<br />

informix@irk:/work$ w4glc -generate ./ws_zipcode_irk.4cf<br />

Begin environment check ...<br />

Environment check is completed.<br />

Generating code. Please wait ...<br />

Generating Wrapper code ....<br />

The wrapper file is /tmp/w4gl_informix/zipcode_details_wrap.c<br />

Generating WSDL ....<br />

Generating headers ....<br />

Generating skeletal code ....<br />

Code generation completed.<br />

Removing /tmp/w4gl_informix/zipcode_details_wrap.c ...<br />

Removing /tmp/w4gl_informix/zipcode_details.wsdl ...<br />

Removing /tmp/w4gl_informix/axis2_skel_ws_zipcode.h ...<br />

Removing /tmp/w4gl_informix/axis2_svc_skel_ws_zipcode.c ...<br />

Removing /tmp/w4gl_informix/services.xml ...<br />

Removing /tmp/w4gl_informix/axis2_skel_ws_zipcode.c ...<br />

informix@irk:/work$<br />

Chapter 12. <strong>Informix</strong> 4GL Web Services 405


12.3.2 The w4gl utility<br />

For additional information about the I4GL Web Services compiler, refer to:<br />

http://publib.boulder.ibm.com/infocenter/idshelp/v115/topic/com.ibm.4gl_admin.d<br />

oc/fgl_wsg_500.htm<br />

The character-based interface w4gl utility is the main tool when using Web<br />

Services with <strong>Informix</strong> 4GL. It allows you to perform the same task as the<br />

command line tool, w4glc, but it also manages the data within the program<br />

design database, syspgm4gl.<br />

The design database contains the following information about the Web Services<br />

environment:<br />

► Information for the host system, such as the host name or temporary<br />

directories<br />

► Location for the Axis2 web server<br />

► Details for the <strong>Informix</strong> servers to which the Web Services connects<br />

► Definition for Web Services, such as function names or parameters types<br />

The web service definition that is specified through the utility is saved in<br />

database tables and is available for future reuse and modification, thus reducing<br />

development effort.<br />

The w4gl utility uses the same I4GL character-based interface as other 4GL tools<br />

to accomplish the creation and consumption of Web Services.<br />

Example 12-3 shows the main menu of the w4gl utility.<br />

Example 12-3 The w4gl utility main menu<br />

+------------------------------------------------------------------------------+<br />

|W4GL: Publish Subscribe Host name App server Exit |<br />

|Create and Deploy web services from I4GL functions. |<br />

|--------------------------------[ irkpgm4gl ]-------------------[Help: CTRL-W]|<br />

| |<br />

| |<br />

| |<br />

| |<br />

| |<br />

| |<br />

| |<br />

| |<br />

| |<br />

| |<br />

| |<br />

| |<br />

406 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


| |<br />

| |<br />

| |<br />

| |<br />

| |<br />

| |<br />

+------------------------------------------------------------------------------+<br />

The w4gl utility offers the following options:<br />

► Use the Publish option to create a new web service.<br />

► Use the Subscribe option to consume a web service.<br />

► Use the Host name option to managed the host information that is stored in<br />

the design database.<br />

► Use the Application server option to managed the Axis2 information that is<br />

stored in the design database.<br />

For a detailed description of all the w4gl utility menu options, refer to the 4GL<br />

Web Services Administration Guide, which is available at:<br />

http://publib.boulder.ibm.com/infocenter/idshelp/v115/index.jsp?topic=/com.ibm.<br />

4gl_admin.doc/fgl_wsg_006.htm<br />

12.3.3 Web Services Description Language Parser (wsdl_parser)<br />

Web Services Description Language (WSDL) is an XML-based language for<br />

describing network services. You can use WSDL to describe all the functions and<br />

parameters for a web service.<br />

When you subscribe a web service, the wsdl_parser tool parses the WSDL file to<br />

retrieve all the information that is required to define a web service.<br />

The syntax to invoke the wsdl_parser tool is:<br />

wsdl_parser sid wsdl_path ws_func i4gl_func target_dir target_file<br />

Table 12-3 describes each parameter. All of the parameters are required for the<br />

tool to work correctly.<br />

Table 12-3 The wsdl_parser tool parameters list<br />

Parameter Description<br />

sid An integer that uniquely identifies the subscriber<br />

wsdl_path Location of the file that describes the complete description of the<br />

web service; can be an online or a local copy of the WSDL file<br />

Chapter 12. <strong>Informix</strong> 4GL Web Services 407


Parameter Description<br />

ws_func Function to consume within the designated web service<br />

i4gl_func Name for the wrapper function to be used by the I4GL program<br />

target_dir The path where files are stored while the web service is being<br />

consumed<br />

target_file The file name that contains the generated subscriber client code<br />

Note: The sid parameter is used only when you invoke the wsdl_parser from<br />

the w4gl tool. This parameter is ignored if you use wsdl_parser from the<br />

command line.<br />

Example 12-4 shows the wsdl_parser tool used to generate the configuration file<br />

for a ws_zipcode web service. This example passes the WSDL definition directly<br />

from a web server as the following wsdl_path parameter:<br />

http://irk:9876/axis/services/ws_zipcode?wsdl<br />

Example 12-4 The wsdl_parser tool output<br />

informix@irk:/work$ wsdl_parser 0 http://irk:9876/axis/services/ws_zipcode?wsdl<br />

zipcode_details zipcode4gl `pwd`/publish zipcode4gl.c<br />

informix@irk:/work$ ls publish<br />

local.wsdl zipcode4gl.c_zipcode4gl.4cf<br />

informix@irk:/work$<br />

408 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


12.3.4 I4GL Web Services process<br />

Figure 12-1 illustrates how the I4GL Web Services tools work together.<br />

Figure 12-1 I4GL Web Services tools<br />

12.4 Developing a web service with I4GL<br />

In this section, we demonstrate the steps that are required to create a web<br />

service using <strong>IBM</strong> <strong>Informix</strong> 4GL. Publish and subscribe are two operations to<br />

perform with a web service:<br />

► Publish<br />

The tasks required to create a new web service with the w4gl utility are:<br />

a. Add the Host name and an Axis2 server information.<br />

b. Add the web service definition details.<br />

c. Generate the web service configuration file for publishing.<br />

d. Deploy a web service by registering the service in the Axis2 web server.<br />

e. Package a web service as a single file (a .tar file) that is ready for the<br />

production server.<br />

► Subscribe<br />

The tasks needed to consume a web service are with the w4gl tool are:<br />

a. Add details for the web service to consume.<br />

b. Compile the Web Services wrapper code that generates the configuration<br />

file for subscription.<br />

Chapter 12. <strong>Informix</strong> 4GL Web Services 409


In the remaining sections, we describe how to publish a simple I4GL function as<br />

a web service and show that the function can be used from other languages such<br />

as Java.<br />

12.4.1 Example I4GL function<br />

We use a basic I4GL function, state_name(), for the web service. This function<br />

connects to the database server and retrieves the name for a specific state code.<br />

Example 12-5 shows the 4GL code state_name() saved in the state_name.4gl<br />

file. This function queries the state table from the stores_demo database. The<br />

state_name() function takes one input parameter state code of type CHAR(2)<br />

and returns the state name that has CHAR(15) data type.<br />

Example 12-5 The state_name.4gl file<br />

FUNCTION state_name(code)<br />

DEFINE state_rec RECORD<br />

code CHAR(2),<br />

sname CHAR(15)<br />

END RECORD,<br />

code CHAR(2),<br />

sel_stmt CHAR(100);<br />

LET sel_stmt= "SELECT code, sname FROM state WHERE code = ?";<br />

PREPARE st_id FROM sel_stmt;<br />

DECLARE cur_id CURSOR FOR st_id;<br />

OPEN cur_id USING code;<br />

FETCH cur_id INTO state_rec.*;<br />

CLOSE cur_id;<br />

FREE cur_id;<br />

FREE st_id;<br />

RETURN state_rec.sname<br />

END FUNCTION<br />

To ensure that the 4GL code is correct, we compile the function with the I4GL<br />

compiler, c4gl, as shown in Example 12-6.<br />

Example 12-6 Compile 4GL function<br />

informix@irk:/work$ c4gl -c state_name.4gl<br />

informix@irk:/work$<br />

410 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


12.4.2 Host and application details<br />

Before adding any of the details for the web service, we must provide details<br />

about the system where the web service will run and the Axis2 server that is<br />

used. To complete these tasks, we use the “Host name” and “Application server”<br />

menus from the w4gl utility.<br />

Example 12-7 shows the HOST INFORMATION form with the host name irk and<br />

the /tmp/w4gl_informix temporary directory.<br />

Example 12-7 Host name menu<br />

+------------------------------------------------------------------------------+<br />

|HOST NAME: Query Next Previous Add Modify Remove Exit |<br />

|See the existing host name details. |<br />

|[1 of 1]------------------------[ irkpgm4gl ]-------------------[Help: CTRL-W]|<br />

| |<br />

| HOST INFORMATION |<br />

| |<br />

| Machine ID [ 1] |<br />

| Host Name [irk ] |<br />

| Temporary Directory [/tmp/w4gl_informix ] |<br />

| [ ] |<br />

| |<br />

| |<br />

| |<br />

| |<br />

| |<br />

| |<br />

| |<br />

| |<br />

| |<br />

| |<br />

| |<br />

+------------------------------------------------------------------------------+<br />

Host information includes the following fields:<br />

► Machine ID is an automatic identifier number.<br />

► Host Name is the system name where the Axis2 server is installed.<br />

► Temporary Directory is the directory that is used by the w4glc utility for<br />

creating temporary files.<br />

After you define the host information, add the information for the Axis2<br />

application server using the APP SERVER menu.<br />

Chapter 12. <strong>Informix</strong> 4GL Web Services 411


Example 12-8 shows the APP SERVER form.<br />

Example 12-8 Application menu<br />

+------------------------------------------------------------------------------+<br />

|APP SERVER: Query Next Previous Add Modify Remove Exit |<br />

|Go to the next app server |<br />

|[1 of 1]------------------------[ irkpgm4gl ]-------------------[Help: CTRL-W]|<br />

| |<br />

| APP SERVER INFORMATION |<br />

| Server ID [ 1] |<br />

| Server Name [axis ] |<br />

| Host Name [irk ] |<br />

| Port Number [ 9876] |<br />

| ENVIRONMENT VARIABLES |<br />

| INFORMIXDIR [/usr3/4gl750 ] |<br />

| INFORMIXSQLHOSTS [/usr3/sqlhosts ] |<br />

| CLIENT_LOCALE [en_us.utf8 ] |<br />

| DBDATE [Y4MD- ] |<br />

| Notes [ ] |<br />

| [ ] |<br />

| [ ] |<br />

| [ ] |<br />

| |<br />

| |<br />

| |<br />

+------------------------------------------------------------------------------+<br />

An application server is identified by the following fields:<br />

► Server ID is an automatic identifier number.<br />

► Server Name is the name of the Axis2 server.<br />

► Host Name is the system name where the Axis2 server runs.<br />

► Port Number is the port used for incoming connections to the web service.<br />

The APP SERVER option is also used to stored specific environment information<br />

for the application server. This information is required because the Axis2 server<br />

binary loads the I4GL libraries that might need additional resource files located in<br />

the $INFORMIXDIR directory.<br />

12.4.3 Definition of the web service<br />

In this section, we demonstrate how to define a web service from the w4gl utility.<br />

To define a web service:<br />

1. Add the <strong>IBM</strong> <strong>Informix</strong> database that the web service will use.<br />

2. Add the definition for the web service, such as the name of the service or the<br />

name of the 4GL function.<br />

412 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


3. Add specific details for the web service such as input and output variables.<br />

4. Add the location of the 4GL source code file.<br />

Add <strong>Informix</strong> database details<br />

You add <strong>Informix</strong> database details using the Database menu from the w4gl utility.<br />

Example 12-9 shows the DATABASE INFORMATION form with details of the<br />

database that we used in our example.<br />

Example 12-9 Database option<br />

+------------------------------------------------------------------------------+<br />

|DATABASE: Query Next Previous Add Modify Remove Exit |<br />

|Go to the previous database record. |<br />

|[1 of 1]------------------------[ irkpgm4gl ]-------------------[Help: CTRL-W]|<br />

| |<br />

| DATABASE INFORMATION |<br />

| |<br />

| Database ID [ 1] |<br />

| Database Name [stores7 ] |<br />

| Database Server [irk1150 ] |<br />

| IDS Version [11.50 ] |<br />

| DB_LOCALE [en_US.819 ] |<br />

| Notes [ ] |<br />

| [ ] |<br />

| [ ] |<br />

| [ ] |<br />

| |<br />

| |<br />

| |<br />

| |<br />

| |<br />

| |<br />

+------------------------------------------------------------------------------+<br />

This menu option uses the following fields:<br />

► Database ID is an automatic number that identifies a database definition.<br />

► Database name defines the database name to which the web server connects.<br />

► IDS Version is the <strong>Informix</strong> database server version number.<br />

► DB_LOCALE is the locale of the database. The default DB_LOCALE is en_US.819.<br />

Chapter 12. <strong>Informix</strong> 4GL Web Services 413


Add details about the web service<br />

You can add details about the web service using the Add option in the web<br />

service menu. Example 12-10 shows this option.<br />

Example 12-10 Add the web service menu<br />

+------------------------------------------------------------------------------+<br />

|WEB SERVICE: Query Next Previous Add Modify Remove Install ... |<br />

|Specify a new service record. |<br />

|--------------------------------[ irkpgm4gl ]-------------------[Help: CTRL-W]|<br />

| |<br />

| |<br />

| |<br />

First, you add the web service name and the function name using the Detail<br />

menu option. Example 12-11 shows this input form with the details of our web<br />

service.<br />

Example 12-11 Web service details<br />

+------------------------------------------------------------------------------+<br />

|ADD: Detail Variable File Exit |<br />

|Specify the web service parameters. |<br />

|--------------------------------[ irkpgm4gl ]-------------------[Help: CTRL-W]|<br />

| |<br />

| Webservice ID [ 4] |<br />

| Webservice Name [ws_statename ] |<br />

| Function Name [state_name ] |<br />

| Notes [Returns the state name for a given code ] |<br />

| [ ] |<br />

| [ ] |<br />

| [ ] |<br />

| |<br />

| |<br />

| |<br />

| |<br />

| |<br />

| |<br />

| |<br />

| |<br />

| |<br />

| |<br />

+------------------------------------------------------------------------------+<br />

The following input details on this form describes a web service:<br />

► Webservice ID is an automatically generated identifier for the web service.<br />

► Webservice Name is the name of the web service.<br />

► Function Name is the he name of the 4GL function.<br />

414 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Input and output variables<br />

Next, you add the input and output variables that the web service uses with the<br />

Variable menu option. Example 12-12 shows this menu option. Our function<br />

takes an CHAR(2) input parameter and returns a CHAR(15) value.<br />

Example 12-12 Web service VARIABLE option<br />

+------------------------------------------------------------------------------+<br />

|VARIABLE: Input Output Exit |<br />

|Exit the Variable menu. |<br />

|--------------------------------[ irkpgm4gl ]-------------------[Help: CTRL-W]|<br />

| |<br />

| [ 1] Input parameter - Variable name Data type |<br />

| |<br />

| [ 1][code ][CHAR(2) ] |<br />

| [ ][ ][ ] |<br />

| [ ][ ][ ] |<br />

| [ ][ ][ ] |<br />

| [ ][ ][ ] |<br />

| |<br />

| [ 1] Output parameter - Variable name Data type |<br />

| |<br />

| [ 1][sname ][CHAR(15) ] |<br />

| [ ][ ][ ] |<br />

| [ ][ ][ ] |<br />

| [ ][ ][ ] |<br />

| [ ][ ][ ] |<br />

| |<br />

| |<br />

+------------------------------------------------------------------------------+<br />

Chapter 12. <strong>Informix</strong> 4GL Web Services 415


Source file information<br />

Finally, you define a web service. We stored the location of the I4GL source file<br />

that contains our function using the File menu option. Example 12-13 shows the<br />

fields used by the File option.<br />

Example 12-13 Web service File option<br />

+------------------------------------------------------------------------------+<br />

|ADD: Detail Variable File Exit |<br />

|Exit the web services Add menu. |<br />

|--------------------------------[ irkpgm4gl ]-------------------[Help: CTRL-W]|<br />

| |<br />

| Service Name [ws_state_name ] |<br />

| Function Name [state_name ] |<br />

| |<br />

| File Number [ 1] |<br />

| Directory [/work ] |<br />

| File Name [state_name.4gl ] |<br />

| |<br />

| File Number [ ] |<br />

| Directory [ ] |<br />

| File Name [ ] |<br />

| |<br />

| File Number [ ] |<br />

| Directory [ ] |<br />

| File Name [ ] |<br />

| |<br />

| |<br />

| |<br />

+------------------------------------------------------------------------------+<br />

An I4GL function can require more than one I4Gl file. You must supply all the<br />

required file names and their directories. We supplied the 4GL file<br />

state_name.4gl that contains the state_name() function.<br />

12.4.4 Generate the configuration file<br />

With the details of the web service stored in the design database, you can then<br />

generate the configuration file (.4cf) for a Publish operation. The Generate<br />

option is inside the Install menu option.<br />

416 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Example 12-14 shows the Generate form. You must complete every field in the<br />

form. If you stored the definition for these items in the design database, you can<br />

retrieve them using the Ctrl+B key shortcut.<br />

Example 12-14 Generate form<br />

+------------------------------------------------------------------------------+<br />

|INSTALL: Generate Deploy Package Exit |<br />

|Generate the configuration file for a web service. |<br />

|[1 of 1]------------------------[ irkpgm4gl ]-------------------[Help: CTRL-W]|<br />

| |<br />

| +-----------------------------------------------------+ |<br />

| |DATABASES: Query Previous query Exit | |<br />

| Service ID [ 4] M|Make a new selection | |<br />

| |-----------------------------------------------------| |<br />

| Service Name [ws_s| DATABASE INFORMATION | |<br />

| Host Name [irk | | |<br />

| Temp Directory [/tmp|ID Database Name | |<br />

| [ |[ 1] [stores7 ]| |<br />

| App-Server Name [axis|[ ] [ ]| |<br />

| Port Number [ 98|[ ] [ ]| |<br />

| Database Name [ |[ ] [ ]| |<br />

| Database Server [ |[ ] [ ]| |<br />

| |[ ] [ ]| |<br />

| | | |<br />

| |Arrow key - Press Esc to Accept or press Ctrl+C to Ca| |<br />

| +-----------------------------------------------------+ |<br />

| |<br />

+------------------------------------------------------------------------------+<br />

After you enter all the information, use the Generate option to create the<br />

configuration file. Example 12-15 shows the output of the Generate option.<br />

Example 12-15 Generate option<br />

+------------------------------------------------------------------------------+<br />

|INSTALL: Generate Deploy Package Exit |<br />

|Generate the configuration file for a web service. |<br />

|[1 of 1]------------------------[ irkpgm4gl ]-------------------[Help: CTRL-W]|<br />

| |<br />

| GENERATE CONFIGURATION |<br />

| |<br />

| Service ID [ 4] Machine ID [ 1] Server ID [ 1] Database ID [ 1] |<br />

| |<br />

| Service Name [ws_state_name ] |<br />

| Host Name [irk ] |<br />

| Temp Directory [/tmp/w4gl_informix ] |<br />

| [ ] |<br />

| App-Server Name [axis ] |<br />

| Port Number [ 9876] |<br />

| Database Name [stores7 ] |<br />

| Database Server [irk1150 ] |<br />

| |<br />

| Generated configuration file ws_state_name_irk.4cf |<br />

+------------------------------------------------------------------------------+<br />

Chapter 12. <strong>Informix</strong> 4GL Web Services 417


The Generate operation creates the configuration file that is required for<br />

publishing a web service. The name of the file is constructed using the web<br />

service name, the host name, and a .4cf extension. In our example, the name of<br />

the file is ws_state_name_irk.4cf.<br />

Example 12-16 shows the configuration file for the ws_state_name web service.<br />

Example 12-16 The ws_state_name_irk.4cf file<br />

[SERVICE]<br />

TYPE = publisher<br />

INFORMIXDIR = /usr3/4gl750uc3<br />

DATABASE = stores7<br />

CLIENT_LOCALE = en_us.utf8<br />

DB_LOCALE = en_US.819<br />

INFORMIXSERVER = irk1150<br />

HOSTNAME = irk<br />

PORTNO = 9876<br />

I4GLVERSION = 7.50.xC3<br />

WSHOME = /usr3/4gl750uc3/AXIS2C<br />

WSVERSION = axis<br />

TMPDIR = /tmp/w4gl_informix<br />

SERVICENAME = ws_state_name<br />

[FUNCTION]<br />

NAME = state_name<br />

[INPUT]<br />

[VARIABLE] NAME = code TYPE = CHAR(2) [END-VARIABLE]<br />

[END-INPUT]<br />

[OUTPUT]<br />

[VARIABLE] NAME = sname TYPE = CHAR(15) [END-VARIABLE]<br />

[END-OUTPUT]<br />

[END-FUNCTION]<br />

[DIRECTORY]<br />

NAME = /work<br />

FILE = state_name.4gl,<br />

[END-DIRECTORY]<br />

[END-SERVICE]<br />

You can use a configuration file (4cf) with the w4glc utility to perform tasks, such<br />

as generate and compile, directly from the command line. Example 12-17 shows<br />

how to perform all the steps that the w4gl deploy options performs using the<br />

w4glc utility.<br />

Example 12-17 Using w4glc<br />

informix@irk:/work$ w4glc -generate -compile -deploy ws_state_name_irk.4cf<br />

Begin environment check ...<br />

Environment check is completed.<br />

Generating code. Please wait ...<br />

418 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Generating Wrapper code ....<br />

The wrapper file is /tmp/w4gl_informix/state_name_wrap.c<br />

Generating WSDL ....<br />

Generating headers ....<br />

Generating skeletal code ....<br />

Code generation completed.<br />

Generating shared object for service ws_state_name ....<br />

Compiling code. Please wait...<br />

Executing: c4gl --shared -o /tmp/w4gl_informix/libws_state_name.so<br />

-I/usr3/4gl750/AXIS2C/include/axis2-1.5.0 -L/usr3/4gl750/AXIS2C/lib<br />

-laxis2_engine -laxutil -laxis2_axiom /tmp/w4gl_informix/state_name_wrap.c<br />

/tmp/w4gl_informix/axis2_skel_ws_state_name.c<br />

/tmp/w4gl_informix/axis2_svc_skel_ws_state_name.c /work/state_name.4gl<br />

/usr3/4gl750/lib/tools/w4glutil.a /usr3/4gl750/lib/tools/lib4gl.a<br />

Compilation done.<br />

Deploying service ws_state_name ...<br />

Deploying the service. Please wait ...<br />

Copying /tmp/w4gl_informix/libws_state_name.so ...<br />

Copying /tmp/w4gl_informix/services.xml ...<br />

Copying /tmp/w4gl_informix/state_name.wsdl ...<br />

Service name: ws_state_name<br />

The wrapper file is /tmp/w4gl_informix/state_name_wrap.c<br />

Generating WSDL ....<br />

Generating headers ....<br />

Generating skeletal code ....<br />

Code generation completed.<br />

Generating shared object for service ws_state_name ....<br />

Compiling code. Please wait...<br />

Executing: c4gl --shared -o /tmp/w4gl_informix/libws_state_name.so<br />

-I/usr3/4gl750/AXIS2C/include/axis2-1.5.0 -L/usr3/4gl750/AXIS2C/lib<br />

-laxis2_engine -laxutil -laxis2_axiom /tmp/w4gl_informix/state_name_wrap.c<br />

/tmp/w4gl_informix/axis2_skel_ws_state_name.c<br />

/tmp/w4gl_informix/axis2_svc_skel_ws_state_name.c /work/state_name.4gl<br />

/usr3/4gl750/lib/tools/w4glutil.a /usr3/4gl750/lib/tools/lib4gl.a<br />

Compilation done.<br />

Deploying service ws_state_name ...<br />

Deploying the service. Please wait ...<br />

Copying /tmp/w4gl_informix/libws_state_name.so ...<br />

Copying /tmp/w4gl_informix/services.xml ...<br />

Copying /tmp/w4gl_informix/state_name.wsdl ...<br />

Service name: ws_state_name<br />

Deployed at : /usr3/4gl750/AXIS2C/services/ws_state_name<br />

Removing /tmp/w4gl_informix/state_name_wrap.c ...<br />

Removing /tmp/w4gl_informix/state_name.wsdl ...<br />

Removing /tmp/w4gl_informix/axis2_skel_ws_state_name.h ...<br />

Removing /tmp/w4gl_informix/axis2_svc_skel_ws_state_name.c ...<br />

Removing /tmp/w4gl_informix/services.xml ...<br />

Removing /tmp/w4gl_informix/axis2_skel_ws_state_name.c ...<br />

Removing /tmp/w4gl_informix/libws_state_name.so ...<br />

The output of the command line tool shows all the steps completed while creating<br />

and compiling the wrapper function. When errors occur during the deployment<br />

Chapter 12. <strong>Informix</strong> 4GL Web Services 419


process, running each individual step with the w4glc utility might help to diagnose<br />

the reason for the problem.<br />

12.4.5 Deployment of the web service<br />

This process generates the auxiliary code that is required to link the Axis2<br />

application server with the I4GL function. During deployment, the C code for the<br />

web service is created and compiled automatically using the 4GL libraries. The<br />

result of this process is a shared library ready that can be used in the application<br />

server.<br />

This process also creates a WSDL file for the web service and copies this file,<br />

together with the web service shared library, into the application server directory.<br />

The Deploy option is part of the Install menu. Example 12-18 shows the<br />

deployment of the ws_state_name web service.<br />

Example 12-18 Deploy form<br />

+------------------------------------------------------------------------------+<br />

|INSTALL: Generate Deploy Package Exit |<br />

|Deploy the web service. |<br />

|[1 of 1]------------------------[ irkpgm4gl ]-------------------[Help: CTRL-W]|<br />

| |<br />

| CONFIGURATION TO DEPLOY |<br />

| |<br />

| File Name [ws_state_name_irk.4cf ] |<br />

| [ ] |<br />

| [ ] |<br />

| |<br />

| |<br />

| |<br />

| |<br />

| |<br />

| |<br />

| |<br />

| |<br />

| |<br />

| |<br />

| |<br />

| Deployed ws_state_name. |<br />

+------------------------------------------------------------------------------+<br />

420 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


After a successful deployment, the web service is ready to be consume by any<br />

application. The files are copied into the Axis2 services directory automatically.<br />

Example 12-19 shows the web service files on the application server.<br />

Example 12-19 Application Server services directory<br />

informix@irk:/work$ ls $INFORMIXDIR/AX*/services/ws_state_name<br />

libws_state_name.so services.xml state_name.wsdl<br />

informix@irk:/work$<br />

12.4.6 Packaging of the web service<br />

Packaging a web service is the process of creating a compressed file with all the<br />

components that are required by the web service. You can use the compressed<br />

file, in .tar format, on other Axis2 servers. Example 12-20 shows the Package<br />

menu option.<br />

Example 12-20 Package option<br />

+------------------------------------------------------------------------------+<br />

|INSTALL: Generate Deploy Package Exit |<br />

|Package the web service. |<br />

|[1 of 1]------------------------[ irkpgm4gl ]-------------------[Help: CTRL-W]|<br />

| |<br />

| SERVICE PACKAGING |<br />

| |<br />

| File Name [ws_state_name_irk.4cf ] |<br />

| [ ] |<br />

| [ ] |<br />

| |<br />

| |<br />

| |<br />

| |<br />

| |<br />

| |<br />

| |<br />

| |<br />

| |<br />

| |<br />

| |<br />

| Packaging successful. Check $TMPDIR directory (in config file) for .tar file |<br />

+------------------------------------------------------------------------------+<br />

Chapter 12. <strong>Informix</strong> 4GL Web Services 421


The compressed file is left in the $TMPDIR directory. Example 12-21 shows the<br />

contents of the packaged file for the ws_state_name web service.<br />

Example 12-21 Packaged .tar file<br />

informix@irk:/work$ tar tvf /tmp/w4gl_informix/ws_state_name.tar<br />

drwxr-xr-x informix/informix 2010-07-05 21:01 ws_state_name/<br />

-rw-r--r-- informix/informix 2010-07-05 21:01 ws_state_name/services.xml<br />

-rw-r--r-- informix/informix 2010-07-05 21:01 ws_state_name/state_name.wsdl<br />

-rwxr-xr-x informix/informix 2010-07-05 21:01 ws_state_name/libws_state_name.so<br />

informix@irk:/work$<br />

12.4.7 Starting the Axis2 application server<br />

An Axis2 application server is included with the <strong>Informix</strong> 4GL package. It is<br />

located in the AXIS2C directory under the $INFORMIXDIR directory.<br />

The Axis2 application server must be started to consume a web service. It is not<br />

required during the development or deploy process.<br />

Example 12-22 demonstrates how to start the Axis2 application server.<br />

Example 12-22 Starting Axis2<br />

informix@irk:/usr3/4gl750/AXIS2C/bin$ ./axis2_http_server -p 9876<br />

Started Simple Axis2 HTTP Server ...<br />

For more information about the Axis2 application server, refer to:<br />

http://ws.apache.org/axis2/c/docs/axis2c_manual.html<br />

12.4.8 Consuming the I4GL web service<br />

The main feature of a web service is that it can be used by any application in any<br />

platform. A web service is not tied to the technology or programming language<br />

that is used to develop the service. Any application that supports SOAP can<br />

make use of the functions that are implemented inside a web service. SOAP is a<br />

simple XML-based protocol that is used to exchange information over an HTTP<br />

link.<br />

In this section, we demonstrate how to use the ws_state_name web service using<br />

a basic Java application.<br />

422 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Getting a list of available Web Services<br />

You can get a list of available Web Services in the Axis2 application server by<br />

opening a web browser and connecting to the Axis2 server:<br />

http://hostname:port/axis/services<br />

Figure 12-2 shows the Web Services that are available in our example.<br />

Figure 12-2 Axis2 Web Services<br />

You can use the ?wsdl keyword to retrieve the WSDL file as follows:<br />

http://hostname:port/axis/services/ws_state_name?wsdl<br />

Chapter 12. <strong>Informix</strong> 4GL Web Services 423


Figure 12-3 shows the WSDL information for the ws_state_name service.<br />

Figure 12-3 WSDL information for the ws_state_name service<br />

Java application<br />

The main advantages of Web Services is that the application that uses the<br />

services does not need to know anything about how the service is implemented.<br />

The information needed for consuming a web service is defined in the WSDL file,<br />

such as the name of the operations that it supports and the parameters that it<br />

requires.<br />

Example 12-23 demonstrates how to use the ws_state_name I4GL web service<br />

from a simple Java application.<br />

Example 12-23 The state_name.java file<br />

informix@irk:/work$ cat state_name.java<br />

import org.apache.axis.client.Call;<br />

import org.apache.axis.client.Service;<br />

import javax.xml.namespace.QName;<br />

public class state_name {<br />

public static void main(String [] args) {<br />

try {<br />

String endpoint = "http://irk:9876/axis/services/ws_state_name";<br />

String qname = "http://www.ibm.com/ws_state_name";<br />

424 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong><br />

Service service = new Service();<br />

Call call = (Call) service.createCall();


}<br />

call.setTargetEndpointAddress( new java.net.URL(endpoint) );<br />

call.setOperationName(new QName(qname, "state_name"));<br />

String ret = (String) call.invoke( new Object[] { args[0] } );<br />

System.out.println("Sent 'CA', got '" + ret + "'");<br />

} catch (Exception e) {<br />

System.err.println(e.toString());<br />

}<br />

}<br />

informix@irk:/work$ javac state_name.java<br />

informix@irk:/work$ java state_name CA<br />

Sent 'CA', got 'California '<br />

informix@irk:/work$ java state_name AR<br />

Sent 'CA', got 'Arkansas '<br />

informix@irk:/work$<br />

12.5 Consuming a web service with I4GL<br />

In this section, we demonstrate how to consume a web service using <strong>IBM</strong><br />

<strong>Informix</strong> 4GL.<br />

12.5.1 Web service to consume<br />

You can use the w4gl utility to insert details about the specific web service that<br />

you want to consume. The Subscribe menu option allows you to manage<br />

definitions for Web Services in the design database.<br />

Example 12-24 shows the Subscribe form with the details referring to the<br />

ws_state_name web service.<br />

Example 12-24 Subscribe form<br />

+------------------------------------------------------------------------------+<br />

|SUBSCRIBE: Query Next Previous Add Modify Remove Compile Exit |<br />

|Specify a new web service definition. |<br />

|--------------------------------[ irkpgm4gl ]-------------------[Help: CTRL-W]|<br />

| |<br />

| Subscription ID [ 3] |<br />

| WSDL Path [http://irk:9876/axis/services/ws_state_name?wsdl ] |<br />

| [ ] |<br />

| Webservice Function[state_name ] |<br />

| I4GL Function [statename ] |<br />

Chapter 12. <strong>Informix</strong> 4GL Web Services 425


| Target Directory [/work/publish ] |<br />

| Target File Name [statename ] |<br />

| Notes [Wrapper for ws_state_name Web Service ] |<br />

| [ ] |<br />

| [ ] |<br />

| |<br />

| |<br />

| |<br />

| |<br />

| |<br />

| |<br />

| |<br />

+------------------------------------------------------------------------------+<br />

This form includes the following details:<br />

► Subscription ID is an automatic generated identifier of the web service.<br />

► WSDL Path is the complete path of the WSDL file for the service. This path can<br />

be a local file or a URL.<br />

► Web service Function is the function name that is provided by the web<br />

service.<br />

► I4GL Function is the name of the wrapper C function. This name is the<br />

function that our I4GL used to invoke the web service operation.<br />

► Target Directory is the directory where the wrapper and configuration files<br />

are created.<br />

► Target File Name is the name of the C source file with the I4GL function.<br />

The configuration file for a publish operation is generated automatically by the<br />

w4gl utility, but you can also create it using the wsdl_parser as shown in<br />

Example 12-25.<br />

Example 12-25 Generating the configuration file<br />

informix@irk:/work$ wsdl_parser 0<br />

http://irk:9876/axis/services/ws_state_name?wsdl state_name wsstatecode<br />

`pwd`/publish statecode.c<br />

informix@irk:/work$ ls publish<br />

local.wsdl statecode.c_wsstatecode.4cf<br />

informix@irk:/work$ cat publish/statecode.c_wsstatecode.4cf<br />

[SERVICE]<br />

TYPE = subscriber<br />

I4GLVERSION = 7.50.xC4<br />

WSHOME = 0<br />

TARGET_DIR = /work/publish<br />

I4GL_FUNCTION = wsstatecode<br />

TARGET_FILE = statecode.c<br />

[WSDL_INFO]<br />

426 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


WSDL_PATH = /work/publish/local.wsdl<br />

WSDL_NAME_SPACE = http://www.ibm.com/state_name<br />

[FUNCTION]<br />

SERVICENAME = ws_state_name<br />

NAME = state_name<br />

[INPUT]<br />

[VARIABLE] NAME = code TYPE = char(2) [END-VARIABLE]<br />

[END-INPUT]<br />

[OUTPUT]<br />

[VARIABLE] NAME = sname TYPE = char(15) [END-VARIABLE]<br />

[END-OUTPUT]<br />

[END-FUNCTION]<br />

[END-WSDL_INFO]<br />

[END-SERVICE]<br />

12.5.2 Compiling the wrapper code<br />

Next, you need to generate and compile the wrapper code using the Compile<br />

menu option of the w4gl utility. Example 12-26 shows the w4gl utility after the<br />

wrapper code is compiled for the ws_state_name web service.<br />

Example 12-26 Compile option<br />

+------------------------------------------------------------------------------+<br />

|SUBSCRIBE: Query Next Previous Add Modify Remove Compile Exit |<br />

|Compile the subscriber client code. |<br />

|--------------------------------[ irkpgm4gl ]-------------------[Help: CTRL-W]|<br />

| |<br />

| Subscription ID [ 3] |<br />

| WSDL Path [http://irk:9876/axis/services/ws_state_name?wsdl ] |<br />

| [ ] |<br />

| Webservice Function[state_name ] |<br />

| I4GL Function [statename ] |<br />

| Target Directory [/work/publish ] |<br />

| Target File Name [statename ] |<br />

| Notes [Wrapper for ws_state_name Web Service ] |<br />

| +---------------------------------------------------------------------------+|<br />

| | ||<br />

| |Subscriber code has been compiled successfully. ||<br />

| +---------------------------------------------------------------------------+|<br />

| |<br />

| |<br />

| |<br />

| |<br />

| |<br />

+------------------------------------------------------------------------------+<br />

Chapter 12. <strong>Informix</strong> 4GL Web Services 427


After this process is complete, the C files for the wrapper function, including the<br />

object file that contains the function code, are left in the Target Directory that is<br />

specified in the web service definition.<br />

Example 12-27 shows the files for the ws_state_name web service. You can use<br />

these files from an <strong>Informix</strong> 4GL program to consume the web service.<br />

Example 12-27 Web service files<br />

informix@irk:/work/publish$ ls<br />

axis2_stub_ws_state_name_statename.h statename.c_statename.4cf<br />

statename.c statename.o<br />

informix@irk:/work/publish$<br />

12.5.3 Using the web service from an I4GL application<br />

To consume a web service from I4GL, you have to link the object file for the<br />

wrapper function in the 4GL code or use the C source file that is generated<br />

during the subscribe compile process.<br />

Example 12-28 shows a simple 4GL program that uses the wrapper function for<br />

the ws_state_name web service. The wrapper function can be called like any<br />

other C function in I4GL.<br />

Example 12-28 The I4GL subscriber code: wsstate.4gl<br />

informix@irk:/work/publish$ cat wsstate.4gl<br />

MAIN<br />

DEFINE sname CHAR(15)<br />

WHENEVER ERROR STOP<br />

CALL statename("CA") RETURNING sname<br />

DISPLAY "State name: ",sname<br />

END MAIN<br />

informix@irk:/work/publish$ c4gl wsstate.4gl statename.c -o wsstate<br />

$INFORMIXDIR/lib/tools/w4glutil.a -I$AXIS2C_HOME/include/axis2-1.5.0<br />

-L$AXIS2C_HOME/lib -laxis2_engine<br />

informix@irk:/work/publish$ ./wsstate<br />

State name: California<br />

informix@irk:/work/publish$<br />

For more information about <strong>Informix</strong> 4GL, refer to the 4GL Reference Manual at:<br />

http://publib.boulder.ibm.com/infocenter/ifxhelp/v0/index.jsp?topic=/com.ibm.to<br />

ols.doc/4gl.html<br />

428 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


12.6 Troubleshooting<br />

In this section, we discuss typical problems that can occur when developing a<br />

web service using the <strong>Informix</strong> 4GL Web Services tools and how to obtain<br />

diagnostic information through the use of tracing or log files.<br />

12.6.1 Typical problems<br />

This section lists typical problems that can occur.<br />

Connection<br />

Connection errors normally occur when there is something wrong in the<br />

configuration details for the development environment or the web service.<br />

Any web service developed in I4GL requires the use of the <strong>Informix</strong> 4GL<br />

communication libraries for the database connection. I4GL tools such as w4gl<br />

keep details about the environment in the Design database. Therefore, it is<br />

critical that the communication with the <strong>IBM</strong> <strong>Informix</strong> database was configured<br />

correctly before beginning any project.<br />

Environment variables such as INFORMIXDIR and INFORMIXSQLHOSTS must<br />

contain valid details for the <strong>Informix</strong> database server to use during development.<br />

Also, consider the following problems that are related to connection:<br />

► Confirm <strong>Informix</strong> database server details. <strong>Informix</strong> Web Services tools and<br />

Web Services running on the Axis2 server use the database information that<br />

is defined in the Design database.<br />

► Verify connection information. Connection information regarding the Axis2<br />

server, such as the host name or port number, is stored as part of an<br />

Application Server definition. Check that these values are valid.<br />

► Consuming Web Services with a 4GL application requires a TCP connection<br />

from the I4GL program to the application server that is running the web<br />

service. Make sure that the location of the web service is correct and that the<br />

application server can be reached from the I4GL process.<br />

Compilation errors<br />

A common reason for having compilation errors is due to an incorrect setup or<br />

incorrect use of the <strong>Informix</strong> 4GL Web Services utilities.<br />

Environment variables such as PATH and LD_LIBRARY_PATH (or the suitable<br />

variable for the platform) might cause compilation and runtime errors when<br />

developing a web service with <strong>Informix</strong> 4GL. When a compile problem occurs<br />

Chapter 12. <strong>Informix</strong> 4GL Web Services 429


while using one of the I4GL web service tools, the information about the error is<br />

written into the W4GL log file. The default name and location of this file is<br />

/tmp/w4glerr.log.<br />

Example 12-29 shows an error message that is generated by the w4gl utility<br />

during the deploy process.<br />

Example 12-29 A w4gl error.<br />

The file "state_name.err" has been written.<br />

-CDCAK0012: The web service not deployed. Check error log '/tmp/w4glerr.log'<br />

The Deploy menu option performs several operations automatically, including<br />

generating the wrapper code, compiling, and moving the Web Services files into<br />

the Axis2 server. To know the specific task that is failing, use the web compiler<br />

utility (w4glc) to perform each individual task manually.<br />

By default, the w4glc script deletes the temporary files that are used to perform a<br />

task. Use the -keep flag to avoid file deletion.<br />

Example 12-30 shows how to run the generate process using the w4glc utility.<br />

Example 12-30 Using w4glc generate to avoid file deletion<br />

informix@irk:/work$ w4glc -generate -keep ws_state_name_irk.4cf<br />

Begin environment check ...<br />

Environment check is completed.<br />

Generating code. Please wait ...<br />

Generating Wrapper code ....<br />

The wrapper file is /tmp/w4gl_informix/state_name_wrap.c<br />

Generating WSDL ....<br />

Generating headers ....<br />

Generating skeletal code ....<br />

Code generation completed.<br />

With the wrapper files in the temporary directory, you can execute the compile<br />

process from the command line using the w4glc utility and examine the output for<br />

any errors. Example 12-31 shows the output of the compile process when an<br />

compilation error occurs.<br />

Example 12-31 Compilation output<br />

informix@irk:/work$ w4glc -compile -keep ws_state_name_irk.4cf<br />

Begin environment check ...<br />

Environment check is completed.<br />

Generating shared object for service ws_state_name ...<br />

Compiling code. Please wait...<br />

430 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Executing: c4gl -keep --shared -o /tmp/w4gl_informix/libws_state_name.so<br />

-I/usr3/4gl750/AXIS2C/include/axis2-1.5.0 -L/usr3/4gl750/AXIS2C/lib<br />

-laxis2_engine -laxutil -laxis2_axiom...<br />

The compilation was not successful. Errors found: 1.<br />

The file "state_name.err" has been written.<br />

Error executing: c4gl -keep --shared -o /tmp/w4gl_informix/libws_state_name.so<br />

-I/usr3/4gl750/AXIS2C/include/axis2-1.5.0 ...<br />

/usr3/4gl750/lib/tools/w4glutil.a /usr3/4gl750/lib/tools/lib4gl.a at<br />

/usr3/4gl750/lib/globals.pm line 583.<br />

Error executing: c4gl -keep --shared -o /tmp/w4gl_informix/libws_state_name.so<br />

-I/usr3/4gl750/AXIS2C/include/axis2-1.5.0 -L/usr3/4gl750/AXIS2C/lib<br />

-laxis2_engine -laxutil ...<br />

informix@irk:/work$<br />

Similar to any I4GL program, if the error was inside the <strong>Informix</strong> 4GL code, a .err<br />

file is created that contains the error message. Example 12-32 shows the content<br />

of the state_name.err file.<br />

Example 12-32 The state_name.err file<br />

informix@irk:/work$ cat state_name.err<br />

FUNCTION state_name(code)<br />

DEFINE state_rec RECORD<br />

code CHAR(2),<br />

sname CHAR(15)<br />

END RECORD,<br />

code CHAR(2),<br />

sel_stmt CHAR(100);<br />

LET sel_stmt= "SELECT code, sname FROM state WHERE code = ?";<br />

PEPARE st_id FROM sel_stmt;<br />

|________^<br />

|<br />

| A grammatical error has been found on line 11, character 10.<br />

| The construct is not understandable in its context.<br />

| See error number -4373.<br />

DECLARE cur_id CURSOR FOR st_id;<br />

OPEN cur_id USING code;<br />

FETCH cur_id INTO state_rec.*;<br />

...<br />

Chapter 12. <strong>Informix</strong> 4GL Web Services 431


Keeping the wrapper C files in the temporary directory might be useful when the<br />

compilation error appears inside the Axis2 functions. Example 12-33 shows the<br />

temporary files that are created with the generate option for the ws_state_name<br />

web service.<br />

Example 12-33 Temporary files<br />

informix@irk:/work$ ls /tmp/w4gl_informix/<br />

axis2_skel_ws_state_name.c services.xml tmpXMLReqFile<br />

axis2_skel_ws_state_name.h state_name_wrap.c ws_state_name.tar<br />

axis2_svc_skel_ws_state_name.c state_name.wsdl<br />

informix@irk:/work$<br />

While compiling any web service, during creation or consume, make sure all the<br />

required libraries and include files are passed to the compiler correctly. These<br />

requirements can vary from platform to platform. Always check the release notes.<br />

The release and documentation files for <strong>Informix</strong> 4GL are located in the<br />

release/en_us/0333 directory inside the INFORMIXDIR variable. These files<br />

contain additional information that is relevant to the version of I4GL that is<br />

installed, such as known issues or compiler requirements, that might help<br />

diagnose the problem.<br />

Consuming the web service<br />

Errors when consuming the web service might be caused by an invalid web<br />

service definition. Items such as the function name or parameters type are<br />

defined in the configuration file and are used to create the WSDL file that the<br />

application server uses to define the web service. You can retrieve the WSDL<br />

information for a web service using the location of the service and the ?wsdl<br />

suffix from any web browser.<br />

432 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Figure 12-4 shows the WSDL information for the ws_state_name web service.<br />

Figure 12-4 WSDL for ws_state_name service<br />

Make sure the operations, parameters, and data types are correct for the I4GL<br />

code that the function uses.<br />

Testing a web service<br />

<strong>Informix</strong> I4GL does not provide any specific tool for testing Web Services.<br />

Although you can create a simple 4GL code to consume the web service,<br />

depending on the complexity of the web service, it can be more useful to perform<br />

a complete testing.<br />

You can use open source tools, such as soapUI, to test your web service before<br />

publish it in the production environment. For more information about soapUI,<br />

refer to:<br />

http://www.soapui.org/<br />

Chapter 12. <strong>Informix</strong> 4GL Web Services 433


12.6.2 Tracing<br />

A developer can use one of the following types of tracing when diagnosing an<br />

<strong>Informix</strong> 4GL web service problem:<br />

► Application server trace can be used to diagnose problems between a client<br />

application and the Axis2 application server.<br />

► Database trace can be used when diagnostic problems are specific to<br />

operations with the database server, such as SQL errors or incorrect data<br />

returned.<br />

Application server trace<br />

The Axis2c application server provides a method to trace all the exchanged<br />

messages between the application server and a client that is consuming a web<br />

service.<br />

You can set this trace using the -l log_level option when you start the Axis2<br />

server. To launch the Axis2 server with trace enable, run the following command:<br />

axis2_http_server -p 9876 -l 6 -f /tmp/w4gl_informix/axis_trace.log<br />

Use the -l to specify the logging level for the application server. The maximum<br />

value is 6, which enables full tracing.<br />

You can specify the location of the trace file using the -f log_file option.<br />

Example 12-34 shows the contents of a typical trace file.<br />

Example 12-34 A typical application_trace sample<br />

[debug] phase_resolver.c(139) Service name is : ws_zipcode<br />

[debug] phase_resolver.c(1123) Operation name is : zipcode_details<br />

[debug] phase_holder.c(139) Add handler AddressingOutHandler to phase<br />

[debug] phase_holder.c(139) Add handler AddressingOutHandler to phase<br />

[debug] phase_resolver.c(222) svc name is:ws_state_name<br />

[debug] phase_resolver.c(139) Service name is : ws_state_name<br />

[debug] phase_resolver.c(1123) Operation name is : state_name<br />

[debug] phase_holder.c(139) Add handler AddressingOutHandler to phase<br />

...<br />

For more information about the logging options with the Axis2c application<br />

server, refer to:<br />

http://ws.apache.org/axis2/c/docs/axis2c_manual.html#simple_axis_server<br />

434 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Database trace<br />

<strong>IBM</strong> <strong>Informix</strong> 4GL uses the SQLI protocol to exchange data with the <strong>Informix</strong><br />

server. Thus, any web service that is developed using <strong>Informix</strong> 4GL also uses the<br />

SQLI protocol for any communication with the database server.<br />

You can use the SQLIDEBUG environment variable to collect all the messages<br />

between the application server and the <strong>Informix</strong> database server.<br />

To enable this trace, create the SQLIDEBUG environment variable before<br />

starting the Axis2 Application server.<br />

Example 12-35 demonstrates how to set the SQLIDEBUG variable and how to<br />

run sqliprint to un-encode the SQLI file.<br />

Example 12-35 The SQLIDEBUG variable client side<br />

informix@irk:/usr3/4gl750/AXIS2C/bin$ export SQLIDEBUG=2:/tmp/sqlitrace<br />

informix@irk:/usr3/4gl750/AXIS2C/bin$ ./axis2_http_server -p 9876<br />

Started Simple Axis2 HTTP Server ...<br />

...<br />

...<br />

informix@irk:/work$ ls /tmp/sqlitrace*<br />

/tmp/sqlitrace_17008_0_8c819d0<br />

informix@irk:/works$ sqliprint -o tracefile.txt /tmp/sqlitrace_17008_0_8c819d0<br />

informix@irk:/works$<br />

Note: The sqliprint tool is included with <strong>Informix</strong> Client Software<br />

Development Kit (Client SDK).<br />

You can also use the SQLIDEBUG trace at the server side. For more information,<br />

refer to 3.3.6, “Troubleshooting” on page 117.<br />

Chapter 12. <strong>Informix</strong> 4GL Web Services 435


436 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Chapter 13. Application development<br />

considerations<br />

13<br />

In this chapter, we examine some of the considerations a developer might need<br />

to address in a multi-user environment. A single user workstation that connects<br />

to an exclusive-use database does not the issue of two or more independent<br />

uses of the same data at the same time. However, in a multi-user environment,<br />

concurrency is a challenge.<br />

<strong>IBM</strong> <strong>Informix</strong> database servers are designed to provide features to help in<br />

handling concurrency and sorting facilities. The application developer should<br />

design applications to take advantage of these built-in features, rather than<br />

attempt to implement their own facilities in the application. In this chapter we<br />

examine the factors that cause concurrency problems, and focus on ways to<br />

keep the scope and duration of locks to a minimum. To do this, we consider<br />

isolation levels, sharing data, and data contention issues that can occur when<br />

two or more attempts are made to access or change the same row of data.<br />

In the last two sections, we focus on configuration parameters that effect the<br />

application development, and how to monitor issues when the application<br />

developers work with the database administrator to tune the engine and the<br />

application to work effectively.<br />

© Copyright <strong>IBM</strong> Corp. 2010. All rights reserved. 437


13.1 Concurrency and locking<br />

13.1.1 Types of locks<br />

Concurrency involves two or more independent uses of the same data at the<br />

same time. In a database system with many users, each user needs to be able to<br />

access and modify data. Unless the developer and database system impose<br />

controls, there can be negative consequences. Programs might access old data<br />

that is in the process of being changed by another user, and changes might<br />

seem to disappear even though it seems like the change was performed<br />

successfully.<br />

To take advantage of database server controls, tables in a multiple user<br />

environment should be logging tables. At a minimum, if you must use a<br />

nonlogging table within a transaction, either set Repeatable Read isolation level<br />

or lock the table in exclusive mode.<br />

To avoid concurrency problems, the database server imposes a system of locks.<br />

A lock is a claim, or reservation, that a program can place on a piece of data. The<br />

database server assures that no other program can modify it, as long as the lock<br />

is in place. When another application requests the data, the database server<br />

either makes the program wait or turns it back with an error.<br />

The application developer can control the effect of lock access using a<br />

combination of SQL statements and with the buffering mode selected for the<br />

database. The most used SQL statements are SET LOCK MODE, SET<br />

ISOLATION, and SET TRANSACTION. We discuss these in more detail later.<br />

For now, we need a better understanding of the types of locks that we can<br />

encounter.<br />

<strong>IBM</strong> <strong>Informix</strong> offers several server edition. <strong>IBM</strong> <strong>Informix</strong> Extended Parallel Server,<br />

<strong>Informix</strong> Online, and Standard Engine will have different syntax for concurrency<br />

related commands. You can find more information about the command syntax for<br />

the discussion in this chapter in <strong>IBM</strong> <strong>Informix</strong> Guide to SQL: Syntax, v11.50,<br />

SC27-3611.<br />

A lock is implemented as a variable associated with a data item. It can be<br />

explicitly placed by an application or, more frequently, is implicitly handled by the<br />

database management system. The lock is used to mark a data item as<br />

reserved; the type of lock designation determines what actions are permitted by<br />

users in regard to the data item.<br />

438 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


An <strong>IBM</strong> <strong>Informix</strong> instance can have several types of locks:<br />

► A shared lock reserves its object for reading only. It prevents the object from<br />

changing while the lock remains. More than one program can place a shared<br />

lock on the same object. More than one object can read the record while it is<br />

locked in shared mode. In the lock list output visible from onstat -k, a thread<br />

with a shared lock is be designated with an S. If an object is currently locked in<br />

exclusive mode and the user thread wants to acquire a shared lock, the<br />

designation is “IS” (intent-shared).<br />

When a session first connects to a database, <strong>IBM</strong> <strong>Informix</strong> Servers place a<br />

shared lock on the database, to prevent another session from acquiring an<br />

exclusive lock on the same database. SELECT queries place a shared lock at<br />

the table level, because it is faster for the engine to find a table level lock than<br />

it is to search through potentially thousands of row locks.<br />

► Intent-exclusive locks are set automatically by <strong>Informix</strong>. If a row in a table is<br />

updated, an exclusive lock is placed on the row and an intent-exclusive lock is<br />

placed on the table. This assures that no other session can place a shared or<br />

exclusive lock on the table as long as an individual row is locked exclusively.<br />

In the lock list output visible from onstat -k, a thread with an intent exclusive<br />

lock is designated with an IX. A related designation that is sometimes visible<br />

is SIX. This designation indicates the object is currently shared, with<br />

Intent-exclusive when the chance arrives.<br />

► An exclusive lock reserves its object for the use of a single application. This<br />

lock type is used when the application needs to change the object. You<br />

cannot place an exclusive lock where any other kind of lock exists. After you<br />

place an exclusive lock, you cannot place another lock on the same object. In<br />

the lock list output visible from onstat -k, a thread with an exclusive lock is<br />

designated with an X.<br />

► A promotable (or update) lock establishes an intent to update. You can only<br />

place it where no other updatable or exclusive lock exists. You can place an<br />

updatable lock on records that already have shared locks. When the<br />

application is about to change the locked object, you can promote the update<br />

lock to an exclusive lock, but only if no other locks, including shared locks, are<br />

on the record at the time the lock would change from update to exclusive. If a<br />

shared lock was on the record when the update lock was set, you must drop<br />

the shared lock before the update lock can be promoted to an exclusive lock.<br />

In the lock list output visible from onstat -k, a thread with an update lock is<br />

designated with an U.<br />

Chapter 13. Application development considerations 439


13.1.2 Lock duration<br />

The length of time a lock remains in effect is known as lock duration. The<br />

duration of a lock is determined by the application, the closing of a database, and<br />

the type of transaction method used by the application and database<br />

If the database does not use transactions (no transaction log exists and you do<br />

not use a COMMIT WORK statement), an explicit table lock remains until it is<br />

removed by the execution of the UNLOCK TABLE statement.<br />

If database transactions are in use, the end-of-lock-duration event occurs when<br />

the transaction ends or a COMMIT WORK is issued in the application. The<br />

ending transaction causes a release of all table, row, page, and index locks that<br />

were on hand during the transaction.<br />

13.1.3 Lock granularity<br />

With <strong>IBM</strong> <strong>Informix</strong> Servers, the developer can apply locks to databases, tables,<br />

disk pages, data rows, or index-key values. At a database level, an exclusive lock<br />

is simple to enforce for a developer, but it has a big impact on users. No one gets<br />

access until the database lock processing is completed. Concurrency drops to<br />

zero, and performance is maximized for the exclusive use of a single user<br />

running an application.<br />

At the other end of the granularity scope for locks, a transaction can exclusively<br />

lock a row, and have no impact on other users in their work efforts (if they are not<br />

trying to access the same row, and the lock mode is row). Concurrency is<br />

maximized, but performance will tend to slide as the number of users for a<br />

database or table increases.<br />

Table locks<br />

It is the responsibility of both database administrator and developer to select and<br />

enable the best level of lock granularity for users and for their database system.<br />

At the database level, administrative activities such as imports and exports are<br />

usually the task of the database administrator. For such activity, the database<br />

administrator would use a command such as<br />

DATABASE database_name EXCLUSIVE;<br />

Another task, principally for the database administrator, is to enable a change for<br />

a table or an index structure. The task of enabling work on an entire table can be<br />

done with a command similar to one of the following command:<br />

► LOCK TABLE table_name IN EXCLUSIVE MODE;<br />

► LOCK TABLE table_name in SHARE MODE;<br />

440 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


When the task is finished (end of statement or transaction reached), the table is<br />

implicitly unlocked. It could be unlocked explicitly with the following command:<br />

UNLOCK TABLE table_name;<br />

Note: A table lock on a table can decrease update concurrency radically. Only<br />

one update transaction can access that table at any given time, and that<br />

update transaction locks out all other transactions. However, multiple<br />

read-only transactions can simultaneously access the table. This behavior is<br />

useful in a data warehouse environment where the data is loaded and then<br />

queried by multiple users.<br />

Page locks<br />

Lock mode PAGE is the default for <strong>Informix</strong> tables, and it is considered the<br />

optimal level in lock efficiency when rows are being accessed and modified in<br />

physical order. If your tables are large in row count and small in row size, a page<br />

level lock can be severely limiting, because it will lock a large number of rows on<br />

a page, and discourage user access.<br />

In this case, it would be more efficient to change the default lock mode. For all<br />

new tables, this can be done by way of the <strong>Informix</strong> onconfig file, using the<br />

parameter DEF_TABLE_LOCKMODE. For example:<br />

DEF_TABLE_LOCKMODE ROW;<br />

Note: Use a small (or default) page size if your application contains small<br />

sized rows. Increasing the page size for an application that randomly<br />

accesses small rows can decrease performance. In addition, a page lock on a<br />

larger page will lock more rows, which is likely to reduce concurrency in some<br />

situations.<br />

Tables that use page locks cannot support the USELASTCOMMITTED<br />

concurrency feature.<br />

Row and key locks<br />

Row and key locks generally provide the best overall performance when you are<br />

updating a relatively small number of rows, because they increase concurrency.<br />

However, the database server incurs some overhead in obtaining a lock. For an<br />

operation that changes a large number of rows, obtaining one lock per row might<br />

not be cost effective. For operations that consistently change a large number of<br />

rows, page locks might be a better option.<br />

Chapter 13. Application development considerations 441


If a table is not created with row locking and you want row or key locks, you must<br />

alter the table. Here is an example to show how to create a table with row locking<br />

turned on:<br />

CREATE TABLE table_namer(field1 serial,field2 char(20)...)<br />

LOCK MODE ROW;<br />

The ALTER TABLE statement can also change the lock mode. An example for<br />

this command syntax is:<br />

ALTER TABLE table_name LOCK MODE (ROW);<br />

When the lock mode is ROW and you insert or update a row, the database server<br />

creates a row lock. In some cases, you place a row lock by simply reading the<br />

row with a SELECT statement.<br />

When the lock mode is ROW and you insert, update, or delete a key (performed<br />

automatically when you insert, update, or delete a row), the database server also<br />

creates a lock on the key in the index.<br />

Key-value locks<br />

When a user deletes a row within a transaction, the row cannot be locked<br />

because it becomes a non-existent row. However, the database server must<br />

somehow record that a row existed until the end of the transaction. The database<br />

server uses key-value locking to lock the deleted row. Key locks are used<br />

identically to row locks. When the table uses row locking, key locks are<br />

implemented as locks on imaginary rows.<br />

When the table uses page locking, a key lock is placed on the entire index page<br />

that contains the key or that would contain the key if it existed. A page lock on an<br />

index page can decrease concurrency more substantially than a page lock on a<br />

data page. Index pages are dense and hold a large number of keys. By locking<br />

an index page, you make a potentially large number of keys unavailable to other<br />

users until you release the lock.<br />

Note: To determine the current lock mode for a table:<br />

► On UNIX, try “oncheck -pt dbname:tablename | grep Locking”<br />

► On Windows systems, examine the output of “oncheck -pt<br />

dbname:tablename”<br />

Database locks<br />

The act of opening a database places a shared lock on the database name. The<br />

statements which open a database are CONNECT, DATABASE, or CREATE<br />

DATABASE. As long as a database is open, the shared lock on the database<br />

442 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


prevents any other program from dropping the database or putting an exclusive<br />

lock on it.<br />

Locking a database for exclusive use are not needed very often, because this<br />

would prevent other users and programs from accessing it for the duration of the<br />

lock. The usual reason for a database lock would be the need for a major<br />

structure change across several tables, when implementing a series of related<br />

indexes on several tables, or when you have an application that needs<br />

uninterrupted access to the database for a period of time. To lock a database in<br />

exclusive mode, the syntax is:<br />

DATABASE database_name EXCLUSIVE;<br />

Tasks that run from the sysadmin database (dbscheduler tasks, such as Auto<br />

Update Statistics), occasionally might prevent exclusive database access. In this<br />

case, you must temporarily disable the dbscheduler. In the sysadmin database,<br />

stop the scheduler API with:<br />

execute function task(scheduler shutdown)<br />

Restart the scheduler API with:<br />

execute function task(scheduler start)<br />

Smart large object locks<br />

Smart large objects are quite different in the way they work from the rest of the<br />

structures and processes in <strong>IBM</strong> <strong>Informix</strong> databases. The locking and locking<br />

granularity for smart large objects is also different. The database server uses one<br />

of the following granularity levels for locking smart large objects:<br />

► The sbspace chunk header partition<br />

► The smart large object<br />

► A byte range of the smart large object<br />

The default locking granularity for a smart BLOB is at the level of the smart large<br />

object. When you update a smart large object, the database server locks the<br />

smart large object that is being updated. Concurrently, there is an update lock<br />

placed on the sbspace chunk header partition while the object is being updated.<br />

Byte locks<br />

Byte locks, also known as byte-range locks, are used to lock a specific byte range<br />

of a smart large object. Byte-range locking is advantageous because it allows<br />

multiple users to update the same smart large object simultaneously, as long as<br />

they are updating different parts of it. Also, users can read a part of a smart large<br />

object while another user is updating or reading a different part of the same<br />

smart large object.<br />

Chapter 13. Application development considerations 443


How the database server manages byte-range locks<br />

The database server manages byte-range locks in the lock table in a similar<br />

fashion to other locks placed on rows, pages, and tables. However, the lock table<br />

must store the byte range as well. If a user places additional locks on a byte<br />

range, any new byte locks in the range that are contiguous are consolidated into<br />

one lock range.<br />

Likewise, if a user unlocks a portion of the bytes included within a byte-range<br />

lock, the database server will split into multiple byte-range locks.<br />

To enable use of byte-range locks<br />

By default, the database server places a lock on the entire smart large object. At<br />

the time of sbspace creation, there is an option to use byte-range locking.<br />

When the DBA sets the default locking mode for the sbspace to byte-range<br />

locking, the database server locks only the necessary bytes when it updates any<br />

smart large objects stored in the sbspace. To set byte-range locking for the<br />

sbspace that stores the smart large object, the database administrator must use<br />

the onspaces utility.<br />

The following example sets byte-range locking for a new sbspace:<br />

onspaces -c -S sblob -g 2 -p /ifmx/sblob1 -o 0 -s 1000 -Df LOCK_MODE=RANGE<br />

When byte-range locking is set for the individual smart large object, the database<br />

server implicitly locks only the necessary bytes when it selects or updates the<br />

smart large object. The application developer can set byte-range locking for the<br />

smart large object when it is opened, using one of the following methods:<br />

► Set the MI_LO_LOCKRANGE flag in the mi_lo_open() DataBlade API function.<br />

► Set the LO_LOCKRANGE flag in the ifx_lo_open() ESQL/C function.<br />

To lock a byte range explicitly, use one of the following functions:<br />

► mi_lo_lock()<br />

► ifx_lo_lock()<br />

These functions lock the range of bytes that is specified for the smart large<br />

object. If the developer specifies an exclusive lock with either function, UPDATE<br />

statements do not place locks on the smart large object if they update the locked<br />

bytes.<br />

The database server releases exclusive byte-range locks placed with<br />

mi_lo_lock() or ifx_lo_lock() at the end of the transaction. The database<br />

server releases shared byte-range locks placed with mi_lo_lock() or<br />

ifx_lo_lock() based on the same rules as locks placed with SELECT<br />

444 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


statements, depending upon the isolation level. The application can also release<br />

shared byte-range locks with mi_lo_unlock() or ifx_lo_unlock().<br />

For more information about these DataBlade API functions, see <strong>IBM</strong> <strong>Informix</strong>:<br />

DataBlade API Programmer's Guide:<br />

http://publib.boulder.ibm.com/infocenter/idshelp/v10/index.jsp?topic=/com.ibm.d<br />

apip.doc/dapip.htm<br />

You can fine additional details about the ESQL/C functions in the <strong>IBM</strong> <strong>Informix</strong>:<br />

ESQL/C Programmer's Manual at:<br />

http://publib.boulder.ibm.com/infocenter/idshelp/v10/index.jsp?topic=/com.ibm.e<br />

sqlc.doc/esqlc.htm<br />

13.2 Locking issues and performance<br />

Row and key locks generally provide the best performance whenever a database<br />

system only needs to update a small number of rows at a time. However, the<br />

database incurs additional overhead in obtaining a lock as the granularity gets<br />

smaller. The developer should help decide the granularity based on the character<br />

of the trnasactions.The following are guidelines for your decision making:<br />

► For low row count transactions, use row level locking.<br />

► For large processes that update an entire table, set locking to page or lock the<br />

table in exclusive mode before processing.<br />

► For massive updates to many tables or the whole database, lock the database<br />

in exclusive mode before processing.<br />

The type of isolation can affect overall performance because it affects<br />

concurrency. Before you execute a SELECT statement, you can set the isolation<br />

level with one of these options:<br />

► The SET ISOLATION statement (an extension to ANSI SQL-92 standard)<br />

– Can be executed more than once in a transaction.<br />

– Can change the enduring isolation level for a session<br />

– Has an additional isolation level (Cursor Stability)<br />

► SET TRANSACTION (ANSI/ISO-compliant)<br />

– Can only be executed once in a transaction.<br />

► Dirty Read isolation (or ANSI Read Uncommitted) level does not place any<br />

locks on any rows fetched during a SELECT statement. Dirty Read isolation is<br />

appropriate for static tables that are used for queries. Use Dirty Read isolation<br />

with care if update activity occurs at the same time. With Dirty Read, the<br />

Chapter 13. Application development considerations 445


13.2.1 Deadlocks<br />

reader can read a row that has not been committed to the database and might<br />

be eliminated or changed during a rollback.<br />

A deadlock is a situation in which a pair of programs blocks the progress of each<br />

other. Each program has a lock on some object that the other program wants to<br />

access. In a database with local database queries only, a deadlock arises only<br />

when all programs concerned set their lock modes to wait for locks.<br />

An <strong>Informix</strong> database server detects deadlocks immediately when they only<br />

involve data at a single network server. Before a lock is granted, the database<br />

server examines the lock list for each user. If a user holds a lock on the resource<br />

that the requestor wants to lock, the database server traverses the lock wait list<br />

for the user to see if the user is waiting for any locks that the requestor holds. If<br />

so, the requestor receives a deadlock error. It prevents the deadlock from<br />

occurring by returning an error code (error -143 ISAM error: deadlock detected)<br />

to the second program to request a lock. The error code is the one the program<br />

receives if it sets its lock mode to not wait for locks. If your program receives an<br />

error code related to locks even after it sets lock mode to wait, you know the<br />

cause is an impending deadlock.<br />

The best way to avoid deadlocks is to set lock mode to wait for a specific number<br />

of seconds (N), where N is the number of seconds it is reasonable for your<br />

applications to wait on a lock. Example syntax:<br />

SET LOCK MODE TO WAIT 30;<br />

Deadlock errors can be unavoidable when applications update the same rows<br />

frequently. However, certain applications might always be in contention with each<br />

other. Examine applications that are producing a large number of deadlocks and<br />

try to run them at different times. To monitor the number of deadlocks, monitor<br />

the deadlks field in the output of onstat -p.<br />

Distributed transactions<br />

Deadlock handling is more challenging when you are using a distributed query,<br />

which involves more than one database server. In this case, the server cannot<br />

monitor the locks of the other database, so deadlocks cannot be detected before<br />

they occur.<br />

Occasionally, there might be a need for each database to wait on a lock from<br />

another local transaction. When the wait occurs, the entire distributed transaction<br />

might need to wait until the action is cleared up. If both servers get into a<br />

wait-for-the-other-server to complete mode, you have a multi-server deadlock<br />

that neither server can get out of easily.<br />

446 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


To avoid this situation, set the DEADLOCK_TIMEOUT parameter in the onconfig<br />

file. This parameter tells the server how much time to wait before returning an<br />

error code (error -143 ISAM error: deadlock detected). For more information<br />

about using this configuration parameter, see <strong>IBM</strong> <strong>Informix</strong> Dynamic Server<br />

Administrator's Guide, v11.50, SC27-3606.<br />

Distributed transactions, also known as global transactions, can have additional<br />

problems beyond concurrency and locking. In a distributed transaction, we can<br />

have queries that include multiple, separate databases spanning multiple host<br />

systems across a network. With the added task of reaching out to different<br />

servers, we are confronted with delays caused by network traffic, connectivity<br />

issues, additional user authentication, and user activity on the other database<br />

server that can slow or temporarily prevent quick access to the remote database<br />

server.<br />

In the context of a query that is doing an update, insert, select, or delete, this new<br />

group of interfering factors can occasionally present problems. Developers<br />

should include coding conventions to accommodate distributed (XA) transactions<br />

and include code to avoid certain problems. We have included an ESQL/C<br />

routine (xa_tool.ec) in Appendix B, “Accommodating distributed transactions” on<br />

page 469 that is designed to help provide a start for handling XA problems.<br />

13.3 Isolation levels<br />

The number and duration of locks placed on data during a SELECT statement<br />

depends on the level of isolation that the user sets. The type of isolation can<br />

affect overall performance because it affects concurrency.<br />

You can set the isolation level with the SET ISOLATION or the ANSI SET<br />

TRANSACTION statement before you execute the SELECT statement. The main<br />

differences between the two statements are that SET ISOLATION has an<br />

additional isolation level, Cursor Stability, and SET TRANSACTION cannot be<br />

executed more than once in a transaction as SET ISOLATION can.<br />

Dirty Read isolation<br />

Dirty Read isolation (or ANSI Read Uncommitted) does not place any locks on<br />

any rows fetched during a SELECT statement. Dirty Read isolation is appropriate<br />

for static tables that are used for queries. It offers the best performance of all<br />

isolation levels, because the database server does not check or place any locks<br />

for queries.<br />

If update activity can occur at the same time as a dirty read, there is a chance<br />

that a rollback might need to occur during the dirty read. The reader could read a<br />

Chapter 13. Application development considerations 447


ow that has not been committed (this is known as a phantom read) to the<br />

database and the data would be lost during a subsequent rollback. Because of<br />

potential problems with uncommitted data that is rolled back, use Dirty Read<br />

isolation with care.<br />

Databases that do not have logging turned on (and thus do not allow<br />

transactions) use Dirty Read as a default isolation level. In fact, Dirty Read is the<br />

only isolation level allowed for databases that do not have logging turned on.<br />

Committed Read isolation<br />

Committed Read isolation (or ANSI Read Committed) removes the problem of<br />

phantom reads. A reader with this isolation level checks for locks before it returns<br />

a row. By checking for locks, the reader cannot return any uncommitted rows.<br />

The database server does not actually place any locks for rows read during<br />

Committed Read. It simply checks for any existing rows in the internal lock table.<br />

Committed Read is the default isolation level for databases with logging, and it is<br />

an appropriate isolation level for most activities.<br />

Cursor Stability isolation<br />

A reader with Cursor Stability isolation acquires a shared lock on the row that is<br />

currently fetched. This action assures that no other user can update the row until<br />

the user fetches a new row.<br />

If you do not use a cursor to fetch data, Cursor Stability isolation behaves in the<br />

same way as Committed Read. No locks are actually placed.<br />

Repeatable Read isolation<br />

Repeatable Read isolation (also known as ANSI Serializable and ANSI<br />

Repeatable Read) is the strictest isolation level. With Repeatable Read, the<br />

database server locks all rows examined (not just fetched) for the duration of the<br />

transaction.<br />

Repeatable Read is useful during any processing in which multiple rows are<br />

examined, but nothing will change during the transaction. The original application<br />

holds a read lock on each account that it examines until the end of the<br />

transaction, so the attempt by the second application to change the first account<br />

fails (or waits, depending upon SET LOCK MODE).<br />

Note: With Repeatable Read, because even examined rows are locked, if the<br />

database server reads the table sequentially, a large number of rows<br />

unrelated to the query result can be locked.<br />

448 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Use Repeatable Read isolation for tables when the database server can use an<br />

index to access a table. If an index exists and the optimizer chooses a sequential<br />

scan instead, you can use directives to force use of the index. However, forcing a<br />

change in the query path might negatively affect query performance.<br />

13.4 Configuration options<br />

We have brought configuration parameters into our discussion several times. In<br />

this section, we examine <strong>IBM</strong> <strong>Informix</strong> Server configuration options that directly<br />

affect application development. We point out what the developers should know,<br />

and how these parameters affect the application and transactions. For more<br />

information about any of the parameters in the onconfig file or environment<br />

variables relating to configuration, see <strong>IBM</strong> <strong>Informix</strong> Dynamic Server<br />

Administrator's Reference, v11.50, SC27-3607.<br />

13.4.1 Server identification<br />

When the <strong>Informix</strong> server needs to resolve a database instance name, the<br />

oninit process uses the contents of a file known as the sqlhosts file. Each line<br />

in the sqlhosts file provides a database server naming reference, called the<br />

DBSERVERNAME, along with a protocol, a host system reference, and a<br />

listening protocol service reference. On Windows systems, this information is<br />

stored in the registry and is updated and accessed using the setnet32.exe utility.<br />

Multiple DBSERVERNAME references allow for an evenly distributed connection<br />

distribution over a variety of protocols<br />

In addition to the information in the sqlhosts file, the DBSERVERNAME crosses<br />

reference to the onconfig file, which holds the configuration information<br />

describing how the database server is to operate. When a client application<br />

connects to a database server, it specifies a DBSERVERNAME, which helps the<br />

server to know which protocol will be used for the connectivity.<br />

The DBSERVERNAME used in the application connection must be consistent<br />

with a name specified in the sqlhosts file and a DBSERVERNAME that is<br />

defined in the onconfig file.<br />

In the onconfig file, there is a default (main instance) DBSERVERNAME and one<br />

or more alternate DBSERVERNAME parameters that are available. The DBA<br />

specifies the default name to be used with the DBSERVERNAME parameter in<br />

the onconfig file. For alternative application processing, the DBA can allow for or<br />

specify alternative protocols, referenced by an a different DBSERVERNAME.<br />

The alternate DBSERVERNAME or names are specified by the<br />

DBSERVERALIASES parameter in the onconfig file. An application developer<br />

Chapter 13. Application development considerations 449


should check with the DBA to determine whether to use the DBSERVERNAME<br />

or one of the DBSERVERALIASES for connecting with his application. Example<br />

SQL statements include CONNECT, DATABASE, CREATE TABLE, and ALTER<br />

TABLE, which can specify the database server instance.<br />

13.4.2 Storage space identifiers<br />

When tables are created, the database creator has syntax options available to<br />

define where tables and indexes are to be placed physically in a disk structure.<br />

Typically, the database administrator defines the disk structure layout. The disk<br />

layout is assigned by way of dbspaces, and each dbspace is further broken down<br />

into allocations of chunks.<br />

The dbspace is the parent structure unit, used to hold storage information for<br />

tables and indexes, with low level definitions to describe where the actual data<br />

pointers for row data resides, as well as information about indexes, fragments,<br />

and table scope. The dbspace area that tracks pointer locations for data is known<br />

as the table space.<br />

When defining the table and index schema, the database administrator can<br />

specify a dbspace location to hold the table or the index. Other space<br />

specifications for default storage are available if none are specified at creation<br />

time. These default locations define where to store binary large objects (BLOBs),<br />

character large objects (CLOBs), and temporary storage locations.<br />

The default location for the location of temp tables and sorting space, if not<br />

predefined, is the dbspace where a table is accessed, or the root dbspace<br />

(rootdbs). If a default onconfig file definition for the location of temp dbspace is<br />

defined, we have more control over the location used<br />

The DBSPACETEMP parameter<br />

The DBSPACETEMP parameter specifies a list of dbspaces that the database<br />

server uses to globally manage the storage of temporary tables. When a<br />

temporary space is available, it improves performance by enabling the database<br />

server to spread I/O for temporary tables across multiple disks efficiently. The<br />

database server also uses temporary dbspaces during backups to store the<br />

before-images of data that are overwritten while the backup is occurring. More<br />

than one dbspace can be specified for this parameter. Simply list them as<br />

comma-separated values.<br />

The DBSPACETEMP parameter can contain dbspaces with a non-default page<br />

size, but all of the dbspaces in the DBSPACETEMP list must have the same page<br />

size.<br />

450 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


When using a logged database, file activity in temporary dbspaces is not logged.<br />

If the developer writes a query that requires tempspace, it is useful to include the<br />

phrase WITH NO LOG, so that you can force the query to use the designated<br />

temporary dbspace.<br />

The SBSPACENAME parameter<br />

The SBSPACENAME parameter specifies the name of the default sbspace. If<br />

your database tables include smart-large-object columns that do not explicitly<br />

specify a storage space, that data is stored in the sbspace that SBSPACENAME<br />

specifies. The default sbspace is also used by the built-in encryption and<br />

decryption functions to store BLOB or CLOB values.<br />

An sbspace is a specialized type of dbspace, used for storing smartblobs and<br />

binary large object dbspaces. (Binary data or some type of multidimensional data<br />

is common to any datablade that uses R-tree indexing.)<br />

When a create table statement includes a column that defines a CLOB or BLOB<br />

object, the column information will be stored in an sbspace. If the PUT clause is<br />

not specified in the create table statement when the defined CLOB or BLOB is<br />

created, the default location where the column data will be stored is the sbspace<br />

designated by the SBSPACENAME parameter.<br />

If you are using <strong>IBM</strong> <strong>Informix</strong> with J/Foundation, you must provide a smart large<br />

object where the database server can store the Java archive (.jar) files. These<br />

.jar files contain the Java user-defined routines (UDRs). If you use Java UDRs,<br />

you will want to create additional, separate sbspaces for storing smart large<br />

objects.<br />

The SBSPACETEMP parameter<br />

The SBSPACETEMP parameter specifies the name of the default temporary<br />

sbspace for storing temporary smart large objects without metadata or user-data<br />

logging. If you store temporary smart large objects in a standard sbspace, the<br />

metadata is logged. For more information about using temporary smart large<br />

objects, see <strong>IBM</strong> <strong>Informix</strong> DataBlade API Programmer's Guide, V11.50,<br />

SC23-9429.<br />

The SYSSBSPACENAME parameter<br />

The SYSSBSPACENAME parameter specifies the name of the sbspace in which<br />

the database server stores statistics that the UPDATE STATISTICS statement<br />

collects for certain user-defined data types. Normally, the database server places<br />

statistics in the sysdistrib system catalog table.<br />

Chapter 13. Application development considerations 451


Note: For information about writing user-defined statistics, refer to <strong>IBM</strong><br />

<strong>Informix</strong> User-Defined Routines and Data Types <strong>Developer's</strong> Guide, V11.5,<br />

SC23-9438.<br />

For information about providing statistics data for a smart BLOB column, refer<br />

to <strong>IBM</strong> <strong>Informix</strong> DataBlade API Programmer's Guide, V11.50, SC23-9429.<br />

13.4.3 Limiters and limits<br />

In addition to the storage location identifiers mentioned in 13.4.2, “Storage space<br />

identifiers” on page 450, a number of parameters in the onconfig file impose<br />

resource limits. Limits help the engine and system to utilize appropriate<br />

resources rather than consume all the resources on the system and end up in a<br />

crash. When the resources are no longer needed, they are released to be used<br />

by other processes. These configuration limits can be adjusted in cooperation<br />

with the database administrator, to accommodate for application concerns that<br />

might need them.<br />

The MULTIPROCESSOR parameter<br />

The MULTIPROCESSOR parameter is used to determine the type of processing<br />

method the engine will use. If it is set to 0, locking is done in a way that is suitable<br />

for a single- processor computer, and processor affinity is ignored.<br />

If the nearby onconfig file SINGLECPU_VP parameter is non-zero (On),<br />

MULTIPROCESSOR and user-defined VPCLASSes (of any kind) will not work.<br />

The VPCLASS parameter<br />

The VPCLASS parameter allows you to designate a class of virtual processors<br />

(VPs), create a user-defined VP, and specify the following information for it:<br />

► The number of virtual processors that the database server should start<br />

initially.<br />

► The maximum number of virtual processors allowed for this class.<br />

► The assignment of virtual processors to CPUs if processor affinity is available.<br />

► The disabling of priority aging by the operating system if the operating system<br />

implements priority aging.<br />

You can have multiple VPCLASS parameter definitions. Use one VPLCLASS<br />

reference for each class of virtual processor, one per line. Basic guidelines for<br />

defining a VPLCASS are in <strong>IBM</strong> <strong>Informix</strong> Dynamic Server Administrator's<br />

Reference, V11.50, SC27-3607.<br />

452 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


For information about creating a user-defined virtual process, see <strong>IBM</strong> <strong>Informix</strong><br />

User-Defined Routines and Data Types <strong>Developer's</strong> Guide, V11.5, SC23-9438<br />

or J/Foundation <strong>Developer's</strong> Guide, V11.5, SC23-9434.<br />

The NETTYPE parameter<br />

The NETTYPE parameter provides tuning options for the protocols that<br />

DBSERVERNAME entries define in the sqlhosts file or registry. Each<br />

DBSERVERNAME entry in the sqlhosts file or registry is defined in relation to<br />

either the DBSERVERNAME parameter or the DBSERVERALIASES parameter<br />

in the ONCONFIG file.<br />

The NETTYPE configuration parameter describes a network connection as<br />

follows:<br />

► The protocol (or type of connection).<br />

► The number of poll threads assigned to manage the connection.<br />

► The expected number of concurrent connections.<br />

► The class of virtual processor that will run the poll threads.<br />

► You can specify a NETTYPE parameter for each protocol that you want the<br />

database server to use.<br />

► There is a special NETTYPE setting available if you want to enable the<br />

database server to use multiplexed connections on UNIX. To do this, you<br />

designate a NETTYPE with the value sqlmux, as in the following example.<br />

NETTYPE sqlmux<br />

The LOCKS parameter<br />

The LOCKS parameter specifies the initial size of the lock table. Every SQL<br />

session that connects to a database, and accesses tables and rows, generates a<br />

lock. If the lock is non-exclusive, it is shared; if something needs to change, it is<br />

exclusive. If there is an intent to change an object, it is an intent-exclusive lock.<br />

The lock table holds an entry for each type of lock entry, and each of these lock<br />

entries will have a small allocation in resident memory.<br />

When the number of locks exceeds the lock table value, on 32-bit servers, the<br />

database server will increase the size of the lock table by doubling the lock table<br />

value, up to 99 times, or to the maximum value for the server allowance<br />

(whichever comes first). On 32-bit servers, the maximum limit is 8,000,000 locks.<br />

On 64-bit servers, the lock table limit is based on the maximum starting locks<br />

value (500,000)+99 allowed increments of 1,000,000 locks for a total of<br />

599,000,000 locks.<br />

Chapter 13. Application development considerations 453


The amount of memory storage per lock ranges from 100 to 200 bytes,<br />

depending on the byte-word size and the platform.<br />

Note: All lock table increments are kept in virtual memory. If the server engine<br />

has limited shared memory, locks can become a memory resource drain.<br />

The STACKSIZE parameter<br />

The STACKSIZE parameter specifies the stack size for database server user<br />

threads. Setting a value for STACKSIZE that is too large wastes virtual memory<br />

space and can cause swap-space problems.<br />

For 32-bit platforms, the default STACKSIZE value of 32 KB is sufficient for<br />

non-recursive database activity. For 64-bit platforms, the recommended<br />

STACKSIZE value is 64 KB.<br />

In recursive SQL routines, the server checks for the possibility of stack-size<br />

overflow and automatically expands the stack.<br />

UDRs should increase the stack size for a routine as needed, using the stack<br />

modifier in the CREATE FUNCTION statement.<br />

The USELASTCOMMITTED parameter<br />

This parameter specifies the isolation level whenever the LAST COMMITTED<br />

feature of the COMMITTED READ isolation level is implicitly in effect. The LAST<br />

COMMITTED feature can reduce the risk of locking conflicts between concurrent<br />

transactions on tables that have exclusive row locks.<br />

Important: The USELASTCOMMITTED parameter works only with tables<br />

that have been created or altered to have ROW as their locking granularity.<br />

For the USELASTCOMMITTED parameter to work as expected, and given that a<br />

table has been created or altered to have ROW as their locking granularity, the<br />

following considerations also apply:<br />

► If SET TRANSACTION is enabled with READ COMMITTED or READ<br />

UNCOMMITTED, USELASTCOMMITTED will work.<br />

► Tables created without any explicit lock mode setting will use the default<br />

setting in DEF_TABLE_LOCKMODE.<br />

The DEF_TABLE_LOCKMODE parameter<br />

The DEF_TABLE_LOCKMODE parameter sets the lock mode for every newly<br />

created table for all sessions connected to a logging or nonlogging database, and<br />

has no effect on existing tables in the database.<br />

454 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


The specified value can be ROW, which sets the lock mode to ROW for every<br />

new table connected to a database. If the specified value is PAGE (default), any<br />

exclusive locked table remains inaccessible.<br />

There is also an environment variable on the client side,<br />

DEF_TABLE_LOCKMODE, which can be set with a lock mode value (PAGE or<br />

ROW). The environment variable has rules of precedence involved if the<br />

onconfig value is also set. For more information, see <strong>IBM</strong> <strong>Informix</strong> Dynamic<br />

Server Administrator's Reference, V11.50, SC27-3607.<br />

The DEADLOCK_TIMEOUT parameter<br />

The DEADLOCK_TIMEOUT parameter specifies the maximum number of<br />

seconds that a database server thread can wait to acquire a lock. Use this<br />

parameter only for distributed queries that involve a remote database server.<br />

Note: This parameter applies only to distributed queries. There is a separate,<br />

automated mechanism for deadlocks that are internal to a local database.<br />

The OPTCOMPIND parameter<br />

The OPTCOMPIND parameter determines the method used by the engine to<br />

process a query. All queries are optimized to run based on the guideline<br />

recommended by this parameter, unless the developer forces a different<br />

guideline using a directive.<br />

When the OPTCOMPIND parameter is set to one of the following values, a given<br />

query is optimized using the guideline assigned:<br />

0 When appropriate indexes exist for tables in the query, the optimizer<br />

chooses index scans, without consideration of the cost, over table<br />

scans.<br />

1 As long as the isolation is not Repeatable Read, the optimizer will<br />

use cost based decisions. If Repeatable Read is in use, it behaves as<br />

though OPTCOMPIND=0. Setting 1 is recommended for optimal<br />

performance.<br />

2 The optimizer uses cost to determine an execution path regardless of<br />

isolation level. Index scans are not given preference; the optimizer<br />

decision is purely based on cost. Setting 2 is the default if the<br />

parameter is not set.<br />

Note: Use the same OPTCOMPIND value in the development and in the<br />

production environment. Performance and query behavior can have variations<br />

if the OPTCOMIND value is different in the development and production<br />

environments.<br />

Chapter 13. Application development considerations 455


The DIRECTIVES parameter<br />

The DIRECTIVES parameter enables or disables the use of SQL directives. SQL<br />

directives allow you to specify behavior for the query optimizer in developing<br />

query plans for SELECT, UPDATE, and DELETE statements.<br />

Set DIRECTIVES to 1, which is the default value, to enable the database server<br />

to process directives.<br />

Set DIRECTIVES to 0 to disable the database server from processing directives.<br />

Note: Client programs have the option to set the IFX_DIRECTIVES<br />

environment variable to ON or OFF to enable or disable processing of<br />

directives by the database server. The setting of the IFX_DIRECTIVES<br />

environment variable overrides the setting of the DIRECTIVES configuration<br />

parameter. If you do not set the IFX_DIRECTIVES environment variable, all<br />

sessions for a client inherit the database server configuration for processing<br />

SQL directives.<br />

The MAX_PDQPRIORITY parameter<br />

The MAX_PDQPRIORITY parameter limits the PDQ resources that the database<br />

server can allocate to a given DSS query. MAX_PDQPRIORITY is a factor that is<br />

used to scale the value of PDQ priority set by users. For example, if the database<br />

administrator sets MAX_PDQPRIORITY to 80, and a user sets the<br />

PDQPRIORITY environment variable to 50 and issues a query, the database<br />

server silently processes the query with a PDQ priority of 40. The database<br />

administrator can use the onmode utility to change the value of<br />

MAX_PDQPRIORITY while the database server is online.<br />

In <strong>Informix</strong> database server, PDQ resources include memory, CPU, disk I/O, and<br />

scan threads. the MAX_PDQPRIORITY parameter lets the database<br />

administrator run decision support concurrently with OLTP, without a<br />

deterioration of OLTP performance. However, if the MAX_PDQPRIORITY<br />

parameter is too low, the performance of decision- support queries can degrade.<br />

Table 13-1 lists the MAX_PDQPRIORITY value that you can set.<br />

Table 13-1 The MAX_PDQPRIORITY value<br />

Value Database Server Action<br />

0 Turns off PDQ. DSS queries use no parallelism.<br />

1 Fetches data from fragmented tables in parallel (parallel scans) but<br />

uses no other form of parallelism.<br />

100 Uses all available resources for processing queries in parallel.<br />

456 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Value Database Server Action<br />

An integer<br />

between 1-100<br />

13.4.4 Java configuration parameters<br />

The configuration parameters listed in Table 13-2 allow you to use J/Foundation,<br />

which incorporates an embedded Java Virtual Machine (JVM) on the database<br />

server. For more information about these parameters, see J/Foundation<br />

<strong>Developer's</strong> Guide, V11.5, SC23-9434.<br />

Table 13-2 Java configuration parameters<br />

Parameter name Description<br />

Sets the percentage of the user-requested PDQ resources to be<br />

allocated to the query.<br />

AFCRASH 0x10 When the 0x10 bit is on for AFCRASH, all the messages that the<br />

JVM generates are logged into the JVM_vpid file, where vpid is<br />

the process ID of the Java virtual processor. This file is stored in<br />

the directory where the JVPLOG file is stored.<br />

JVPDEBUG When set to 1, tracing messages are written to the JVPLOG file.<br />

JVPHOME Directory where the classes of the <strong>IBM</strong> <strong>Informix</strong> JDBC Driver are<br />

installed.<br />

JVPLOGFILE Absolute path name for your Java VP log files.<br />

JVPPROPFILE Absolute path name for the Java VP properties file.<br />

JVPJAVAVM Libraries to use for the JVM.<br />

JVPJAVAHOME Directory where the Java Runtime Environment (JRE) for the<br />

database server is installed.<br />

JVMTHREAD Thread package (green or native) to use for the JVM.<br />

JVPVJAVALIB Path from JVPJAVAHOME to the location of the Java VM<br />

libraries.<br />

JVPCLASSPATH Initial Java class path setting.<br />

VPCLASS jvp=n Number of Java virtual processors that the database server<br />

should start.<br />

For additional onconfig file parameters and how they relate to development, see<br />

Appendix A, “Parameters in the onconfig file” on page 467.<br />

Chapter 13. Application development considerations 457


13.5 Working with your database administrator<br />

There is an assumption throughout this book that our main audience is the<br />

developer, with a distinctive separate role from the database administrator (DBA).<br />

The database server administrator has the task of allocating and handling<br />

resources effectively in the server side of a client -server environment. When a<br />

performance issue occurs or when a transaction process is not working as it<br />

should, you need to work with the database administrator to find a solution.<br />

Present the problem to the database administrator, who might have a good idea<br />

about a particular configuration area that might relate to the problem. There are a<br />

few areas we can discuss here, which might help target the common problems<br />

that developers experience.<br />

Configuration parameters that affect logging<br />

Checkpoints, logging, and page cleaning are necessary to maintain database<br />

consistency. A direct trade-off exists between the frequency of checkpoints or the<br />

size of the logical logs and the time that it takes to recover the database in the<br />

event of a failure. A database administrator has to consider ways to reduce the<br />

overhead for these activities based on the acceptable delay during recovery.<br />

Sometimes these decisions are influenced by the behavior of the application.<br />

Here we discuss the configuration parameters that effect logging.<br />

LOGBUFF and PHYSBUFF<br />

The LOGBUFF and PHYSBUFF configuration parameters effect logging I/O<br />

activity because they specify the respective sizes of the logical-log and<br />

physical-log buffers that are in shared memory. The size of these buffers<br />

determines how quickly they fill and therefore how often they need to be flushed<br />

to disk. If checkpoints tend to have long duration, you can seek further<br />

information related to buffer tuning and checkpoint tuning information in the <strong>IBM</strong><br />

<strong>Informix</strong> Dynamic Server Performance Guide, V11.50, SC27-3618-00.<br />

LOGFILES<br />

The LOGFILES parameter specifies the number of logical-log files. This<br />

parameter only becomes important with respect to the long transaction high<br />

water mark (LTXHWM and LTXEHWM), if we are having trouble with transactions<br />

that need to be rolled back. See the sections on DYNAMIC_LOGS, LTXHWM<br />

and LTXEHWM, later in this chapter for more details.<br />

LOGSIZE<br />

Choose a log size based on how much logging activity occurs and the amount of<br />

risk in case of catastrophic failure. If you cannot afford to lose more than an<br />

hour's worth of data, create many small log files that each hold an hour's worth of<br />

458 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


transactions. If your system is stable with high logging activity, choose larger logs<br />

to improve performance.<br />

Note: A backup process can hinder transaction processing if data is located<br />

on the same disk as the logical-log files. It is better to keep logical logs on<br />

separate disks from data, if possible. If extra disks are not an option for<br />

separate logical log space, however, you can wait for periods of low user<br />

activity before you back up the logical-log files.<br />

You need to adjust the size of the logical log when your transactions include<br />

simple large objects or smart large objects, as the following sections describe.<br />

Estimating logical-log size when logging simple large objects<br />

To obtain better overall performance for applications that perform frequent<br />

updates of TEXT or BYTE data in blobspaces, reduce the size of the logical log.<br />

Blobpages cannot be reused until the logical log to which they are allocated is<br />

backed up. When TEXT or BYTE data activity is high, the performance impact of<br />

more frequent checkpoints is balanced by the higher availability of free<br />

blobpages.<br />

When you use volatile blobpages in blobspaces, smaller logs can improve<br />

access to simple large objects that must be reused. Simple large objects cannot<br />

be reused until the log in which they are allocated is flushed to disk. In this case,<br />

you can justify the cost in performance because those smaller log files are<br />

backed up more frequently.<br />

Estimating logical-log size when logging smart large objects<br />

If you plan to log smart large object user data, you must ensure that the log size<br />

is considerably larger than the amount of data being written. Smart large object<br />

metadata is always logged even if the smart large objects are not logged.<br />

Use the following guidelines when you log smart large objects:<br />

► If you are appending data to a smart large object, the increased logging<br />

activity is roughly equal to the amount of data written to the smart large<br />

object.<br />

► If you are updating a smart large object (overwriting data), the increased<br />

logging activity is roughly twice the amount of data written to the smart large<br />

object. The database server logs both the before-image and after-image of a<br />

smart large object for update transactions. When updating the smart large<br />

objects, the database server logs only the updated parts of the before and<br />

after image.<br />

Chapter 13. Application development considerations 459


► Metadata updates affect logging less. Even though metadata is always<br />

logged, the number of bytes that are logged is usually much smaller than the<br />

smart large objects.<br />

The DYNAMIC_LOGS parameter<br />

The default value for the DYNAMIC_LOGS configuration parameter is 2, which<br />

means that the database server allocates a new logical log file automatically after<br />

the current log file when it detects that the next log file contains an open<br />

transaction. The database server automatically checks whether the log after the<br />

current log still contains an open transaction at the following times:<br />

► Immediately after it switches to a new log file while writing log records (not<br />

while reading and applying log records)<br />

► At the beginning of the transaction cleanup phase which occurs as the last<br />

phase of logical recovery<br />

Logical recovery happens at the end of fast recovery and at the end of a cold<br />

restore or roll forward. For more information about the phases of fast recovery,<br />

see <strong>IBM</strong> <strong>Informix</strong> Dynamic Server Administrator's Guide, Version 11.50,<br />

SC27-3606.<br />

If you set DYNAMIC_LOGS to 0, the database server still checks whether the<br />

next active log contains an open transaction when it switches log files. If it finds<br />

an open transaction in the next log to be active, it issues the following warning:<br />

WARNING: The oldest logical log file (%d) contains records from an open<br />

transaction (0x%p), but the Dynamic Log Files feature is turned off.<br />

The LTXHWM and LTXEHWM parameters<br />

The LTXHWM parameter indicates how full the logical log is when the database<br />

server starts to check for a possible long transaction and to roll it back.<br />

LTXEHWM indicates the point at which the database server suspends new<br />

transaction activity to locate and roll back a long transaction.<br />

With the dynamic log file feature, long transaction high watermarks are no longer<br />

as critical because the database server does not run out of log space unless you<br />

use up the physical disk space available on the system. Under normal conditions,<br />

you should keep the default values for LTXHWM and LTXEHWM. If a rollback is<br />

ever needed, it can indicate a serious problem within an application.<br />

460 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


After Version 9.4, LTXHWM and LTXEHWM are not in the onconfig.std file and<br />

default to the following values, depending on the value of the DYNAMIC_LOGS<br />

configuration parameter:<br />

► With DYNAMIC_LOGS set to 1 or 2, the long transaction high watermark<br />

default values are 80 for LTXHWM and 90 for LTXEHWM. Because the<br />

database server does not run out of logs, other users can still access the log<br />

during the rollback of a long transaction.<br />

► With DYNAMIC_LOGS to 0, the default values are 50 for LTXHWM and 60 for<br />

LTXEHWM.<br />

You might want to change these default values for one of the following reasons:<br />

► To allow other transactions to continue update activity (which requires access<br />

to the log) during the rollback of a long transaction. In this case, you increase<br />

the value of LTXEHWM to raise the point at which the long transaction<br />

rollback has exclusive access to the log.<br />

► To perform scheduled transactions of unknown length, such as large loads<br />

that are logged. In this case, you increase the value of LTXHWM so that the<br />

transaction has a chance to complete before reaching the high watermark.<br />

13.5.1 Parameters for negotiation<br />

While the database administrator should make final decisions for server<br />

parameters, there are several parameters for which you need agreement to<br />

achieve the most effective results.<br />

The VPCLASS parameter<br />

If you decide to use UDRs, a UDR can use the processing power in the CPU<br />

class that users currently have at their disposal, or you can define the UDR with<br />

its own processor class when you create the function. You define a new class of<br />

virtual processors to isolate UDR execution from other transactions that execute<br />

on the CPU virtual processors. This method is typically used when you write<br />

UDRs to support user-defined data types. The class name that you specify in the<br />

VPCLASS parameter must match the name specified in the CLASS modifier of<br />

the CREATE FUNCTION statement.<br />

Note: Because a user-defined CPU class is treated as a virtual processor, the<br />

onconfig file SINGLE_CPU_VP parameter must be off (0) and<br />

MULTIPROCESSOR must be on (1).<br />

Chapter 13. Application development considerations 461


Guidelines for setting VPCLASS:<br />

► For uniprocessor computers, it is recommended that you use one CPU virtual<br />

processor.<br />

► VPCLASS cpu,num=1.<br />

► For multiprocessor systems with four or more CPUs that are primarily used as<br />

database servers, it is recommended that you set the VPCLASS num option to<br />

one less than the total number of processors. For example, if you have four<br />

CPUs, use the following specification:<br />

VPCLASS cpu,num=3<br />

Process priority aging<br />

On some operating systems, priority aging occurs when the operating system<br />

lowers the priority of long-running processes as they accumulate processing<br />

time. Always disable the priority aging parameter of VPCLASS because it can<br />

cause the performance of the database server processes to decline over time.<br />

For further information, check the system notes for your database server.<br />

Processor affinity<br />

Processor affinity distributes the computation impact of CPU virtual processors<br />

and other processes. On computers that are dedicated to the database server,<br />

assigning CPU virtual processors to all but one of the CPUs achieves maximum<br />

CPU utilization. On computers that support both database server and client<br />

applications, you can bind applications to certain CPUs through the operating<br />

system. By doing so, you effectively reserve the remaining CPUs for use by<br />

database server CPU virtual processors, which you bind to the remaining CPUs<br />

with the VPCLASS configuration parameter.<br />

Set the aff option of the VPCLASS parameter to the numbers of the CPUs on<br />

which to bind CPU virtual processors. For example, on an 8 CPU system, the<br />

following VPCLASS setting assigns CPU virtual processors to processors 4 to 7,<br />

and CPU’s 0, 1, 2, and 3 would be most available to the application:<br />

VPCLASS cpu,num=4,aff=4-7<br />

For additional methods that can be used with the VPCLASS, see I<strong>IBM</strong> <strong>Informix</strong><br />

Dynamic Server Administrator's Guide, V11.50, SC27-3606.<br />

13.5.2 Monitoring isolation levels<br />

As a general discovery tool, the onstat -g sql command can be used for<br />

determining the isolation levels and lock modes for SQL statements actively<br />

running against the server, their associated databases and any SQL errors that<br />

might have occurred. The onstat -g sql command can also be run with an<br />

462 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


optional session ID. The output contains the most recent and the current SQL<br />

statements being run by the session.<br />

13.5.3 Monitoring locks<br />

The onstat -k command displays the current database locks held within the<br />

system. The type of lock is determined by the logging mode, isolation levels, and<br />

application design. Example 13-1shows the output of a sample onstat -k<br />

command.<br />

Example 13-1 The onstat -k command output<br />

<strong>IBM</strong> <strong>Informix</strong> Dynamic Server Version 11.50.UC6 -- On-Line -- Up 03:55:17 --<br />

15360 Kbytes<br />

Locks<br />

address wtlist owner lklist type tblsnum rowid key#/bsiz<br />

a095f78 0 a4d9e68 0 HDR+S 100002 203 0<br />

1 active, 2000 total, 2048 hash buckets, 0 lock table overflows<br />

The information in this output explains lock aspects. The type column explains<br />

the lock types associated with each open lock. The abbreviations in the Type<br />

column defines lock types as follows:<br />

HDR Header<br />

B Byte lock<br />

S Shared<br />

I Intent<br />

X Exclusive<br />

U Update<br />

IX Intent exclusive<br />

IS Intent-shared<br />

SIX Shared, Intent exclusive<br />

Chapter 13. Application development considerations 463


The lock level is determined by the value of the tblsnum (tblspace ID) and the row<br />

ID as show in Table 13-3 and Table 13-4.<br />

Table 13-3 Determining lock level from Row ID<br />

If RowID Lock level is<br />

Equals 0 Table<br />

Ends in 00 Page<br />


– X=transaction cleanup<br />

– Y=condition<br />

Watch for persistent L, S, T, or Y.<br />

3. Look at flag position 3 (thread activity):<br />

– A=DBSpace backup<br />

– B=Begin work<br />

– P=Preparing/prepared<br />

– X=XA prepare<br />

– C=Commiting/committed<br />

– R=Aborting/aborted<br />

– H=Heuristic aborting/aborted<br />

Watch for P, X, C, R, H.<br />

For more information about onstat commands and the meanings of the columns,<br />

refer to:<br />

http://publib.boulder.ibm.com/infocenter/idshelp/v115/index.jsp?topic=/com.ibm.<br />

adref.doc/ids_adr_0608.htm<br />

Chapter 13. Application development considerations 465


466 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


A<br />

Appendix A. Parameters in the onconfig<br />

file<br />

In 13.4, “Configuration options” on page 449, we discuss several parameters that<br />

have a direct impact on developer methods and understandings. The list<br />

provided in that section is limited to the direct-impact related parameters. It is<br />

likely that application developers will not have much use for the remaining<br />

onconfig parameters most of the time.<br />

Normally, this remaining configuration information is a concern only for the DBAs.<br />

Occasionally, there will come a time when performance of an application might<br />

come into question. Sometimes slow performance is caused by the application,<br />

and is under control of the developer. At other times it might be an onconfig file<br />

setting in the <strong>IBM</strong> <strong>Informix</strong> server that requires adjustment.<br />

Table A-1 on page 468 lists the parameters that might help developers and DBAs<br />

to narrow the target area for further investigation. The table is not an exhaustive<br />

list. Parameters that do not apply or that we have already discussed in this book<br />

are not listed. For further information about any of these parameters, see <strong>IBM</strong><br />

<strong>Informix</strong> Dynamic Server Administrator's Reference, v11.50, SC27-3607.<br />

From the developer’s point of view, it makes sense to categorize the configuration<br />

parameters from a functional perspective, rather than a strict listing by name.<br />

Toward this objective, the parameter names are listed in the table by function<br />

groupings to help narrow down the parameter list that can be considered for an<br />

© Copyright <strong>IBM</strong> Corp. 2010. All rights reserved. 467


area of specific interest. The functional groupings do not reflect specific naming<br />

conventions used in the onconfig file.<br />

Table A-1 Parameters in the onconfig file<br />

Related function area Parameters<br />

Storage Space ROOTNAME, ROOTOFFSET, ROOTSIZE, MIRROR,<br />

MIRROROFFSET, LOGFILES, LOGSIZE,<br />

DBSPACETEMP, SBSPACETEMP, SBSPACENAME,<br />

SYSSBSPACENAME, CLEANERS, STAGEBLOB,<br />

TBLTBLFIRST, TBLTBLNEXT, DATASKIP<br />

Path locations ROOTPATH, JVPJAVALIB, JVPJAVAVM, MSGPATH,<br />

PLOG_OVERFLOW_PATH<br />

Buffer Movement BUFFERPOOL,PHYSBUFF, PHYSFILE<br />

Memory Cache DD_HASHSIZE, DD_HASHMAX, DS_HASHSIZE,<br />

DS_POOLSIZE, PC_HASHSIZE, PC_POOLSIZE,<br />

STMT_CACHE, STMT_CACHE_HITS,<br />

STMT_CACHE_SIZE, STMT_CACHE_NOLIMIT,<br />

STMT_CACHE_NUMPOOL, PLCY_POOLSIZE,<br />

PLCY_HASHSIZE, USRC_POOLSIZE,<br />

USRC_HASHSIZE<br />

Memory control RESIDENT, SHMVIRTSIZE, SHMADD, EXTSHMADD,<br />

SHMTOTAL, SHMVIRT_ALLOCSEG,<br />

SHMNOACCESS,VP_MEMORY_CACHE_KB,<br />

ONLIDX_MAXMEM<br />

Virtual processor and<br />

connection<br />

468 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong><br />

NETTYPE, LISTEN_TIMEOUT,<br />

MAX_INCOMPLETE_CONNECTIONS, FASTPOLL,<br />

MULTIPROCESSOR, VPCLASS, SINGLE_CPU_VP,<br />

AUTO_AIOVPS, DIRECT_IO<br />

SQL Control LOCKS, OPTCOMPIND, DIRECTIVES,<br />

EXT_DIRECTIVES, OPT_GOAL, IFX_FOLDVIEW,<br />

RA_PAGES, RA_THRESHOLD<br />

Transaction control DEF_TABLE_LOCKMODE, BLOCKTIMEOUT,<br />

TXTIMEOUT, HETERO_COMMIT,<br />

DEADLOCK_TIMEOUT, DYNAMIC_LOGS, LOGBUFF,<br />

LTXHWM, LTXEHWM, TEMPTAB_NOLOG,<br />

AUTO_REPREPARE<br />

Decision support DS_MAX_QUERIES, DS_TOTAL_MEMORY,<br />

DS_MAX_SCANS, DS_NONPDQ_QUERY_MEM


B<br />

Appendix B. Accommodating distributed<br />

transactions<br />

This appendix discusses the use of distributed transactions with an <strong>IBM</strong> <strong>Informix</strong><br />

database server.<br />

© Copyright <strong>IBM</strong> Corp. 2010. All rights reserved. 469


B.1 Distributed transactions<br />

A transaction is a series of actions performed as a single logical unit of work in<br />

which either all of the actions are performed or none of them are.<br />

A distributed transaction is a transaction that runs in multiple processes, usually<br />

on several systems, and normally involves actions against two or more<br />

databases. Each participant of a distributed transaction must agree to commit<br />

the changes before the distributed transaction can be committed.<br />

There are three core components on a distributed transaction:<br />

► Application program (AP)<br />

Application program implements the desired business function. It specifies a<br />

sequence of operations that involve resources such as databases. An<br />

application program participates in one or more units of work, and might<br />

decide to commit or roll back each unit of work independently.<br />

► Resource manager (RM)<br />

Resource manager manages access to shared resources such as databases.<br />

The resource manager provides the services to manage the data involved in<br />

the distributed transaction.<br />

► Transaction manager (TM)<br />

Transaction manager manages global transactions and coordinates the<br />

decision to commit them or roll them back ensuring their atomicity. The<br />

transaction manager also coordinates recovery activities of the resource<br />

managers when necessary, such as after a component failure.<br />

The XA standards, set forth by the Open Group's X/Open Distributed Transaction<br />

Processing (DTP) model, define the interfaces between the transaction manager,<br />

the application program, and the resource manager in a DTP environment.<br />

These interfaces are implemented in the <strong>Informix</strong> TP/XA Interface Library.<br />

B.2 TP/XA Transaction Manager XA Interface Library<br />

TP/XA is a library of functions that allows the <strong>IBM</strong> <strong>Informix</strong> database server act<br />

as a resource manager in the X/Open DTP environment.The TP/XA library<br />

facilitates communication between a third-party transaction manager and the<br />

database server.<br />

TP/XA is supplied with <strong>IBM</strong> <strong>Informix</strong> ESQL/C, which is included with <strong>Informix</strong><br />

Client Software Development Kit (Client SDK).<br />

470 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


In addition to the TP/XA library, a header file xa.h, is supplied that contains the<br />

definition for the functions and common structures, such as XID or xa_switch_t,<br />

which are used by the transaction manager and resource manager.<br />

Table B-1 describes the functions used to work with XA transactions.<br />

Table B-1 TP/XA macro definitions<br />

Function Description<br />

xa_open() Initializes the resource manager (database server) for an XA<br />

transaction<br />

xa_close() Close a currently open resource manager<br />

xa_start() Starts an XA transaction<br />

xa_end() Dissociates from an XA transaction<br />

xa_rollback() Tells the resource manager to roll back an XA transaction<br />

xa_prepare() Asks the resource manager to prepare to commit an XA<br />

transaction<br />

xa_commit() Tells the resource manager to commit an XA transaction<br />

xa_recover() Obtains a list of XIDs that are currently in a prepared or<br />

heuristically completed state<br />

xa_forget() Tells the resource manager to forget a heuristically completed<br />

transaction<br />

xa_complete() Test Completion of asynchronous XA Request. This function is<br />

provided only for compliance with the X/Open XA Specification<br />

B.3 XA_TOOL ESQL/C sample<br />

Example B-1is a basic ESQL/C application which demonstrates how to use<br />

some of the TP/XA functions such as xa_prepare() and xa_rollback() to<br />

perform operations with a distributed transaction.<br />

Example B-1 The xa_tool.ec application<br />

/*************************************************************<br />

*<br />

* WARNING: USE OF THIS PROGRAM MAY HAVE UNDESIRABLE AFFECTS<br />

* TO THE DATABASE SERVER, INCLUDING DATA CORRUPTION!!<br />

*<br />

* TITLE: xa_tool.ec<br />

*<br />

Appendix B. Accommodating distributed transactions 471


* Compile with:<br />

* on UNIX systems:<br />

* esql -o xa_tool xa_tool.ec -lifxa<br />

* on Windows systems<br />

* esql xa_tool.ec<br />

*<br />

* This program will connect to a global transaction branch<br />

* and let the user manipulate the transaction.<br />

*<br />

* Usage:<br />

* xa_tool <br />

*<br />

* The fID, gtl, bql, and hex data should be provided from the<br />

* transaction desired to be manipulated. The information is<br />

* found by execution of the onstat -G command. Example output<br />

* of the onstat -G command:<br />

*<br />

* Global Transaction Identifiers<br />

* address flags fID gtl bql data<br />

* cb2a964 0x8442a 0 2 4 4D4E4F000000<br />

* 1 active, 128 total<br />

*<br />

* If transaction cb2a964 is the transaction that is desired<br />

* to be manipulated, then this program should be executed<br />

* with the following command:<br />

*<br />

* xa_tool 0 2 4 4D4E4F000000<br />

*<br />

*<br />

*************************************************************<br />

*/<br />

#include <br />

#include <br />

#include <br />

#include "xa.h"<br />

extern struct xa_switch_t infx_xa_switch;<br />

#define xa_open(info, rmid, flags) \<br />

((*infx_xa_switch.xa_open_entry)(info,rmid,flags))<br />

#define xa_start(gtrid,rmid, flags) \<br />

((*infx_xa_switch.xa_start_entry)(gtrid,rmid,flags))<br />

#define xa_rollback(gtrid,rmid, flags) \<br />

((*infx_xa_switch.xa_rollback_entry)(gtrid,rmid,flags))<br />

#define xa_commit(gtrid,rmid, flags) \<br />

((*infx_xa_switch.xa_commit_entry)(gtrid,rmid,flags))<br />

#define xa_rollback(gtrid,rmid, flags) \<br />

((*infx_xa_switch.xa_rollback_entry)(gtrid,rmid,flags))<br />

#define xa_end(gtrid,rmid, flags) \<br />

((*infx_xa_switch.xa_end_entry)(gtrid,rmid,flags))<br />

#define xa_prepare(gtrid,rmid, flags)\<br />

((*infx_xa_switch.xa_prepare_entry)(gtrid,rmid,flags))<br />

472 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


#define xa_close(info,rmid, flags)\<br />

((*infx_xa_switch.xa_close_entry)(info,rmid,flags))<br />

#define xa_forget(gtrid,rmid, flags)\<br />

((*infx_xa_switch.xa_forget_entry)(gtrid,rmid,flags))<br />

#define xa_recover(gtrid, count, rmid, flags)\<br />

((*infx_xa_switch.xa_recover_entry)(gtrid,count,rmid,flags))<br />

/* Doesn't matter what database is opened... */<br />

#define OPEN_DATABASE "sysmaster"<br />

/* Initialize the xid */<br />

void<br />

setup_myxid (XID *xid, int x_fID, int x_gtl, int x_bql, char* x_data)<br />

{<br />

int ii, c;<br />

xid->formatID = x_fID;<br />

xid->gtrid_length = x_gtl;<br />

xid->bqual_length = x_bql;<br />

}<br />

for(ii=0; iidata[ii] = (char) c;<br />

void xa_tool(XID *xid)<br />

{<br />

int choice = 0;<br />

int cc;<br />

while( choice != 'Q')<br />

{<br />

printf("\tP -- XA_PREPARE\n");<br />

printf("\tC -- XA_COMMIT\n");<br />

printf("\tR -- XA_ROLLBACK\n");<br />

printf("\tF -- XA_FORGET\n");<br />

printf("\tQ -- terminate program\n");<br />

printf("Enter Choice: ");<br />

choice = getchar();<br />

choice = toupper(choice);<br />

printf("%c\n\n", choice);<br />

switch(choice)<br />

{<br />

case 'P':<br />

printf("Executing XA_PREAPRE\n");<br />

if ((cc = xa_prepare(xid, 0, TMNOFLAGS)) != XA_OK)<br />

Appendix B. Accommodating distributed transactions 473


}<br />

{<br />

printf("XA_PREPARE failed with %d\n", cc);<br />

}<br />

else<br />

printf("... XA_PREPARE finished\n\n");<br />

break;<br />

case 'C':<br />

printf("Executing XA_COMMIT\n");<br />

if ((cc = xa_commit(xid, 0, TMNOFLAGS)) != XA_OK)<br />

{<br />

printf("XA_COMMIT failed with %d\n", cc);<br />

}<br />

else<br />

printf("... XA_COMMIT finished\n\n");<br />

break;<br />

case 'R':<br />

printf("Executing XA_ROLLBACK\n");<br />

if ((cc = xa_rollback(xid, 0, TMNOFLAGS)) != XA_OK)<br />

{<br />

printf("XA_ROLLBACK failed with %d\n", cc);<br />

}<br />

else<br />

printf("... XA_ROLLBACK finished\n\n");<br />

break;<br />

case 'F':<br />

printf("Executing XA_FORGET\n");<br />

if ((cc = xa_forget(xid, 0, TMNOFLAGS)) != XA_OK)<br />

{<br />

printf("XA_FORGET failed with %d\n", cc);<br />

}<br />

else<br />

printf("... XA_FORGET finished\n\n");<br />

break;<br />

case 'Q':<br />

break;<br />

default:<br />

printf("%c is not a valid option!\n\n", choice);<br />

choice = 0;<br />

}<br />

if (choice != 'Q') {<br />

choice = getchar();<br />

choice = 0;<br />

}<br />

}<br />

int main(int arc, char *argv[])<br />

{<br />

$int cc;<br />

XID xid;<br />

int xid_fID, xid_gtl, xid_bql;<br />

char xid_data[300];<br />

474 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


}<br />

if (arc != 5)<br />

{<br />

printf("Error: Incorrect number of parameters.\n");<br />

printf("Usage: %s \n", argv[0]);<br />

exit(2);<br />

}<br />

printf("\n\n");<br />

xid_fID = atoi(argv[1]);<br />

xid_gtl = atoi(argv[2]);<br />

xid_bql = atoi(argv[3]);<br />

strcpy(xid_data, argv[4]);<br />

/* setup the XID which is used to identify the transaction */<br />

setup_myxid(&xid, xid_fID, xid_gtl, xid_bql, xid_data);<br />

/* establish connection to the database */<br />

printf("Calling xa_open ... \n");<br />

if ((cc = xa_open(OPEN_DATABASE, 0, TMNOFLAGS)) != XA_OK)<br />

{<br />

printf("xa_open failed with %d, sqlcode = %d\n", cc, SQLCODE);<br />

exit(1);<br />

}<br />

else<br />

printf("... xa_open finished\n\n");<br />

/** This is for xa_tool... **/<br />

xa_tool(&xid);<br />

/* close the connection */<br />

printf("Calling xa_close...\n");<br />

if ((cc = xa_close("", 0, TMNOFLAGS)) != XA_OK)<br />

{<br />

printf("xa_close failed with %d\n", cc);<br />

exit(1);<br />

}<br />

else<br />

printf("... xa_close finished\n\n");<br />

You also can use the xa_tool example to complete unresolved transactions left<br />

in the database server. Local transactions are rolled back automatically by the<br />

<strong>Informix</strong> database server if the connection between the client application and the<br />

database server is lost. This roll back occurs because the database server is in<br />

direct control of the transaction.<br />

Appendix B. Accommodating distributed transactions 475


When using distributed transactions, the database server cannot resolved a<br />

transaction automatically. The Transaction Manager is the only process in charge<br />

of committing or aborting the global transaction. Thus, if there is a<br />

communication error or a failure within the resource manager, there is a chance<br />

of leaving unresolved transactions in the database server. These transactions<br />

can be resolved using the xa_commit(), xa_rollback(), and xa_forget()<br />

functions.<br />

Example B-2 shows how to compile and use the xa_tool.ec program to rollback<br />

an XA transaction left in the <strong>Informix</strong> database server.<br />

Example B-2 The xa_tool.ec program output<br />

D:\Infx\ids1150>onstat -G<br />

<strong>IBM</strong> <strong>Informix</strong> Dynamic Server Version 11.50.FC6 -- On-Line -- Up 05:04:17<br />

Global Transaction Identifiers<br />

address flags isol timeout fID gtl bql data<br />

83246d88 -L--G COMMIT 0 0 2 4 4D4E4F000000<br />

1 active, 128 total<br />

D:\Infx\ids1150><br />

C:\work>esql -nologo xa_tool.ec<br />

<strong>IBM</strong> <strong>Informix</strong> CSDK Version 3.50, <strong>IBM</strong> <strong>Informix</strong>-ESQL Version 3.50.TC7<br />

xa_tool.c ...<br />

C:\work>xa_tool 0 2 4 4D4E4F000000<br />

Calling xa_open ...<br />

... xa_open finished<br />

P -- XA_PREPARE<br />

C -- XA_COMMIT<br />

R -- XA_ROLLBACK<br />

F -- XA_FORGET<br />

Q -- terminate program<br />

Enter Choice: R<br />

R<br />

Executing XA_ROLLBACK<br />

... XA_ROLLBACK finished<br />

P -- XA_PREPARE<br />

C -- XA_COMMIT<br />

R -- XA_ROLLBACK<br />

F -- XA_FORGET<br />

Q -- terminate program<br />

476 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Enter Choice: q<br />

Q<br />

Calling xa_close...<br />

... xa_close finished<br />

C:\work><br />

For more information related to the TP/XA library, refer to the TP/XA Transaction<br />

Manager XA Interface Library User Manual at:<br />

http://publibfp.boulder.ibm.com/epubs/pdf/5193.pdf<br />

Appendix B. Accommodating distributed transactions 477


478 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Related publications<br />

We consider the publications that we list in this section particularly suitable for a<br />

more detailed discussion of the topics that we cover in this book.<br />

<strong>IBM</strong> <strong>Redbooks</strong> publications<br />

For information about ordering these publications, see “How to get <strong>IBM</strong><br />

<strong>Redbooks</strong> publications” on page 480. Note that some of the documents that we<br />

reference here might be available in softcopy only.<br />

► Embedding <strong>Informix</strong> Dynamic Server: An Introduction, SG24-7666<br />

Other publications<br />

The following publications are also relevant as further information sources:<br />

► <strong>IBM</strong> <strong>Informix</strong> Dynamic Server Administrator’s Guide, v11.50, SC23-7748<br />

► <strong>IBM</strong> <strong>Informix</strong> Guide to SQL: Reference, v11.50, SC23-7750<br />

► Embedded SQLJ User’s Guide, Version 2.90, G251-2278<br />

► <strong>IBM</strong> <strong>Informix</strong> Storage Manager Administrator’s Guide, v2.2, G229-6388<br />

► <strong>IBM</strong> <strong>Informix</strong> Security Guide, v11.50, SC23-7754<br />

► <strong>IBM</strong> <strong>Informix</strong> GLS User’s Guide, G229-6373<br />

► <strong>IBM</strong> <strong>Informix</strong> Dynamic Server Administrator’s Reference, SC23-7749<br />

► <strong>IBM</strong> <strong>Informix</strong> Guide to SQL: Syntax, v11.50, SC23-7751<br />

► <strong>IBM</strong> <strong>Informix</strong> Guide to SQL: Tutorial, G229-6427<br />

► <strong>IBM</strong> <strong>Informix</strong> Dynamic Server Performance Guide, v11.50, SC23-7757<br />

► <strong>IBM</strong> <strong>Informix</strong> High-Performance Loader User’s Guide, v11.50, SC23-9433<br />

► <strong>IBM</strong> <strong>Informix</strong> Migration Guide, SC23-7758<br />

► <strong>IBM</strong> <strong>Informix</strong> JDBC Driver Programmer’s Guide, SC23-9421<br />

► <strong>IBM</strong> <strong>Informix</strong> ESQL/C Programmer’s Manual, v3.50, SC23-9420<br />

► <strong>IBM</strong> Data Server Provider for .NET Programmer’s Guide, SC23-9848<br />

© Copyright <strong>IBM</strong> Corp. 2010. All rights reserved. 479


Online resources<br />

► <strong>IBM</strong> <strong>Informix</strong> Dynamic Server Installation Guide for UNIX, Linux, and Mac OS<br />

X, GC23-7752<br />

► <strong>IBM</strong> <strong>Informix</strong> DB-Access User’s Guide, SC23-9430<br />

► <strong>IBM</strong> <strong>Informix</strong> ODBC Driver Programmer’s Manual, SC23-9423<br />

► <strong>IBM</strong> <strong>Informix</strong> Dynamic Server Installation Guide for Windows, GC23-7753<br />

► Guide to <strong>Informix</strong> MaxConnect, Version 1.1, G251-0577<br />

► <strong>IBM</strong> <strong>Informix</strong> Backup and Restore Guide, v11.50, SC23-7756<br />

► <strong>IBM</strong> <strong>Informix</strong> Dynamic Server Enterprise Replication Guide, v11.50,<br />

SC23-7755<br />

► “Expand transaction capabilities with savepoints in <strong>Informix</strong> Dynamic Server”<br />

by Uday B. Kale in <strong>IBM</strong> developerWorks, 26 March 2009:<br />

http://www.ibm.com/developerworks/data/library/techarticle/dm-0903idssavepo<br />

ints/index.html<br />

The following website is also relevant as further information sources:<br />

► <strong>IBM</strong> <strong>Informix</strong> Dynamic Server v11.50 Information Center:<br />

http://publib.boulder.ibm.com/infocenter/idshelp/v115/index.jsp<br />

How to get <strong>IBM</strong> <strong>Redbooks</strong> publications<br />

Help from <strong>IBM</strong><br />

You can search for, view, or download <strong>Redbooks</strong>, Redpapers, Technotes, draft<br />

publications and Additional materials, as well as order hardcopy <strong>Redbooks</strong><br />

publications, at this website:<br />

ibm.com/redbooks<br />

<strong>IBM</strong> Support and downloads<br />

ibm.com/support<br />

<strong>IBM</strong> Global Services<br />

ibm.com/services<br />

480 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


Index<br />

Symbols<br />

.4cf extension 418<br />

.ec 128<br />

.ecp 128<br />

.NET connection string attributes<br />

Client_Locale 259<br />

Connection Lifetime 259<br />

DB_LOCALE 259<br />

DELIMIDENT 259<br />

Enlist 259<br />

Fetch Buffer Size 260<br />

Host 260<br />

Max Pool Size 260<br />

OPTOFC 260<br />

Packet Size 260<br />

Pooling 260<br />

PWD 260<br />

Skip Parsing 260<br />

UserDefinedTypeFormat 260<br />

XCL 260<br />

Numerics<br />

4GL 15<br />

A<br />

access method 333<br />

ACE Report Writer 9<br />

ad hoc queries 7<br />

adapter script 370<br />

ADO interface<br />

IAccessor 220<br />

IColumnsInfo 220<br />

ICommand 220<br />

IDBCreateCommand 220<br />

IDBCreateSession 220<br />

IDBDataSourceAdmin 220<br />

IDBProperties 220<br />

IErrorLookup 220<br />

IGetDataSource 220<br />

IRowsetIdentity 220<br />

ISessionProperties 220<br />

ITransaction 220<br />

ADO object 217<br />

adOpenDynamic cursor 224<br />

adOpenForwardOnly cursor 224<br />

adOpenKeyset cursor 224<br />

adOpenStatic cursor 224<br />

annotation 211<br />

ANSI serializable 448<br />

antlr-2.7.6.jar 193<br />

Apache Web Server 295, 297, 299, 303<br />

application programming interface 14<br />

application-programming interface 35<br />

attribute 190<br />

authorized user 5<br />

AutoCommit mode 171<br />

AXIS2C_HOME 403<br />

B<br />

backup 330<br />

begin work 140<br />

BeginTransaction method 274<br />

BeginTransaction() 265<br />

bigint data type 80<br />

bigserial data type 80<br />

binary import routine 333<br />

binary large object 450<br />

binary receive routine 333<br />

binary send routine 333<br />

bind parameter 308<br />

bladelet 359<br />

BLOB 80, 178, 180, 232, 276, 314, 450<br />

BOOLEAN 80<br />

Boolean UDR 333<br />

buffered logging 20<br />

built-in data type 330<br />

bulk load 9<br />

byte 80<br />

byte column 7<br />

byte-range lock 443<br />

byte-range locking 444<br />

C<br />

call level interface 15<br />

CallableStatement object 173<br />

© Copyright <strong>IBM</strong> Corp. 2010. All rights reserved. 481


cast function 332<br />

cast support function 348<br />

certified file 183<br />

character large object 350, 450<br />

chunk 450<br />

CLASSPATH environment variable 157<br />

classpath environment variable 52, 195<br />

CLI 15<br />

CLI parameters<br />

database 73<br />

hostname 73<br />

port 73<br />

protocol 73<br />

client connectivity 7<br />

client locale 62<br />

Client SDK 9, 11, 15, 21–22, 29, 34–38, 42, 58–59,<br />

65–66, 70, 75, 117, 125, 127, 151, 156, 216–217,<br />

222, 250, 254, 256, 293, 296, 328, 364–365, 435,<br />

470<br />

client_locale environment variable 150<br />

CLOB 80, 178–180, 233, 276, 278, 450<br />

collection 10<br />

collection data type 145, 348<br />

collection variable 145<br />

commands<br />

esql 14, 125–128, 130<br />

commit work 140<br />

committed read 448<br />

compiler 130<br />

complex data type 335<br />

component object model 216<br />

concentrator 5<br />

concurrency 438<br />

concurrent query 19<br />

concurrent session 5<br />

connection management 192<br />

connection object 171<br />

connection pooling 155<br />

connection string 257<br />

connection string attribute 221<br />

connection_adapters directory 370<br />

connectionstring property 264<br />

constraint 190<br />

controller 363<br />

convention over configuration 384<br />

cost factor 333<br />

cost function 332<br />

cursor behavior 62<br />

cursor stability 447–448<br />

482 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong><br />

customer object 190<br />

customized routine 330<br />

D<br />

data access layer 190<br />

Data accessibility 143<br />

data consistency 8<br />

data consumer 14<br />

Data Definition Language (DDL) 134, 168, 198,<br />

294, 310, 391<br />

data logging 143<br />

data management 7<br />

Data Manipulation Language (DML) 198<br />

data mart 7<br />

data provider 14, 254<br />

data query language 190<br />

data source 155<br />

data source name 61<br />

data type extension 330<br />

data warehouse 7<br />

database driver 44<br />

database extension 330<br />

database instance name 449<br />

database locale 62<br />

database lock 442<br />

database operation 76<br />

datetime 80<br />

db_locale 63<br />

db_locale environment variable 150<br />

db2cli.ini 73<br />

db2jcc.jar 52, 194<br />

db2jcc4.jar 52<br />

db2sdriver.cfg configuration file 261<br />

DbDataReader method 269<br />

dbschema utility 395<br />

dbspace 450<br />

dbspacetemp parameter 450<br />

deadlock 446<br />

deadlock_timeout parameter 455<br />

def_table_lockmode parameter 441, 454<br />

delete 76<br />

dependency list 337<br />

directives parameter 456<br />

dirty read isolation 445<br />

discarded-logging 194<br />

display environment variable 38<br />

distinct 10, 80<br />

distinct data type 330, 335


distributed transaction 20, 93, 447, 470<br />

distributed transactions 154<br />

distribution statistic 333<br />

dmg format 26<br />

dom4j-1.6.1.jar 194<br />

DRDA protocol 156<br />

DRDADEBUG trace 188<br />

driver manager 11<br />

driver package 44<br />

drsoctcp 31<br />

dyld_library_path environment variable 131<br />

dynamic link library 350<br />

dynamic sql 136<br />

dynamic_logs configuration parameter 460<br />

E<br />

editions 2<br />

element type 145<br />

encryption 182<br />

end-user routine 332<br />

environment variable<br />

ld_library_path 131–132, 353, 365<br />

lib 132<br />

libpath 131<br />

shlib_path 131, 365<br />

esql command 14, 125–128, 130<br />

exception 206<br />

exclusive lock 439<br />

exclusive mode 438–439<br />

execute into command 134<br />

executeQuery() 168<br />

executeUpdate() 168<br />

export routine 333<br />

F<br />

fast data loading 7<br />

fetch buffer size 62<br />

filetoblob 144<br />

finderr utility 14, 37, 126<br />

flat file 9<br />

flow-control extension 331<br />

functional test file 16<br />

G<br />

gem utility 370<br />

generator element 201<br />

get diagnostics statement 149<br />

get() method 206<br />

GetIfxMonthSpan 270<br />

global transaction 470<br />

global transactions 447<br />

H<br />

header file 16, 471<br />

Hibernate dialect 196<br />

Hibernate service 195<br />

Hibernate session instance 203<br />

hibernate.cfg.xml 195<br />

hibernate.property 195<br />

hibernate3.jar 193<br />

hibernate-jpa-2.0-api-1.0.0.Final.jar 193<br />

HibernateUtil class 202<br />

high availability clustering 3<br />

high availability replication 19<br />

host name 61<br />

host variable 146<br />

HQL criteria 209<br />

HQL restriction 209<br />

HTTP link 422<br />

I<br />

i4gl_func 408<br />

<strong>IBM</strong>.Data.DB2 255<br />

<strong>IBM</strong>.Data.<strong>Informix</strong> 255<br />

ICommand interface 225<br />

idssecuritylabel 80<br />

ifx_lo_lock() 444<br />

ifx_lo_open 82<br />

ifx_lo_t 142<br />

ifx_lo_write 82<br />

IfxBlob GetIfxBlob() 265, 269<br />

IfxClob GetIfxClob() 265, 269<br />

IfxCommand 269<br />

IfxCommand class 266<br />

IfxCommand CreateCommand() 265<br />

IfxCommand method 272<br />

IfxConnection class 265<br />

IfxConnection object 274<br />

IfxDataReader 269<br />

IfxDataReader ExecuteReader() 266<br />

IfxDateTime class 283<br />

IfxDateTime GetIfxDateTime() 269<br />

IfxDateTime public method 284<br />

IfxDecimal GetIfxDecimal 269<br />

IfxDecimal object 287<br />

Index 483


IfxDecimal public method 287<br />

ifxdotnettrace variable 293<br />

IfxError 271<br />

IfxException class 271<br />

ifxjdbc.jar 194<br />

IfxMonthSpan 270<br />

ifxoledbc COM class ID 216<br />

ifxoledbctrace environment variable 248<br />

IfxParameter 273<br />

IfxParameter CreateParameter() 266<br />

IfxParameterCollection object 272<br />

IfxTimeSpan GetIfxTimeSpan 270<br />

IfxTransaction 265<br />

IfxTransaction object 274<br />

iifxoledbc.dll 216<br />

iLogin utility 37, 117, 126, 217, 290<br />

Implict invocation 334<br />

incoming parameter 337<br />

<strong>Informix</strong> classes 12<br />

<strong>Informix</strong> Client Software Development Kit , see Client<br />

SDK<br />

<strong>Informix</strong> Connect 9, 34–35, 328<br />

<strong>Informix</strong> OLE DB Provider 37<br />

informixc.so 365<br />

informixdir environment variable 21, 59, 127<br />

informixserver 353<br />

informixserver environment variable 133, 365<br />

informix-sqli 164<br />

inheritance 190<br />

insert 76<br />

installation directory 21<br />

installation ini file 27<br />

installIDSDriver command 44<br />

int8 80<br />

intent locks 439<br />

intent-exclusive lock 439<br />

intent-shared 439<br />

interval day 80<br />

interval day to hour 81<br />

interval day to minute 81<br />

interval day to second 81<br />

interval hour 81<br />

interval hour to minute 81<br />

interval hour to second 81<br />

interval minute 81<br />

interval minute to second 81<br />

interval month 81<br />

interval second 81<br />

interval year 81<br />

484 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong><br />

interval year to month 81<br />

Isolation Level 62, 70<br />

isolation level 20, 438, 447, 463<br />

ISupportErrorInfo interface 234<br />

Iterator function 332<br />

J<br />

Java annotation 191<br />

Java archive file 341<br />

Java class file 195<br />

Java compiler 195<br />

Java interface 12<br />

Java library 193, 195<br />

Java Naming and Directory Interface 166<br />

java property 195<br />

Java runtime 166<br />

Java virtual machine (JVM) 37, 157, 195, 340, 457<br />

java_bindir environment variable 341<br />

java_home environment variable 341<br />

java_root environment variable 341<br />

java.io.Serializable 12<br />

java.lang.object 13<br />

java.sql.ParameterMetaData 12<br />

javassist-3.9.0.GA.jar 194<br />

javax.sql extensions 163<br />

javax.sql.ConnectionEventListener 12<br />

javax.sql.ConnectionPoolDataSource 12<br />

javax.sql.DataSource 12<br />

javax.sql.PooledConnection 12<br />

javax.sql.XADataSource 12<br />

JDBC API interfaces 155<br />

JDBC class 155<br />

JDBC method 155<br />

JDBC standard 8<br />

jjdk_home environment variable 341<br />

JNDI, see Java Naming and Directory Interface.<br />

jre_home environment variable 341<br />

jta-1.1.jar 194<br />

JVM 37, 157, 195, 340, 457<br />

jvp.log 347<br />

K<br />

key 441<br />

Key lock 442<br />

keystore file 183<br />

key-value locking 442


L<br />

library file 126<br />

licensing metric 5<br />

limited use socket 5<br />

list 145<br />

load() 206<br />

load() method 206<br />

loc_t 142<br />

lock 438<br />

lock duration 440<br />

lock list 446<br />

lock mode page 441<br />

locks parameter 453<br />

logbuff 458<br />

logfiles parameter 458<br />

logging mode 463<br />

logical device 8<br />

logical volume manager 8<br />

logical-log buffer 20, 458<br />

logical-log record 20<br />

long identifier 10<br />

loopback connection 8<br />

LPAR 5<br />

ltxehwm parameter 460<br />

ltxhwm parameter 460<br />

LU socket 6<br />

lvarchar 81<br />

M<br />

make file 16<br />

mapping 191<br />

max_pdqpriority parameter 456<br />

MaxBytes 277<br />

memory addressability 2<br />

messages files 16<br />

method 190<br />

method properties<br />

position 277<br />

ReferenceCount 277<br />

mi_lo_lock() 444<br />

migration 394<br />

model 363<br />

module 16<br />

money 81<br />

msgpath file 347<br />

multimedia capability 8<br />

multiplexed connection 18–19<br />

multiplexer 5<br />

multiprocessor parameter 452<br />

multiset 145<br />

mutexes 18<br />

mutually exclusive 18<br />

N<br />

native-protocol 53<br />

nchar 81<br />

negator function 332<br />

nettype parameter 453<br />

network connection 18<br />

nvarchar 81<br />

O<br />

obdcinst.ini file 66<br />

object ExecuteScalar() 266<br />

object file 126<br />

object processing 191<br />

object-orientated programming 190<br />

object-relational mapper 363<br />

ODBC data source 60<br />

ODBC driver 59<br />

ODBC driver configuration files<br />

odbc 66<br />

odbcinst.ini 66<br />

sqlhosts 66<br />

ODBC libraries<br />

libifcli.a or libcli.a 66<br />

libifcli.so or iclis09b.so 66<br />

libifdrm.so or idmrs09a.so 66<br />

libthcli.a 66<br />

libthcli.so or iclit09b.so 66<br />

odbc.ini file 66<br />

ODBC/CLI driver 45<br />

OLE DB consumer 216<br />

OLE DB provider 216<br />

OLE DB providers<br />

DBTYPE_DBDATE 223<br />

DBTYPE_DBTIME 223<br />

DBTYPE_DBTIMESTAMP 224<br />

olsoctcp 31<br />

onconfig file 341<br />

onconfig parameter<br />

dbservername 449<br />

jvpclasspath 341<br />

jvphome 341<br />

jvpjavahome 341<br />

jvpjavalib 341<br />

Index 485


jvpjavavm 341<br />

jvplog 347<br />

jvplogfile 341<br />

jvppropfile 341<br />

oninit 18<br />

opaque 10<br />

opaque data type 330, 332, 335<br />

OpenAdmin Tool (OAT) 9, 17, 295, 297–299<br />

operator 333<br />

operator function 332<br />

operator-class function 332<br />

optcompind parameter 19, 455<br />

OUT parameter 173<br />

outgoing parameter 337<br />

P<br />

packaging file 16<br />

page level lock 441<br />

page locking 442<br />

parallel subquery 19<br />

parallelism 19<br />

parallelizable UDR 332<br />

parsing 139<br />

partition 5<br />

path environment variable 127<br />

path variable 59<br />

persistence 191, 363<br />

persistence data 190<br />

persistence framework 190<br />

persistence object 199<br />

persistent connectivity layer 5<br />

phantom read 448<br />

physbuff configuration parameter 458<br />

physical log image 20<br />

physical-log buffer 458<br />

pipe connection 18<br />

placeholder 88, 308<br />

Plain Old Java Objects (POJO) 199<br />

POJO, see Plain Old Java Object (POJO).<br />

polymorphism 190<br />

precedence hierarchy 337<br />

prepare statement 20<br />

prepared statement 175<br />

PreparedStatement object 169<br />

preprocessor 10<br />

primary key 201<br />

priority aging 462<br />

process memory 347<br />

486 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong><br />

processor affinity 462<br />

processor value unit 5<br />

processor-based pricing 5<br />

program_design_dbs 404<br />

Project Object Model (POM) 194<br />

public method 265<br />

publish 402<br />

pure-Java driver 53<br />

pure-Java drivers 154<br />

Q<br />

query optimization 139<br />

query plan 334<br />

query-intensive analytical application 7<br />

R<br />

rails command 392<br />

recovery 330<br />

<strong>Redbooks</strong> Web site 480<br />

Contact us xiv<br />

regsvr32 tool 245<br />

repeatable read 438, 448<br />

resource manager 470<br />

result set 173<br />

rollback 21, 330, 447<br />

rollback method 274<br />

rollback work statement 140<br />

row and collection functions<br />

ifx_rc_count 106<br />

ifx_rc_create 106<br />

ifx_rc_delete 106<br />

ifx_rc_describe 106<br />

ifx_rc_fetch 106<br />

ifx_rc_free 106<br />

ifx_rc_insert 106<br />

ifx_rc_isnull 106<br />

ifx_rc_setnull 106<br />

ifx_rc_typespec 106<br />

ifx_rc_update 106<br />

rowset 229<br />

R-tree 358<br />

Ruby/<strong>Informix</strong> Adapter 384<br />

S<br />

sbspacename parameter 451<br />

sbspacetemp parameter 451<br />

scaffold command 393


scalability 6, 330<br />

scalable data warehousing 7<br />

sdk_home environment variable 341<br />

secure sockets layer 19<br />

secured connection method 19<br />

select 76<br />

selectivity function 332<br />

serial8 81<br />

server definition 31<br />

server instance 18<br />

server name 61<br />

server_locale environment variable 150<br />

service-oriented architecture 400<br />

Session.createCiteria() 206<br />

Session.createQuery() 206<br />

Session.delete() method 210<br />

Session.get() 205<br />

Session.load() 205<br />

Session.save() 205<br />

SessionFactory class 202<br />

set 145<br />

set isolation 438<br />

set lock mode 438<br />

set transaction 438<br />

setnet32.exe utility 21, 29–31, 42, 61, 66, 117, 126,<br />

222, 245, 247, 449<br />

shared library 67<br />

shared lock 439<br />

shared memory 18, 20<br />

simple large objects 314<br />

Simple Logging Facade for Java (SLF4J) 194–195<br />

simple-logging 194<br />

single install 5<br />

single password CSM 19<br />

single-user product version 8<br />

SLF4J see Simple Logging Facade for Java.<br />

slf4j-api-1.5.8.jar 194<br />

slob method 377<br />

smart blob space 95, 143, 178<br />

smart lager objects 179<br />

smart large object 10<br />

smart large object functions<br />

ifx_lo_alter 97<br />

ifx_lo_close 97<br />

ifx_lo_col_info 97<br />

ifx_lo_create 97<br />

ifx_lo_def_create_spec 97<br />

ifx_lo_open 97<br />

ifx_lo_read 97<br />

ifx_lo_readwithseek 97<br />

ifx_lo_seek 97<br />

ifx_lo_specget_estbytes 97<br />

ifx_lo_specget_extsz 97<br />

ifx_lo_specget_flags 97<br />

ifx_lo_specget_maxbytes 97<br />

ifx_lo_specget_sbspace 97<br />

ifx_lo_specset_estbytes 97<br />

ifx_lo_specset_extsz 97<br />

ifx_lo_specset_flags 97<br />

ifx_lo_specset_maxbytes 97<br />

ifx_lo_specset_sbspace 98<br />

ifx_lo_stat 98<br />

ifx_lo_stat_atime 98<br />

ifx_lo_stat_cspec 98<br />

ifx_lo_stat_ctime 98<br />

ifx_lo_stat_refcnt 98<br />

ifx_lo_stat_size 98<br />

ifx_lo_tell 98<br />

ifx_lo_truncate 98<br />

ifx_lo_write 98<br />

ifx_lo_writewithseek 98<br />

smart large objects 178–180, 182, 232, 276, 278,<br />

280–281, 315, 377, 383<br />

soa_err_log log file 404<br />

SOAP 422<br />

socket connection 18<br />

source file 126<br />

source files 16<br />

SQL communications area 148<br />

SQL dialect 196<br />

SQL optimization 197<br />

sql_autocommit_off 91<br />

sql_bigint 80–81<br />

sql_bit 80<br />

sql_c_binary 80<br />

sql_ifmx_udt_blob 80<br />

sql_ifmx_udt_clob 80<br />

sql_infx_attr_lo_automatic 104<br />

sql_infx_bigint 80<br />

sql_infx_udt_fixed 80–81<br />

sql_infx_udt_varying 81<br />

sql_integer 81<br />

sql_interval_day 80<br />

sql_interval_hour 81<br />

sql_interval_month 81<br />

sql_interval_second 81<br />

sql_interval_year 81<br />

sql_longbinary 104<br />

Index 487


sql_longvarbinary 80, 96<br />

sql_longvarchar 81, 96, 104<br />

sql_timestamp 80<br />

sqlca 148<br />

sqlexec 30<br />

SQLExecDirect() 82<br />

SQLExecDirect() function 82<br />

SQLGetDiagRec() 84<br />

sqlhosts file 21, 27–29, 33–34, 42, 66, 127, 157,<br />

365, 449, 453<br />

sqlidebug trace 119, 151<br />

sqliprt tool 120<br />

sqlj.zip 52<br />

sqlj4.zip 52<br />

SQLSetConnectAttr() 91<br />

SQLSTATE 149<br />

stacksize parameter 454<br />

standard data type 330<br />

startup cost 337<br />

Statement object 168<br />

static SQL statement 136<br />

statistics function 332<br />

stored procedure 133<br />

structured query language 154<br />

subscribe 402<br />

sysdistrib system catalog table 451<br />

syslangauth table 331<br />

syspgm4gl 406<br />

sysprocauth table 331<br />

sysprocbody table 331<br />

sysprocedures table 331<br />

sysroutinelangs table 331<br />

syssbspacename parameter 451<br />

system catalog table 331<br />

T<br />

table space 450<br />

tar file 26<br />

target_dir 408<br />

target_file 408<br />

temporary space 450<br />

temporary table 450<br />

text export routine 333<br />

text import routine 333<br />

Text input routine 333<br />

text output routine 333<br />

third-party vendor 11<br />

thread 439<br />

488 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong><br />

TimeSpan GetTimeSpan() 269<br />

transaction 470<br />

transaction control 330<br />

transaction management 192<br />

transient 210<br />

transient object 210<br />

translation library 62<br />

translation option 62<br />

Type 4 154<br />

type constructor 145<br />

U<br />

UDR 173, 330–332, 334, 336–337, 340, 343, 345,<br />

347–348, 352, 451<br />

UDRManager 13<br />

UDRMetaData 13<br />

UDTManager 13<br />

UDTMetaData 13<br />

uncommitted data 448<br />

unit of work 470<br />

unresolved transaction 475<br />

updatable lock 439<br />

update 76<br />

uselastcommitted 441, 454<br />

user thread 464<br />

user-defined aggregate 332<br />

user-defined data type 335<br />

user-defined routine , see UDR.<br />

utilities<br />

finderr 14, 37, 126<br />

setnet32.exe 21, 29–31, 42, 61, 66, 117, 126,<br />

222, 245, 247, 449<br />

V<br />

validity checking 139<br />

version numbering convention 2<br />

virtual processor 18<br />

virtual server 5<br />

virtual-processor process 352<br />

VMB character 62<br />

void Prepare() 266<br />

vpclass parameter 452, 461<br />

W<br />

w4glc parameters<br />

check 405<br />

compile 405


deploy 405<br />

force 405<br />

generate 405<br />

help 405<br />

keep 405<br />

package 405<br />

silent 405<br />

version 405<br />

web server 363<br />

web service description language 407<br />

web service function 426<br />

workload 3<br />

ws_func 408<br />

WSDL Path 426<br />

wsdl_path 407<br />

X<br />

xa.h 471<br />

XML configuration file 190<br />

XML formatted file 195<br />

XML mapping file 197<br />

XML-based protocol 422<br />

Index 489


490 <strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


(1.0” spine)<br />

0.875”1.498”<br />

460 788 pages<br />

<strong>IBM</strong> <strong>Informix</strong> Developer’s <strong>Handbook</strong>


<strong>IBM</strong> <strong>Informix</strong><br />

Developer’s <strong>Handbook</strong><br />

Learn application<br />

development with<br />

supported APIs,<br />

drivers, and interfaces<br />

Understand <strong>Informix</strong><br />

supported<br />

programming<br />

environments<br />

Follow practical<br />

examples to develop<br />

an <strong>Informix</strong><br />

application<br />

SG24-7884-00 ISBN 0738434701<br />

Back cover<br />

<strong>IBM</strong> <strong>Informix</strong> is a low-administration, easy-to-use, and embeddable<br />

database that is ideal for application development. It supports a<br />

wide range of development platforms, such as Java, .NET, PHP, and<br />

web services, enabling developers to build database applications in<br />

the language of their choice. <strong>Informix</strong> is designed to handle RDBMS<br />

data and XML without modification and can be extended easily to<br />

handle new data sets.<br />

This <strong>IBM</strong> <strong>Redbooks</strong> publication provides fundamentals of <strong>Informix</strong><br />

application development. It covers the <strong>Informix</strong> Client installation<br />

and configuration for application development environments. It<br />

discusses the skills and techniques for building <strong>Informix</strong><br />

applications with Java, ESQL/C, OLE DB, .NET, PHP, Ruby on Rails,<br />

DataBlade, and Hibernate.<br />

The book uses code examples to demonstrate how to develop an<br />

<strong>Informix</strong> application with various drivers, APIs, and interfaces. It<br />

also provides application development troubleshooting and<br />

considerations for performance.<br />

This book is intended for developers who use <strong>IBM</strong> <strong>Informix</strong> for<br />

application development. Although some of the topics that we<br />

discuss are highly technical, the information in the book might also<br />

be helpful for managers or database administrators who are<br />

looking to better understand their <strong>Informix</strong> development<br />

environment.<br />

INTERNATIONAL<br />

TECHNICAL<br />

SUPPORT<br />

ORGANIZATION<br />

®<br />

BUILDING TECHNICAL<br />

INFORMATION BASED ON<br />

PRACTICAL EXPERIENCE<br />

<strong>IBM</strong> <strong>Redbooks</strong> are developed by<br />

the <strong>IBM</strong> International Technical<br />

Support Organization. Experts<br />

from <strong>IBM</strong>, Customers and<br />

Partners from around the world<br />

create timely technical<br />

information based on realistic<br />

scenarios. Specific<br />

recommendations are provided<br />

to help you implement IT<br />

solutions more effectively in<br />

your environment.<br />

For more information:<br />

ibm.com/redbooks<br />

®

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!