IBM Informix Developer’s Handbook Front cover


Add to my manuals
498 Pages

advertisement

IBM Informix Developer’s Handbook Front cover | Manualzz

Front cover

Draft Document for Review August 23, 2010 10:53 am SG24-7884-00

IBM Informix

Developer’s Handbook

Learn application development with supported APIs, drivers, and interfaces

Understand Informix supported programming environments

Practical examples

Whei-Jen Chen

David Jay

Javier Sagrera

Krishna Doddi

Manoj Ghogale

ibm.com/redbooks

Draft Document for Review August 23, 2010 10:53 am

International Technical Support Organization

IBM Informix Developer’s Handbook

October 2010

7884edno.fm

SG24-7884-00

7884edno.fm

Draft Document for Review August 23, 2010 10:53 am

Note: Before using this information and the product it supports, read the information in

“Notices” on page ix.

First Edition (October 2010)

This edition applies to IBM Informix Version 11.5.

This document created or updated on August 23, 2010.

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

Schedule Contract with IBM Corp.

7884TOC.fm

Draft Document for Review August 23, 2010 10:53 am

Contents

Notices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ix

Trademarks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . x

Preface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xi

The team who wrote this book . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xi

Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xii

Become a published author . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xiii

Comments welcome . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xiii

Chapter 1. Introduction to IBM Informix . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1

1.1 Server options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2

1.1.1 Informix servers. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2

1.2 Informix tools for developers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7

1.2.1 I-Connect. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8

1.2.2 Client SDK. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8

1.2.3 4GL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13

1.2.4 Ruby on Rails . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13

1.2.5 Informix DataBlade Developers Kit . . . . . . . . . . . . . . . . . . . . . . . . . . 14

1.2.6 Informix Spatial DataBlade . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14

1.2.7 PHP on Informix . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15

1.3 Informix overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

1.3.1 Architecture overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

1.3.2 Informix developer environment . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19

1.3.3 Informix capabilities. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20

Chapter 2. Setting up an Informix development environment . . . . . . . . . 23

2.1 Informix deployment and setup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24

2.1.1 Installation planning . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24

2.1.2 Informix Server installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24

2.1.3 Configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25

2.2 Client setup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31

2.2.1 Client options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31

2.2.2 Setting up IBM Informix Client Software Development Kit . . . . . . . . 33

2.2.3 Setting up IBM Data Server drivers. . . . . . . . . . . . . . . . . . . . . . . . . . 40

2.2.4 Setting up Informix JDBC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48

Chapter 3. Working with the ODBC driver . . . . . . . . . . . . . . . . . . . . . . . . . 53

3.1 ODBC and Informix . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54

3.2 Setup and configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54

© Copyright IBM Corp. 2010. All rights reserved.

iii

7884TOC.fm

Draft Document for Review August 23, 2010 10:53 am

3.2.1 IBM Informix ODBC Driver . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54

3.2.2 IBM Data Server Driver for ODBC and CLI . . . . . . . . . . . . . . . . . . . . 66

3.2.3 Verifying connectivity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70

3.3 Developing an ODBC application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72

3.3.1 Connecting to the database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72

3.3.2 Type mapping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76

3.3.3 Performing database operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79

3.3.4 Handling special data types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92

3.3.5 Error handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108

3.3.6 Troubleshooting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113

Chapter 4. Working with ESQL/C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121

4.1 Informix ESQL/C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122

4.2 Setup and configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123

4.3 Developing an ESQL/C application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124

4.3.1 Creating an ESQL/C application . . . . . . . . . . . . . . . . . . . . . . . . . . . 124

4.3.2 Performing database operations . . . . . . . . . . . . . . . . . . . . . . . . . . . 128

4.3.3 Data types mapping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137

4.3.4 Handling special data types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138

4.3.5 Exception handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143

4.3.6 Troubleshooting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145

Chapter 5. Working with the JDBC drivers . . . . . . . . . . . . . . . . . . . . . . . . 149

5.1 JDBC drivers for an Informix database . . . . . . . . . . . . . . . . . . . . . . . . . . 150

5.1.1 JDBC drivers for Informix database . . . . . . . . . . . . . . . . . . . . . . . . 150

5.2 Setup and configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152

5.2.1 Configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152

5.2.2 Verify Connectivity with the Informix JDBC driver . . . . . . . . . . . . . . 153

5.2.3 Verify Connectivity with the Data Server Driver . . . . . . . . . . . . . . . 155

5.3 JDBC type mapping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157

5.4 Performing database operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158

5.4.1 Connection to the database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158

5.4.2 Manipulating data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162

5.5 Informix additional features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169

5.5.1 Batch inserts, updates, and resultset metadata . . . . . . . . . . . . . . . 169

5.5.2 BIGSERIAL data type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171

5.5.3 Informix Smart Large Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173

5.5.4 Secure Socket Layer (SSL). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176

5.5.5 Typical errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180

5.5.6 Tracing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181

Chapter 6. IBM Informix with Hibernate . . . . . . . . . . . . . . . . . . . . . . . . . . 183

6.1 Hibernate for Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184

6.1.1 Hibernate. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184

iv

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884TOC.fm

6.1.2 Hibernate concepts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185

6.2 Setup and configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186

6.2.1 Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186

6.2.2 Configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188

6.3 Using Hibernate with an Informix database. . . . . . . . . . . . . . . . . . . . . . . 192

6.3.1 Components of a Hibernate application . . . . . . . . . . . . . . . . . . . . . 192

6.3.2 Working with a Hibernate object . . . . . . . . . . . . . . . . . . . . . . . . . . . 197

6.3.3 Using annotations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205

Chapter 7. Working with the IBM Informix OLE DB Provider . . . . . . . . . 209

7.1 IBM Informix OLE DB Provider . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210

7.2 Setup and configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210

7.2.1 Installation and setup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210

7.2.2 Verifying connectivity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211

7.3 Developing an OLE DB application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214

7.3.1 Supported interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215

7.3.2 Connecting to database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 215

7.3.3 Type mapping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217

7.3.4 Cursors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219

7.3.5 Typical database operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219

7.4 Visual Basic, ADO.NET, and SQL Server . . . . . . . . . . . . . . . . . . . . . . . . 232

7.4.1 OLE DB with Visual Basic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232

7.4.2 ADO.NET and the OLEDB bridge . . . . . . . . . . . . . . . . . . . . . . . . . . 234

7.4.3 SQL Server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 236

7.5 Troubleshooting and tracing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239

7.5.1 Typical errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 240

7.5.2 Tracing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243

Chapter 8. Working with the .NET Data Providers . . . . . . . . . . . . . . . . . . 247

8.1 Informix and .NET data providers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 248

8.2 Setup and configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 248

8.2.1 IBM Informix .Net Provider . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 248

8.2.2 IBM Data Server Provider for .NET . . . . . . . . . . . . . . . . . . . . . . . . . 249

8.2.3 Verifying connectivity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 250

8.3 Developing a .NET application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253

8.3.1 Connecting to database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253

8.3.2 Data type mapping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 256

8.3.3 Performing database operations . . . . . . . . . . . . . . . . . . . . . . . . . . . 258

8.3.4 Handling Informix specific data types . . . . . . . . . . . . . . . . . . . . . . . 269

8.3.5 Troubleshooting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 283

8.4 Visual Studio Add-In for Visual Studio. . . . . . . . . . . . . . . . . . . . . . . . . . . 286

Chapter 9. Working with PHP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 289

9.1 Informix and PHP extensions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 290

Contents

v

7884TOC.fm

Draft Document for Review August 23, 2010 10:53 am

9.2 Setup and configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291

9.2.1 Installation of OAT. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291

9.2.2 PDO_INFORMIX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 293

9.2.3 PDO_IBM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 294

9.2.4 Verifying the PDO setup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 294

9.2.5 Verifying connectivity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 294

9.3 Developing a PHP application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 296

9.3.1 Connecting to database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 296

9.3.2 Performing database operations . . . . . . . . . . . . . . . . . . . . . . . . . . . 299

9.3.3 Handling complex data types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 304

9.3.4 Working with PHP extensions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 313

9.3.5 Exception handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 317

9.3.6 Troubleshooting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 321

Chapter 10. User defined routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 323

10.1 An Overview of UDRs and database extensions . . . . . . . . . . . . . . . . . 324

10.1.1 Considerations for user defined routines . . . . . . . . . . . . . . . . . . . 324

10.1.2 About user-defined routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 326

10.1.3 Considerations for extending data types . . . . . . . . . . . . . . . . . . . . 328

10.2 Developing user defined routines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 329

10.2.1 User defined routines in SQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . 330

10.2.2 User defined routines in Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . 334

10.2.3 User defined routines in C. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 341

10.3 DataBlades and bladelets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 346

10.3.1 Configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 346

10.3.2 IBM Informix provided DataBlades . . . . . . . . . . . . . . . . . . . . . . . . 349

10.3.3 Developing a bladelet routine . . . . . . . . . . . . . . . . . . . . . . . . . . . . 352

Chapter 11. Working with Ruby on Rails. . . . . . . . . . . . . . . . . . . . . . . . . . 355

11.1 A brief overview of Ruby on Rails . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 356

11.1.1 Architecture of Ruby on Rails . . . . . . . . . . . . . . . . . . . . . . . . . . . . 356

11.1.2 Ruby driver and Rails adapter. . . . . . . . . . . . . . . . . . . . . . . . . . . . 357

11.2 Setup and configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 358

11.2.1 Ruby Informix driver . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 358

11.2.2 Data Server Ruby driver . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 361

11.2.3 Rails adapters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 363

11.3 Database operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 367

11.4 Using the Rails adapter with Ruby Informix . . . . . . . . . . . . . . . . . . . . . 376

11.5 Using the Rails adapter with IBM_DB . . . . . . . . . . . . . . . . . . . . . . . . . . 383

Chapter 12. Informix 4GL Web Services . . . . . . . . . . . . . . . . . . . . . . . . . . 389

12.1 Basic concepts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 390

12.1.1 IBM Informix 4GL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 390

12.1.2 Service Oriented Architecture and Web Services . . . . . . . . . . . . . 390

vi

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884TOC.fm

12.1.3 Web Services development . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 390

12.1.4 Informix 4GL and Web Services . . . . . . . . . . . . . . . . . . . . . . . . . . 391

12.1.5 Components . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 391

12.2 Setup and configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 392

12.2.1 Prerequisites and supported platforms . . . . . . . . . . . . . . . . . . . . . 392

12.2.2 Environment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 392

12.3 I4GL Web Service tools. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 394

12.3.1 Web Service Compiler w4glc . . . . . . . . . . . . . . . . . . . . . . . . . . . . 394

12.3.2 The w4gl utility . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 396

12.3.3 Web Service Description Language Parser (wsdl_parser) . . . . . . 397

12.3.4 I4GL Web Services process . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 398

12.4 Developing a Web Service with I4GL . . . . . . . . . . . . . . . . . . . . . . . . . . 398

12.4.1 Example I4GL function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 399

12.4.2 Host and application details . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 400

12.4.3 Definition of the Web Service . . . . . . . . . . . . . . . . . . . . . . . . . . . . 402

12.4.4 Generate the configuration file . . . . . . . . . . . . . . . . . . . . . . . . . . . 405

12.4.5 Deployment of the Web Service . . . . . . . . . . . . . . . . . . . . . . . . . . 409

12.4.6 Packaging of the Web Service . . . . . . . . . . . . . . . . . . . . . . . . . . . 410

12.4.7 Starting the Axis2 application server . . . . . . . . . . . . . . . . . . . . . . . 411

12.4.8 Consuming the I4GL Web Service . . . . . . . . . . . . . . . . . . . . . . . . 411

12.5 Consuming a Web Service with I4GL . . . . . . . . . . . . . . . . . . . . . . . . . . 414

12.5.1 Web service to consume . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 414

12.5.2 Compiling the wrapper code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 415

12.5.3 Using the Web Service from an I4GL application . . . . . . . . . . . . . 416

12.6 Troubleshooting. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 417

12.6.1 Typical problems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 417

12.6.2 Tracing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 422

Chapter 13. Application development considerations. . . . . . . . . . . . . . . 425

13.1 Concurrency and locking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 426

13.1.1 Types of locks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 426

13.1.2 Lock duration. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 428

13.1.3 Lock granularity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 428

13.2 Locking issues and performance. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 433

13.2.1 Deadlocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 434

13.3 Isolation levels. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 435

13.4 Configuration options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 437

13.4.1 Server identification. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 437

13.4.2 Storage space identifiers. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 438

13.4.3 Limiters and limits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 440

13.4.4 Java configuration parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . 444

13.5 Working with your database administrator . . . . . . . . . . . . . . . . . . . . . . 445

13.5.1 Parameters for negotiation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 449

Contents

vii

7884TOC.fm

Draft Document for Review August 23, 2010 10:53 am

13.5.2 Monitoring isolation levels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 450

13.5.3 Monitoring locks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 450

13.5.4 Monitoring user threads . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 451

Appendix A. Onconfig parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 453

Appendix B. Accommodating distributed transactions . . . . . . . . . . . . . 455

B.1 Distributed transactions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 456

B.2 TP/XA Transaction Manager XA Interface Library . . . . . . . . . . . . . . . . . 456

B.3 XA_TOOL ESQL/C sample. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 457

Related publications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 465

IBM Redbooks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 465

Other publications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 465

Online resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 466

How to get Redbooks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 466

Help from IBM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 466

Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 469

viii

IBM Informix Developer’s Handbook

7884spec.fm

Draft Document for Review August 23, 2010 10:53 am

Notices

This information was developed for products and services offered in the U.S.A.

IBM may not offer the products, services, or features discussed in this document in other countries. Consult your local IBM representative for information on the products and services currently available in your area.

Any reference to an IBM product, program, or service is not intended to state or imply that only that IBM product, program, or service may be used. Any functionally equivalent product, program, or service that does not infringe any IBM intellectual property right may be used instead. However, it is the user's responsibility to evaluate and verify the operation of any non-IBM product, program, or service.

IBM may have patents or pending patent applications covering subject matter described in this document.

The furnishing of this document does not give you any license to these patents. You can send license inquiries, in writing, to:

IBM Director of Licensing, IBM Corporation, North Castle Drive, Armonk, NY 10504-1785 U.S.A.

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

provisions are inconsistent with local law: INTERNATIONAL BUSINESS MACHINES CORPORATION

PROVIDES THIS PUBLICATION "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR

IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF NON-INFRINGEMENT,

MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Some states do not allow disclaimer of express or implied warranties in certain transactions, therefore, this statement may not apply to you.

This information could include technical inaccuracies or typographical errors. Changes are periodically made to the information herein; these changes will be incorporated in new editions of the publication. IBM may make improvements and/or changes in the product(s) and/or the program(s) described in this publication at any time without notice.

Any references in this information to non-IBM websites are provided for convenience only and do not in any manner serve as an endorsement of those websites. The materials at those websites are not part of the materials for this IBM product and use of those websites is at your own risk.

IBM may use or distribute any of the information you supply in any way it believes appropriate without incurring any obligation to you.

Information concerning non-IBM products was obtained from the suppliers of those products, their published announcements or other publicly available sources. IBM has not tested those products and cannot confirm the accuracy of performance, compatibility or any other claims related to non-IBM products. Questions on the capabilities of non-IBM products should be addressed to the suppliers of those products.

This information contains examples of data and reports used in daily business operations. To illustrate them as completely as possible, the examples include the names of individuals, companies, brands, and products.

All of these names are fictitious and any similarity to the names and addresses used by an actual business enterprise is entirely coincidental.

COPYRIGHT LICENSE:

This information contains sample application programs in source language, which illustrate programming techniques on various operating platforms. You may copy, modify, and distribute these sample programs in any form without payment to IBM, for the purposes of developing, using, marketing or distributing application programs conforming to the application programming interface for the operating platform for which the sample programs are written. These examples have not been thoroughly tested under all conditions. IBM, therefore, cannot guarantee or imply reliability, serviceability, or function of these programs.

ix

© Copyright IBM Corp. 2010. All rights reserved.

7884spec.fm

Trademarks

Draft Document for Review August 23, 2010 10:53 am

IBM, the IBM logo, and ibm.com are trademarks or registered trademarks of International Business

Machines Corporation in the United States, other countries, or both. These and other IBM trademarked terms are marked on their first occurrence in this information with the appropriate symbol (® or ™), indicating US registered or common law trademarks owned by IBM at the time this information was published. Such trademarks may also be registered or common law trademarks in other countries. A current list of IBM trademarks is available on the Web at http://www.ibm.com/legal/copytrade.shtml

The following terms are trademarks of the International Business Machines Corporation in the United States, other countries, or both:

AIX®

DataBlade®

DB2 Universal Database™

DB2® developerWorks®

Distributed Relational Database

Architecture™

DRDA®

IBM®

Informix®

MQSeries®

Rational®

Redbooks®

Redpaper™

Redbooks (logo)

UC2™

WebSphere®

®

The following terms are trademarks of other companies:

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

Microsoft, Windows, and the Windows logo are trademarks of Microsoft Corporation in the United States, other countries, or both.

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

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

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

x

IBM Informix Developer’s Handbook

7884pref.fm

Draft Document for Review August 23, 2010 10:53 am

Preface

IBM® Informix® is a low-administration, easy-to-use, and embeddable database that is idea for application development. It supports a wide range of development platforms, such as Java™, .NET, PHP, and Web services, enabling developers to build database applications in their language of choice. Informix is designed to handle RDBMS data and XML out of the box, and can easily be extended to handle new data sets.

This IBM Redbooks® publication provides fundamentals of Informix application development. It covers the Informix Clients installation and configuration for application development environments. It discusses the skills and techniques for building Informix applications with Java, ESQL/C, OLE DB, .NET, PHP, Ruby on

Rails, DataBlade®, and Hibernate. Code examples are used to demonstrate how to develop an Informix application with various drivers, APIs, and interfaces.

This book also provides application development trouble-shooting and considerations for performance.

The team who wrote this book

This book was produced by a team of specialists from around the world working at the International Technical Support Organization, Rochester Center.

Whei-Jen Chen is a Project Leader at the International Technical Support

Organization, San Jose Center. She has extensive experience in application development, database design and modeling, and DB2® system administration.

Whei-Jen is an IBM Certified Solutions Expert in Database Administration and

Application Development, and an IBM Certified IT Specialist

David Jay is a Staff Software Engineer in the IBM North

Americas Technical Support Team, providing advanced technical support, defect discovery, and support training for

Informix products and SolidDB. David joined the Informix

Support team in September 1996, and has served in various software and support roles since the 1980's. He has a

Bachelor of Science from Pennsylvania State University, and enjoys public speaking assignments whenever he gets them through Toastmasters and IBM.

xi

© Copyright IBM Corp. 2010. All rights reserved.

7884pref.fm

Draft Document for Review August 23, 2010 10:53 am

Javier Sagrera is a software engineer on the Common Client

Technologies (CCT) group. He joined the Informix team in 2000 and has over 15 years experience in application development for Informix database servers and Informix clients. Currently based on the IBM UK Bedfont Lab in London, he has extensive knowledge on all the Microsoft® technologies and is considered as a subject matter expert worldwide on all the

Informix development tools.

Krishna Doddi (also known as Prasad) has been with IBM

Informix since 1996. He worked in Informix Advanced Support for Client Products. The main products he supported were

Informix Client SDK, mostly on Windows® platform. After the

IBM acquisition in 2001, he moved to DB2 Advanced Support, again in the Client Products division. After five years in DB2, he moved to Informix QA for Informix Client Products including

JCC Common Client and PureQuery. He is currently the focal for Informix Integration projects.

Manoj Ghogale is a Tech Lead in the Informix team at ISL

India. Manoj has 9 years of industry experience and has been with IBM for 5 years. He has worked on numerous automation projects and new features of Informix server. He holds a

Bachelor's degree in Engineering from National Institute of

Engineering, Mysore, India.

Acknowledgements

Thanks to the following people for their contributions to this project:

Jacques Roy

Ted Wasserman

Rakeshkumar Naik

Jonathan Leffler

Robert Uleman

Richard Snoke

Guy Bowerman

IBM Software Group

Greg Holmes

Alberto Bortolan

Adam Hattrell

IBM Bedfont Laboratory xii

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

Emma Jacobs

International Technical Support Organization, Rochester Center

7884pref.fm

Become a published author

Here's an opportunity to spotlight your skills, grow your career, and become a published author - all at the same time! Join an ITSO residency project and help write a book in your area of expertise, while honing your experience using leading-edge technologies. Your efforts will help to increase product acceptance and customer satisfaction, as you expand your network of technical contacts and relationships. Residencies run from two to six weeks in length, and you can participate either in person or as a remote resident working from your home base.

Find out more about the residency program, browse the residency index, and apply online at:

ibm.com/redbooks/residencies.html

Comments welcome

Your comments are important to us!

We want our books to be as helpful as possible. Send us your comments about this book or other IBM Redbooks publications in one of the following ways:

򐂰 Use the online Contact us review Redbooks form found at:

ibm.com/redbooks

򐂰 Send your comments in an e-mail to: [email protected]

򐂰 Mail your comments to:

IBM Corporation, International Technical Support Organization

Dept. HYTD Mail Station P099

2455 South Road

Poughkeepsie, NY 12601-5400

Preface

xiii

7884pref.fm

Draft Document for Review August 23, 2010 10:53 am

xiv

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch01.fm

1

Chapter 1.

Introduction to IBM Informix

We live in a business world that requires a variety of software components to fully handle the scope of business needs. When considered as a group, the products have to work together, and they must scale well to cover the demands of business to assure continued growth. Frequently, a significant criteria list may be needed, to specify all the facets encountered in daily, monthly, and yearly periods of business operations. Developers must be sensitive to how the database engine functions, what are server side capabilities that can be brought into play, and what development tasks need to occur on the client, or application side.

This chapter provides an overview of Informix products and capabilities. The approach is somewhat reference oriented. In addition to the overview of Informix products, we also provide an awareness of the architecture of IBM Informix from both the server-side and the client-side, to better acquaint the developer with perspectives you may need to know.

Lastly, we discuss the capabilities of the products in the Informix suite.The IBM

Informix products that we describe demonstrate how to manage business performance, handle all types of business applications, minimize administration through various self-automated and self-monitored options, and at all times, the setup can help minimize costs for maintenance and resource allocations.

1

© Copyright IBM Corp. 2010. All rights reserved.

7884ch01.fm

Draft Document for Review August 23, 2010 10:53 am

1.1 Server options

There are a number of options for IBM Informix servers, designed to meet the needs of business enterprises that range in size from a small group with a few employees, up to several thousand people. The database needs to meet a variety of requirements of a diverse group. What follows is a brief discussion of each of the server possibilities, and how they are generally used.

With the wealth of different server types available, unless otherwise noted, each comes with the opportunity to use the Client Software Development Kit (Client

SDK) for development of applications. Prior to renaming the brand editions in

May 2010, the IBM Informix has had several versions. You can expect that each version is backward and forward compatible, beginning with 7.2x, and moving forward through 7.3x, 9.2x, 9.30, 9.40, and 10.00. The Cheetah series began with Informix Dynamic Server 11.10, and quickly advanced into the 11.50 family.

At this writing we are now into the IBM Informix Ultimate series that begins with

11.50.xC7 and following,

It is helpful to be aware of version numbering conventions. “UC” or “UD” at the end of a version number indicates 32-bit UNIX®. A “TC” indicates a 32-bit

Windows version. An “FC” indicates a 64-bit version (UNIX or Windows). This becomes important in application and memory addressability. A 32-bit application works with a 64-bit server, but the application will only be able to access 32-bit memory.

1.1.1 Informix servers

Several options are available for IBM Informix Servers, each one designed to address specific needs in business.

No-charge editions

The following no-charge editions are available as separate offerings subject to the IBM International License Agreement for Non-warranted Programs (ILAN):

Informix Developer Edition

The Developer Edition provides all the features of Informix at no cost, when solely used for application development and testing. It can be used for application development and prototyping, with no time limits. Support is available by way of the informix user community through internet forums.

The Informix Developer Edition offers the application development these choices:

C, C++, .NET, Java, Ruby on Rails, Perl, Python, PHP, and 4GL. The operating systems that the Developer Edition supports includes AIX®, HP, Unix, Linux®,

2

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch01.fm

Macintosh, Sun Solaris, and Windows. This Informix edition is limited to 1 CPU, 1

GB memory, and 8 GB storage.

Informix Developer Edition includes the following bundle:

򐂰

Informix Client Software Development Kit

򐂰

Informix DataBlade Developers Kit

򐂰

Informix Spatial Datablade

Informix Innovator-C Edition

The Innovator-C Edition provides a robust and powerful environment designed to support small production workloads. It features the most widely used data processing functionality, including limited Enterprise Replication and High

Availability clustering.

This edition offers application development these choices: C, C++, .NET, Java,

Ruby on Rails, Perl, and 4GL. The operating systems the Innovator-C Edition supports include AIX, HP, Unix, Linux, Macintosh, Sun Solaris, and Windows.

This edition is limited to 1 socket with no more than 4 cores and a total of 2 GB of

RAM operating from the same Install.

The Innovator-C no-charge Informix edition is an offering to be used for development, test, and end-user production workloads without a license fee. This edition can only be used by end-user organizations. It cannot be re-distributed without signing a re-distribution contract. Support is community-based though an optional for-charge service and support package is available.

Licensed versions

In a business enterprise that demands constant uptime and consistent delivery requirements, it helps to have a license and professional, timely support to cover every need. There are several licensing options available. In this section we

discuss the Informix server versions that are licensed subscriptions. Table 1-1 on page 3 describes the terms and abbreviations for these editions. The criteria may

be subject to change over time, consult with a sales representative for the most accurate definitions.

Table 1-1 Informix licensed versions

Licensing term Defined

Processor Value Unit

(PVU)

(also known as processor-based pricing)

Calculated using the number of processor cores in the physical server multiplied by the corresponding value units based on processor architecture. This is an unlimited user or connection license and is usually the optimal choice when the user or session load cannot be controlled or counted.

Chapter 1. Introduction to IBM Informix

3

7884ch01.fm

Draft Document for Review August 23, 2010 10:53 am

Licensing term

Authorized User

Single Install

Concurrent Session

Limited Use Socket

(LU Socket)

Install

Defined

A single named user or specific individual accessing one installation of Informix on each physical or virtual server. That authorized user can establish multiple connections to an Informix instance on the server. Each connection is for the exclusive use of that one authorized user from a single client device.

A single logical connection from a client device to an Informix instance on each physical or logical server. Each connection, whether active or not, requires a license, regardless of whether it comes from one client device with multiple users or from a single user establishing multiple connections. The number of concurrent sessions is counted from the client device, rather than at the Server level, regardless of whether the connection is directly to the Informix instance or indirectly; whether it is through application servers, persistent connectivity layers, connection multiplexers / concentrators, or any other technology inserted between the actual end-user and the Informix instance.

Available only on Informix Growth Edition, this allows for licensing on a physical socket potentially containing multiple cores. A LU Socket license is required for each active processor socket. This licensing metric can only be used on a physical server with no more than four physical sockets. You may purchase licenses for up to four physical sockets and use up to 16 cores.

An “Install” is an installed copy of an informix product on a physical server (or partition thereof) or in a virtual machine image. For example, if a physical server is segmented into partitions, whether logical (also know as LPARs) or physical, each partition containing Informix is considered a separate IBM Informix “Install” for licensing purposes and restrictions. The concept of an

“Install” applies to the licensing limits specified for all Informix Editions.

Informix Choice Edition

Informix Choice Edition is ideal for small to medium size business. This edition is available for both Microsoft Windows and Apple Macintosh operating systems.

This edition is limited to a total of eight cores over a maximum of two sockets and

4

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch01.fm

8GB of RAM operating. The Informix Choice Edition includes limited Enterprise

Replication (ER) clustering with 2-root nodes to send or receive data updates within the cluster. This edition also provides limited High Availability (H/A) cluster functionality; along with the Primary server, you can have one secondary node, either an HDR secondary or RSS secondary. The H/A cluster secondary node can be used for SQL operations. This edition does not support use of the Shared

Disk secondary (SD secondary) node type.

Informix Growth Edition

The Informix Growth Edition is available on all platforms, Linux, UNIX, Windows, and Apple Macintosh. The Growth Edition is ideal for mid-sized companies or departmental servers in an enterprise deployment. It can be deployed on up to

16 cores over a maximum of 4 sockets and 16GB of RAM operating from the same Install. License options include Authorized User Single Install, Concurrent

Session, PVU, and Limited Use Socket (LU Socket) metrics. LU Socket enables licensing by physical processor socket and is limited to physical servers with no more than four physical processor sockets.

Informix Growth Edition gives you additional database functionality including unlimited ER cluster nodes of any type for sending or receiving data updates within the cluster. From a licensing perspective, since ER nodes are stand-alone, each ER node must be fully licensed. Informix Growth edition supports up to two

(2) H/A cluster secondary nodes of any type. As long as the secondary node(s) are only functioning as a backup secondary, they can be deployed without charge. However, if you use a secondary node for SQL operations (read or write), the secondary node must be fully licensed.

Informix Ultimate Edition

The IBM Informix Ultimate Edition includes nearly all the Informix features and functionality with unlimited scalability required for the highest OLTP and warehousing performance.

The operating systems the Informix Ultimate Edition supports include AIX, HP,

Unix, Linux, Macintosh, Sun Solaris, and Windows. This edition can be licensed by PVU, Concurrent Session, or Authorized User Single Install metrics.

With this edition, full H/A cluster and ER functionality is available including unlimited ER nodes and all H/A cluster secondary instance types. From a licensing perspective, since ER nodes are stand-alone, each ER node must be fully licensed but H/A secondary nodes can be deployed without charge if they are only functioning as a backup secondary. If you use any secondary node for

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

This edition offers the following Add-on:

򐂰

The Geodetic and Excalibur DataBlades.

Chapter 1. Introduction to IBM Informix

5

7884ch01.fm

Draft Document for Review August 23, 2010 10:53 am

򐂰 The Storage Optimization Feature was released with Informix version11.5 xC4 and following. The Storage Optimization Feature provides data compression to dramatically reduce data storage and backup/recovery costs and administration. The reduced data footprint also provides a significant increase in performance for data retrieval.

Extended Parallel Server

The IBM Informix Extended Parallel Server (XPS) is a high-end database that is typically used for scalable data warehousing with fast data loading and comprehensive data management. It is designed for a broad range of enterprises that require complex, query-intensive analytical applications.

The IBM Informix Extended Parallel Server usage examples include:

򐂰

Reliable data manipulation

򐂰

Ad hoc queries from data warehouses

򐂰

A combined data warehouse and data mart

򐂰

Rapid and concurrent data loading and query execution

IBM Informix Extended Parallel Server provides full parallel query processing, while being able to use hardware resources to deliver mainframe-caliber scalability, manageability, and performance with minimal OS and administrative overhead. For more information, see Database Strategies: Using Informix XPS

and DB2 Universal Database, SG24-6437.

Informix OnLine

IBM Informix OnLine is an easy to use, embeddable relational database server for low-to-medium workloads.

It has less features and functionality than the Informix Ultimate Server, but it scales well while providing online transaction processing support and the assurance of data integrity. Informix OnLine has rich multimedia data management capabilities, supporting the storage of a wide range of media such as documents, images, and audio by way of text and byte columns. Also it is not designed to handle extended data types or replication.

This server supports a wide variety of application development tools, along with a large number of other third-party tools, through support for the ODBC and JDBC industry standards for client connectivity

There are three edition options for this server:

򐂰

Informix OnLine Extended Edition 5.20

This edition option is a full-featured, easy-to-use SQL database with low administrative overhead. It contains two popular Informix products, Informix

OnLine and Informix STAR, and provides distributed computing with a proven

6

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch01.fm

database server. It allows the Rapid Application Development tools to use pipes to communicate with OnLine Extended Edition 5.20 servers running on the same machine, instead of having to use a TCP/IP loopback connection with Informix Star or Informix Net. It supports greater than 2GB chunk offsets, to utilize the entire capacity of the disk drive without partitioning it into smaller logical devices and employing logical volume managers.

The operating systems this edition supports include AIX, HP Unix, and Sun

Solaris.

򐂰

Informix OnLine Extended Edition for Linux

This edition is same as the Informix OnLine Extended Edition 5.20 but is but only available for Linux.

򐂰

Informix OnLine Personal Edition

This is the single-user product version, available only on Linux. It provides the same functionality as IBM Informix OnLine Extended Edition, at an economical cost. It enables you to quickly become familiar with the ease-of-use and multimedia capability of this proven relational database management system.

Standard Engine

IBM Informix Standard Engine (SE) is an embeddable database server that runs on UNIX, Linux and Windows. It provides an ideal solution for developing small to medium-sized applications that need the power of SQL without database administration requirements (low-maintenance, high-reliability). For limited scale databases, it delivers excellent performance, adheres to data consistency standards, and still provides client/server capabilities. It can be seamlessly integrated with Informix application development tools and third-party development tools compliant with the ODBC and JDBC standards.

The operating systems this edition supports include AIX, HP Unix, Linux, Sun

Solaris, and Windows.

1.2 Informix tools for developers

There is a significant list of tools available from Informix for developers. We focus on the available application programming interface (API) options and language possibilities. There are also other utilities and tools provided with the engine that promote further ease of use. The 4GL developer’s edition includes the ACE

Report Writer, which can be used to quickly generate forms and reports. The

High Performance Loader, onload, onunload, and External table are bulk load and unload utilities that provide fast flat file movements. Other tools include I-Spy for auditing, MaxConnect, and the Open Administration Tool (OAT) for remote

Chapter 1. Introduction to IBM Informix

7

7884ch01.fm

Draft Document for Review August 23, 2010 10:53 am server administration and SQL. For more information on these or other tools, consult with a sales representative or visit the Informix support website at http://www-947.ibm.com/support/entry/portal/Overview/Software/Information_Manag ement/Informix_Product_Family

1.2.1 I-Connect

I-Connect is the

runtime

version of Client SDK that comes with the Server engine. You use Client SDK and related tools to develop your application. Once it is ready for use in production, I-Connect is the tool used to deploy the application. It is supplied with the Server engine software, and provides the connectivity and runtime libraries which permit interaction between the engine and the application. While some I-Connect development can be done without

Client SDK, the great majority should be handled through the Client SDK API.

1.2.2 Client SDK

IBM Informix Client Software Development Kit is a package of several APIs that

are optimized for developing applications for IBM Informix servers. Informix Client

SDK allows developers to write applications in the language they prefer and to build applications that can access multiple IBM Informix databases. Here we discuss the API packages included in Client SDK.

ODBC

Open Database Connectivity (ODBC) is a specification for a database API. It is based on the Call Level Interface specifications from X/Open and the

International Standards Organization and International Electromechanical

Commission (ISO/IEC). ODBC supports SQL statements with a library of C functions. An application calls these functions to implement ODBC functionality.

ODBC applications can perform the following operations:

򐂰

Connect to and disconnect from data sources.

򐂰 Retrieve information about data sources.

򐂰

Retrieve information about the IBM Informix ODBC Driver.

򐂰 Set and retrieve IBM Informix ODBC Driver options.

򐂰

Prepare and send SQL statements.

򐂰 Retrieve SQL results and process the results dynamically.

򐂰

Retrieve information about SQL results and process the information dynamically.

8

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch01.fm

ODBC lets you allocate storage before or after the SQL results are available.This feature lets you determine the results and the action to take without the limitations that predefined data structures impose. ODBC does not require a preprocessor to compile an application program. ODBC supports Secure

Sockets Layer (SSL) connections. For information on using the SSL protocol, see the “Secure Sockets Layer Communication Protocol” section of the IBM Informix

Version 11.5 Security Guide, SC23-7754-04.

The additional features and capabilities that Informix ODBC supports include:

򐂰

Microsoft Transaction Server (MTS) environment. For more information on

MTS, see the MTS sections in the IBM Informix ODBC Driver Programmers

Manual, SC23-9423-03.

򐂰 ODBC can handle extended data types such as:

– Collection (LIST, MULTISET, and SET)

– Distinct

– Opaque (fixed, unnamed)

– Row (named, unnamed)

– Smart large objects (BLOB andCLOB)

– Client functions that support extended data types

򐂰 Long identifiers

򐂰

Global Language Support (GLS) data types (NCHAR,NVARCHAR).

򐂰 Support for Unicode and XA.

򐂰

IPv6 internet protocol.

ODBC with the IBM Informix ODBC Driver can include the following components:

򐂰 Driver manager

An application can link to a driver manager that links to the driver specified by the data source. The driver manager also checks parameters and transitions.

You can purchase the ODBC Driver Manager from a third-party vendor for most UNIX platforms. On Microsoft Windows platforms, the ODBC Driver

Manager is a part of the Operating System.

򐂰 IBM Informix ODBC Driver

This driver provides an interface to the Informix database server. Applications can use the driver in the following configurations:

– To link to the ODBC driver manager

– To link to the Driver Manager Replacement & the driver

– To link to the driver directly

򐂰

Data sources

Chapter 1. Introduction to IBM Informix

9

7884ch01.fm

Draft Document for Review August 23, 2010 10:53 am

The driver provides access to the following data sources:

– Database management systems (DBMS) and database servers

– Databases

– Operating systems and network software required for accessing the database

JDBC and SQLJ

JDBC is an application programming interface (API) that Java applications use to access relational databases. IBM Informix database systems can be supported by one of two APIs for client applications and applets written in Java:

򐂰

IBM Data Server Driver

You can use the IBM Data Server Driver (also known as the IBM common client driver) with either DB2 or Informix. This JDBC driver lets you write Java applications to access a local Informix Server, DB2 data, or any remote relational data on a server that supports DRDA®. Using this API, you can access these database systems using JDBC, SQLJ or pureQuery. SQLJ provides support for embedded static SQL in Java applications.

Note: The IBM Data Server Driver is introduced with Client SDK beginning

with Client SDK 3.50.XC7. At this writing, the Client SDK distributed with

Informix database server is one (1) version less than the server version. As an example, CSDK 3.50.XC6 is the version distributed with Server edition

11.50.XC7

The IBM Data Server Driver for JDBC and SQLJ is a single driver that includes JDBC Type 2 and JDBC Type 4 behavior. For connections to IBM

Informix databases, only Type 4 behavior is supported. IBM Data Server

Driver for JDBC and SQLJ Type 4 driver behavior is also referred to as

IBM

Data Server Driver for JDBC and SQLJ type 4 connectivity

. For more information on these APIs, see the Java discussions at http://publib.boulder.ibm.com/infocenter/db2luw/v9r5/index.jsp?topic=/com.i

bm.db2.luw.apdv.java.doc/doc/rjvjdb2o.html

򐂰

IBM Informix JDBC driver

IBM Informix JDBC driver is a native-protocol, pure- Java driver (JDBC type

4). This means that when you use IBM Informix JDBC Driver in a Java program that uses the JDBC API to connect to an IBM Informix database, your session connects directly to the database or database server, without a middle tier.

When deciding which JDBC interface to use, it is important to understand the differences in these two APIs. If there is a need to work with extended data types

10

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch01.fm

and features unique to IBM Informix databases, you will want to use the IBM

Informix JDBC driver.

To support DataSource objects, connection pooling, and distributed transactions,

IBM Informix JDBC Driver provides classes that implement interfaces and classes described in the JDBC 3.0 API from Sun Microsystems.

Informix classes implementing Java interfaces

Table 1-2 lists the Java interfaces and classes and the Informix classes that

implement them.

Table 1-2 Java interfaces and classes

JDBC interface class

java.io.Serializable

java.sql.Connection

Informix class

com.informix.jdbcx.IfxCoreDataSource

com.informix.jdbc.IfmxConnection

javax.sql.ConnectionEventListener

com.informix.jdbcx.IfxConnectionEvent-

Listener javax.sql.ConnectionPoolDataSource

com.informix.jdbcx.IfxConnectionPoolData-

Source javax.sql.DataSource

javax.sql.PooledConnection

javax.sql.XADataSource

java.sql.ParameterMetaData

com.informix.jdbcx.IfxDataSource

com.informix.jdbcx.IfxPooledConnection

com.informix.jdbcx.IfxXADataSource

com.informix.jdbc.IfxParameterMetaData

IBM Informix JDBC Driver, Version 3.0, and later implements the updateXXX() methods defined in the ResultSet interface by the JDBC 3.0 specification. These methods, such as updateClob, are further defined in the J2SDK 1.4.x API (and later versions) and require that the ResultSet object can be updated. The updateXXX methods allow rows to be updated using Java variables and objects and extend to include additional JDBC types. These methods update JDBC types implemented with locators, not the data designated by the locators.

Informix classes Java specification

To support the Informix implementation of SQL statements and data types, the

IBM Informix JDBC Driver provides classes that extend the JDBC 3.0 API. For information on the Java classes and the Informix classes that application programs can use to extend them, see the IBM Informix JDBC Driver

Programmer's Guide, v3.50, SC23-9421-02.

Chapter 1. Introduction to IBM Informix

11

7884ch01.fm

Draft Document for Review August 23, 2010 10:53 am

Because IBM Informix have extended functionality, extra data types and smart large objects, several Informix classes provide support for functionality that is not

present in the JDBC 3.0 specification. Table 1-3 lists these classes.

Table 1-3 Informix classes beyond the Java Specification

JDBC interface or class Informix class Provides support for

java.lang.object

UDTManager java.lang.object

UDTMetaData

Deploying opaque data types in the database server

Deploying opaque data types in the database server java.lang.object

java.lang.object

UDRManager Deploying user defined routines in the database server

UDRMetaData Deploying user defined routines in the database server

In releases prior to JDK Version 1.4, the UDTManager and UDRManager helper classes included in ifxtools.jar were not accessible from a packaged class. As of

IBM Informix JDBC Driver 2.21.JC3, all these classes are in the udtudrmgr package. For backwards compatibility, unpackaged versions of these classes are also included. To access a packaged class, use the following import statements in your program:

򐂰

Import udtudrmgr.UDTManager;

򐂰

Import udtudrmgr.UDRManager;

OLEDB

Microsoft OLE DB is a specification for a set of data access interfaces designed to enable a variety of data stores to work together seamlessly. OLE DB components are: data providers, data consumers, and service components.

Each

data provider

makes their data available to consumers using data in a tabular form through virtual tables.

Data consumers

use the OLE DB interfaces to access data. You can use the IBM Informix OLE DB Provider to enable client applications, such as ActiveX Data Object (ADO) applications and Web pages, to access data on an Informix server. Detailed information about the characteristics of the IBM Informix OLE DB Provider is available in the IBM Informix OLE DB

Provider Programmer's Guide, Version 3.50, SC23-9424-00. The IBM OLEDB provider works with any IBM Informix Server version greater than or equal to 7.3

(7.3, 8.x, 9.x,10.x or 11.x). For information about OLE DB architecture and programming, go to the Microsoft website http://www.microsoft.com

and search for “Introduction to OLE DB”.

12

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch01.fm

ESQL/C

Informix ESQL/C is an application programming interface (API) that enables you to embed SQL statements directly into a C program. It does this by means of the

Informix ESQL/C preprocessor,

esql

, which converts each SQL statement and

IBM Informix-specific code to C-language source code, and invokes the C compiler to compile it.

The components of Informix ESQL/C include the following:

򐂰 The Informix ESQL/C libraries of C functions, which provide access to the database server, and all the Informix data types.

򐂰

The Informix ESQL/C header files, which define the data structures, constants, and macros useful to an Informix ESQL/C program.

򐂰 The

esql

command, which processes the Informix ESQL/C source code to

create a C source file that it passes to the C compiler.

򐂰

The

finderr

utility on the UNIX system and the Informix Error Messages

Windows-based utility that provides information on IBM Informix specific error messages.

򐂰 GLS locale and code set conversion files for locale specific information.

1.2.3 4GL

IBM Informix 4GL is a fourth-generation application development and production environment that provides power and flexibility without the need for third-generation languages such as C. The two package options, available for all

UNIX and Linux operating systems, include:

򐂰

Informix 4GL Rapid Development System and Informix 4GL Interactive

Debugger. These provide a pseudo-compiled development environment for applications.

򐂰 Informix 4GL C Compiler. This provides the components needed to develop and compile a high-performance application for a production environment.

1.2.4 Ruby on Rails

IBM Informix supports database access for client applications written in the popular and dynamic open source programming language called Ruby. To accomplish this, the developer must use a Ruby driver and a Rails adapter for the standard Ruby framework Rails. IBM Informix offers two methods for using Ruby and Ruby on Rails:

򐂰

Ruby driver and Rails adapter for IBM Data Servers: This is supported on

Informix, Version 11.10 or later, using the DRDA protocol. This option requires

Chapter 1. Introduction to IBM Informix

13

7884ch01.fm

Draft Document for Review August 23, 2010 10:53 am the IBM Data Server Driver for ODBC and the Call Level Interface (CLI) which are available as part of the Informix Client SDK.

򐂰

Ruby/Informix and Rails Informix_adapter: This is specific for Informix database server and works with Informix database connections. Supports all versions of the IBM Informix database servers and requires the IBM Informix

Client SDK libraries for the communication with the database server.

You can download the both packages from the Rubyforge website at http://rubyforge.org/projects/ruby-informix/

.

1.2.5 Informix DataBlade Developers Kit

The IBM Informix DataBlade Developers Kit (DBDK) is an aid for developing

DataBlade modules. The kit runs on Windows and generates much of the code you need for a DataBlade. DataBlades can be developed without a DBDK on operating systems other than Windows; however, it is noteworthy that the procedures for setting up the development environment on a UNIX system are complex without help from DBDK.

The DataBlade Developers Kit provides several graphical user interfaces for creating and working with Informix DataBlade modules.

򐂰 BladeSmith: A tool for organizing a DataBlade module development project.

You can use BladeSmith to create a project and define the objects, such as data types and routines, that belong to the DataBlade module. BladeSmith generates source files, header files, make files, functional test files, SQL scripts, messages files, and packaging files.

򐂰

DBDK Visual C++ Add-In and IfxQuery: Tools for debugging a DataBlade module using Microsoft Visual C++ on Windows. The add-in automates many of the debugging tasks and calls the IfxQuery tool to run unit tests for

DataBlade module routines.

򐂰 BladePack: A tool for creating a DataBlade module package. BladePack can create a simple directory tree containing files to be installed or an installation that includes an interactive user interface.

򐂰

BladeManager: This is a command line tool on UNIX (or Windows) that comes with the Informix Server. It is a utility that is needed for registering and unregistering DataBlade modules in Informix databases.

1.2.6 Informix Spatial DataBlade

Many of the IBM Informix database servers support DataBlades. Among all these

DataBlades, there are a couple that are fairly popular because of their usefulness and flexibility. We introduce one of these here to open your interest into an area

14

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch01.fm

that you may not have considered. Location based data is one of several features and benefits that can be found in the IBM Informix Spatial DataBlade.

The Spatial DataBlade can transform both traditional and location-based data into essential information:

򐂰

It expands IBM Informix Server to provide SQL-based spatial data types and functions that can be used directly through standard SQL queries or with client-side Geographic Information Systems (GIS) software.

򐂰 It delivers innovative spatial technology via a convenient no-charge download.

򐂰

It generates vital business intelligence for a competitive edge.

򐂰 It maximizes spatial data capabilities to enable critical business decisions.

򐂰

It works in an enterprise replication environment which includes spatial data types.

򐂰 It enables organizations to manage complex geospatial information alongside traditional data, without sacrificing the efficiency of the relational database model.

򐂰

It includes R-tree indexing:

R-tree is built into the database kernel and works directly with extended data types to enable proper geospatial data management. Unlike standard indices, the R-tree does not divide space into a full coverage of non- overlapping, adjacent cells. Instead, it uses data partitioning, where each object is automatically represented by a bounding box that is entirely determined by its own shape. These bounding boxes may overlap and do not need to cover the entire space. As a result there is no need to know the spatial extent of the data in advance.

1.2.7 PHP on Informix

PHP, the powerful and popular server-side scripting language for creating Web content, has become an important platform for Informix development. The

Informix Open Admin Tool (OAT), which provides the ability to administer multiple

Informix instances from a single location, is written entirely in the PHP language.

Informix supports database access for client applications written in the PHP programming language by using a PDO (PHP Data Object) extension that functions as a database extraction layer. The primary PHP driver available for

Informix is called PDO_IBM, and is supported on Informix Version 11.10, and following. The other available PHP driver is PDO_INFORMIX. It is the older of these two, and is the driver used for the Informix Open Admin Tool. You can find the drivers for PHP on the PECL for PHP website at http://pecl.php.net/package/PDO_IBM

Chapter 1. Introduction to IBM Informix

15

7884ch01.fm

1.3 Informix overview

Draft Document for Review August 23, 2010 10:53 am

This section provides a description of the database architecture from a developer perspective. There are entire manuals to describe Server side functions and administration. We limit our overview to things that the developer should consider. For more information about the details of the IBM Informix server engine, consult the IBM Informix Administrators Guide at http://publib.boulder.ibm.com/infocenter/idshelp/v115/index.jsp?topic=/com.ibm.

adref.doc/adref.htm

1.3.1 Architecture overview

An understanding of how things work on the Informix database server is beneficial for application development.

Client/Server architecture

IBM Informix Servers are based on a multi-threaded client-server architecture.

Whichever edition you use, the server can support a large number of client connections while users are accessing data. A quick overview provides insights into what aspects influence development, and what aspects may need DBA attention.

The IBM Informix server edition environments consist of several parts that are usually not directly visible to the developer. These parts include shared memory, disk storage, and virtual processors (VPs). The virtual processors are divided up into VP classes to manage specific tasks, such as SQL query processing (CPU), physical and logical log processes (PIO and LIO), network connection processes

(NET), engine administration (ADM), miscellaneous (MSC), and disk I/O (AIO and KAIO) processes. On UNIX and Apple Macintosh systems, VPs are visible as virtual processes. On Windows environments, the VPs are seen as threads.The program execution process is visible as oninit. Virtual processes communicate by way of shared memory structures known as mutexes (mutually

exclusive). Since shared memory is also used to move database data in buffers, it helps to know that some memory buffers are reserved for engine processing and some buffers allocated (and managed dynamically) for data processing.

Network protocols and other connection types

Users can connect to the IBM Informix Server using a network connection, shared memory, pipes, DRDA, or multiplexed connections. Shared memory and pipe connections are only available on the same machine as the server instance.

Network connections are the most popular, since they can connect different machines, and will use either a TCPIP or a socket connection, depending on the

16

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch01.fm

operating system. Whichever method you choose, it is important to minimize the overhead costs associated with opening and closing connections. A developer should keep sessions open only as long as it is prudent, and re-use connections whenever possible.

Authentication and user connections

By default, authentication is determined for users connecting to a database by the existence of a user name in the operating system environment. Other authentication methods include lightweight directory access protocol (LDAP), or single sign-on (SSO) through Kerberos.

If you need a secured authentication method, the IBM Informix Server also has two secured connection methods by way of the encryppted Communication

Support Module (CSM) and single password CSM. You can use one or the other, but not both at the same time. Neither the encrypted CSM not the single password CSM method work over multiplexed connections. Enterprise

Replication (ER) and High Availability (HA) replication support encryption, but not with CSM. Secure Sockets Layer (SSL) communications are an alternative to the

Informix-specific encryption CSMs. SSL encrypts data in end-to-end and secures

TCP/IP and Distributed Relational Database Architecture™ (DRDA) connections between two points over a network. For setup information, see the developerWorks® article Protect your data with Secure Sockets Layer support in

Informix Dynamic Server, Part 1: Setting up SSL support in IDS at http://www.ibm.com/developerworks/data/library/techarticle/dm-0912securesockets

1/index.html

Programming and user process considerations

Any SQL or stored procedure call is parsed and optimized when the engine first receives the statement. Parsing and optimization methods require a little extra running time. If you can minimize this time, you can speed up query execution.

Some factors that can speed up execution time are:

򐂰 If you cannot optimize the query syntax in advance, have the DBA set the onconfig parameter OPTCOMPIND to 2, in order to use distribution data

(determined by Update statistics usage).

򐂰

If you can optimize all of your query syntax expressions in advance, you may want your DBA to consider using OPTCOMPIND 1 or 2.

򐂰 If the same statement is executed multiple times, it is placed in a procedure or dictionary cache. Cache statements run faster.

򐂰

If the statement is a prepared statement, the statement can be shared by multiple users and will not need reparsing or optimizing.

򐂰 When a statement execution thread is ready to run, it will be scheduled to run on a CPU VP. On a machine with multiple processors where each CPU VP

Chapter 1. Introduction to IBM Informix

17

7884ch01.fm

Draft Document for Review August 23, 2010 10:53 am maps to a physical processor, multiple statements can run concurrently on multiple CPU VPs. Take advantage of multiple CPU’s whenever possible by means of concurrent queries, parallel subqueries, and the degree of parallelism whenever possible.

򐂰

When a statement runs on the CPU VP, it is given a brief block of time to run.

At the end of the time unit, it is placed into a VP wait cycle and the next statement thread gets a time block on the VP queue. This gives all executing processes an opportunity to make progress, regardless of the number of processes running.

Physical and logical logging

As each of the various CPU processes are running, the database engine is keeping track of a number of operations. When data is retrieved from disk, the data image is placed in a physical log buffer. Change process information is placed in the logical log. When image data is affected by SQL processing, the physical image is periodically modified and written back to disk. During this process the physical log image and logical log information are also written into log records. Depending on the commit protocols and isolation levels, this information is available to the DBA through recovery operations if things should suddenly go wrong. Automatic recovery features built into the engine can also be used if the engine abruptly goes offline due to a power failure or crash.

Commit protocols

If transactions are made against a database that uses

unbuffered

logging, the records in the logical-log buffer are guaranteed to be written to disk during commit processing. When control returns to the application after the COMMIT statement (and before the PREPARE statement for distributed transactions), the logical-log records are on the disk. The database server flushes the records as soon as any transaction in the buffer is committed (that is, a commit record is written to the logical-log buffer).

If transactions are made against a database that uses

buffered

logging, the records are held (buffered) in the logical-log buffer for as long as possible. They are not flushed from the logical-log buffer in shared memory to the logical log on disk until one of the following situations occurs:

򐂰 The buffer is full.

򐂰 A commit on a database with unbuffered logging flushes the buffer.

򐂰 A checkpoint occurs.

򐂰 The connection is closed.

If you use buffered logging and a failure occurs, you cannot expect the database server to recover the transactions that were in the logical-log buffer when the failure occurred. Thus, you could lose some committed transactions. In return for

18

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch01.fm

this risk of using buffered logging, performance during alterations improves slightly. Only consider using buffered logging:

򐂰

If the database is updated frequently (speed of updating is important).

򐂰 If the application that is performing the transaction can continue as it is, and you decide that the price (in time and effort) of returning the database to a consistent state by either removing the effects or reapplying the transaction is too high or you can re-create the updates in the event of failure.

If a transaction failure does occur, you can simply choose to leave the database in its inconsistent state, if the transaction does not significantly affect database data.

As you consider whether to use a buffered or unbuffered logging method, remember that no automatic process or utility can perform a rollback of a committed transaction or can commit part of a transaction that has been rolled back. Without detailed knowledge of the application, messages are not enough to determine what has happened. Based on your knowledge of your application and your system, you may need to help the DBA determine when to roll back or to follow though on interrupted transactions. For more information on this topic, see the Guide to SQL:Tutorial section on Interrupted modifications at http://publib.boulder.ibm.com/infocenter/idshelp/v115/index.jsp?topic=/com.ibm.

sqlt.doc/ids_sqt_277.htm

1.3.2 Informix developer environment

The environment references you need will have some variations, depending on whether you use the IBM common client API or the native Informix Client SDK, and which operating system you use. The environment settings must include identifying references to the components. This should include:

򐂰

Setting the INFORMIXDIR environment variable to the installation directory of the software install location.

򐂰 Setting up the Informix server information (INFORMIXSERVER)

򐂰

Adding the $INFORMIXDIR/bin to the PATH environment variable

On Windows, you only have to set the Informix database server information. This is accomplished with the setnet32.exe program. On UNIX-type platforms, you may want to set the environment variables so they are set in your user profile at login, or a setup script. You also need to reference the sqlhosts file to identify the

Informix server information. In the chapters that follow, we will explain how to install the server, and provide specific details for the relevant API environment details.

Chapter 1. Introduction to IBM Informix

19

7884ch01.fm

Draft Document for Review August 23, 2010 10:53 am

Before you begin to select an API or library, you should be aware that some operating systems are not available for some of the tools, and server functionality may not be accessible with some of the APIs. Here are some API selection considerations:

򐂰

In regard to IBM Informix Client SDK:

– It is optimized for IBM Informix database servers.

– It works with PHP.

– It directly interfaces with the Informix server, no middle tier required.

– It supports all the Informix data types, extended data types, and smart

BLOBs.

򐂰 In regard to the IBM Data Server Client:

– It is optimized for compatibility and easy development with Informix and

DB2 IBM database servers.

– It works with PHP and Ruby.

– No interface is available for Apple Mac machines.

– The Data Server Client package includes support for C and Fortran development.

– There is no DataBlade API.

1.3.3 Informix capabilities

The IBM Informix database servers provide a broad spectrum of features that allow resilience in response to fast changing systems and applications in a modern business environment. If you are aware of what the product can already do before you begin to develop, it aids and enables you to support applications and easily grow to meet new demands. Here are the capabilities in the IBM

Informix:

򐂰 Resilient:

High availability and fast recovery are standard aspects of an on-demand environment. Informix database server engines have a variety of ways to configure the instance, so there is little chance of the engine being unavailable at critical points in time.

򐂰 Reliable:

In addition to availability, there is a need for continuity. Informix has options to protect a server environment, such as backup servers, full independent copies of the processing environment for failover, and workload balancing at alternate locations around the world.

20

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch01.fm

򐂰 Available:

There is an Informix solution to fit any situation that requires availability:

– Continuous availability feature

– High Availability Replication with allowance for multiple secondary servers

򐂰

Secure:

Informix supports open, industry-standard security mechanisms such as roles, password-based authentication, and RDBMS schema authorizations.

These open standards ensure flexibility and security with easy validation and verification. Column-level encryption and Pluggable Authentication Modules

(PAM) are also available. The Advanced Access Control Feature offers cell-, column- and row-level label-based access control (LBAC). This means access to data can be controlled down to the individual cell level.

򐂰

Adaptable:

Informix is adaptable from the server side and from the client side. The engine component can be stripped down, embedded, and will run with very little user intervention. Using the developer tools which are discussed in the chapters which follow, a developer can provide customized deployment by way of client applications, as well as server-side processes such as stored procedures, multiple triggers on tables and views, user defined functions, and DataBlades

򐂰

Fast:

Informix is known for fast OLTP performance. Application performance is helped by capabilities such as committed isolation level and non-blocking checkpoints which provide maximum concurrency. Direct I/O calls to file systems can result in performance similar to raw device I/O. SQL performance can be improved through techniques or configuration options which will redirect or focus the engine’s optimizer decisions. This can be done by way of optimizer directives in the SQL, or by way of automated update statistics collection which will inform the method used for running the query.

When the DBA and the developer both focus on performance, it will enable things to run more smoothly and reduce infrastructure costs.

򐂰

Flexible:

There are a number of application programmer interfaces (APIs) available, both as specific programming language supplements and as interfaces that extend the architecture of the server instance. In Informix 11 and following, the Web Feature Service API allows developers to use location-based services or location-enabled IT services. It is implemented in the Open

GeoSpatial Consortium Web Feature Service (OGC WFS) API. This API will also interact with location-based data provided by the IBM Informix Spatial and Geodetic DataBlade modules. There is a significant amount of extensibility when using DataBlade technology.

Chapter 1. Introduction to IBM Informix

21

7884ch01.fm

Draft Document for Review August 23, 2010 10:53 am

򐂰 Hidden, behind-the- scenes tasking:

Business systems and applications need to work with minimum invasions into the operations of a business environment. From the server side, applications can run in an automated mode and perform self-maintenance. From an application perspective, database administrative tasks can be controlled and run from inside an application. The SQL Administration API allows you to do tasks such as space management, monitoring and manipulating memory, running scheduled tasks, and monitoring user sessions without developer intervention after they are setup and running.

򐂰 Customizable install footprint:

The installation of Informix can be automated, and the installation footprint can be customized using the Deployment Wizard. In this way you can limit the installation only to the data server functionality you need -- to reduce the size and costs of a solution for your software deployment.

򐂰 Affordable, reduced complexity:

When IBM adds features, or the developer adds features, the first impression is that it will be more complex. With the features described up to this point, it is a surprise to discover that administration can actually be reduced more than ever before, by means of an application or one of the APIs and GUIs explained in this book.

22

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch02.fm

2

Chapter 2.

Setting up an Informix development environment

This chapter describes how to set up an environment for Informix application development including the Installation and configuration of both Informix Servers and Clients. We focus our discussion on the Informix Client products selection, installation, and configuration. After the end of this chapter, you should be able to:

򐂰 Decide which Client product is suitable for your application.

򐂰 Install and configure all Client products that can connect to Informix.

򐂰 Know any special consideration for each Client in terms of connectivity.

In this chapter, Informix database server, Informix Server, and Informix all mean the same and are used interchangeably. Also, Client products, Client, and

Informix Clients mean the same.

© Copyright IBM Corp. 2010. All rights reserved.

23

7884ch02.fm

Draft Document for Review August 23, 2010 10:53 am

2.1 Informix deployment and setup

In this section we describe the various methods of installing Informix Server. We provide how you can plan for the installation depending upon your specific requirement. We focus the discussion on the configuration required at the database server side to enable the Informix Clients connectivity.

2.1.1 Installation planning

In general, an application developer does not involve in the Informix Server product planning and installation. However, you should communicate your application requirements with the DBA who plans, installs, and configures the

Informix database server for you, for example, the need for a smart blob space, a reduced footprint of the server or DataBlades. The Informix installer provides options to install only a small footprint of the server where you can add or remove

the features as you like. We discuss more about DataBlades in 10.3,

“DataBlades and bladelets” on page 346.

2.1.2 Informix Server installation

IBM provides the Informix Server editions, described in 1.1, “Server options” on page 2

in zip, tar, or dmg format depends on the platforms. You can install

Informix Servers in many ways. The common ones are console, GUI, and silent modes of installation. Since this book is more focused on the Informix Client products for the application development, we describe only the silent mode of

Server installation on an UNIX platform. For other methods and platforms, refer to the individual installation PDF file that comes with the product.

To perform silent install in UNIX perform, use the following steps:

1. Extract the compressed tar file into any directory using the following command: tar -xvpf IIF.11.50.tar

2. Create the installation ini file that specifies the installation options. You can use the sample installation ini file, server.ini, as a template. The server.ini

file is located in the directory used to extract the server media package. Edit the following in the server.ini

and save it in a new name, say myserver.ini:

– Change -P installLocation="/opt/IBM/informix" to the location of directory where you want to install the product.

– Change -G licenseAccepted= option to true to accept the software license, otherwise, installation will not proceed.

24

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch02.fm

3. Start the silent install with the command:

./ids_install -silent -options myserver.ini

Performing these steps installs the Informix server in your specified directory along with a demonstration instance by name demo_on .

For more information about Informix installation and creating new instance, refer to the installation guide PDF that comes with the media file.

2.1.3 Configuration

The connectivity information allows a client application to connect to any IBM

Informix database server on the network. The connectivity data for a particular database server includes the following:

򐂰

The host name of the computer or node on which the database server runs

򐂰

The type of connection that an application can use to connect to it

򐂰

The service name or port number used by the database server

򐂰

Database instance (also called database server name)

Even if the client application and the database server are on the same computer or node, you may need to specify connectivity information for your client application.

Connectivity on UNIX

On UNIX, the sqlhosts configuration file contains the connectivity information.

By default this file resides in the $INFORMIXDIR/etc directory. The

INFORMIXSQLHOSTS environment variable can be used to specify an alternative location for the connectivity information. Edit this file according to the protocol you are using or the port number to which your client application will connect. A typical sqlhosts file contains the following fields:

Server Protocol Hostname Service/port Options

Here is an example: demo_on onipcshm on_hostname on_servername k=0 demo_se seipcpip se_hostname sqlexec

Each line in the sqlhost file normally defines an Informix database server:

򐂰 Server: Specifies the name of the IBM Informix database server. This value normally correspond to the value in the INFORMIXSERVER environment variable.

򐂰

Protocol: Specifies the protocol used for the communication with the database server. This must be the same protocol as used by the database server.

Chapter 2. Setting up an Informix development environment

25

7884ch02.fm

Draft Document for Review August 23, 2010 10:53 am

򐂰 Hostname: Specifies the machine where the Informix database server is running.

򐂰

Service/port: Specifies the tcp port or service name, which must be defined in the /etc/services file, used by the Informix database server to accept incoming connections.

򐂰 Options: Specify additional options for the communication, such as buffer size or connection redirection rules.

APIs such as ESQL/C or ODBC relay on the sqlhosts file to obtain the connection parameters for the database server.

Example 2-1 shows how a ESQL/C application connects to an Informix database

server.

Example 2-1 UNIX connection example

informix@kodiak:/work$ cat $INFORMIXDIR/etc/sqlhosts

#server protocol hostname service/port

demo_on onsoctcp kodiak demo_on_tcp

informix@kodiak:/work$ grep demo_on_tcp /etc/services

demo_on_tcp 9089/tcp # Service for demo_on IDS server informix@kodiak:/work$ cat connect.ec

#include <stdio.h> int main()

{

EXEC SQL CONNECT TO 'stores_demo@demo_on';

printf("Connected\n");

} informix@kodiak:/work$ esql connect.ec -o connect informix@kodiak:/work$ ./connect

Connected

informix@kodiak:/work$

The definition for the demo_on

Informix server specifies the communication protocol used as onsoctcp

; the machine where the database server is running is kodiak

; and the TCP port used by the server is

demo_on_tcp

. The service name is defined as port

9089

in the

/etc/services

configuration file.

The ESQL/C example connects to the server and opens the stores_demo database using the instruction:

EXEC SQL CONNECT TO 'stores_demo@demo_on';

For more information about the sqlhosts configuration file refer to the Installing

and Connecting to Client guide at:

26

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch02.fm

http://publib.boulder.ibm.com/infocenter/idshelp/v115/index.jsp?topic=/com.ibm.

admin.doc/ids_admin_0158.htm

Connectivity on Windows

You can set the connectivity on Windows using the program setnet32.exe

that resides in

$INFORMIXDIR/bin

. This utility comes bundle with the Client SDK package. Use this utility to create or change the server name, protocol, service name, and host name. You also can use setnet32.exe

to set any environment

variable used by the Informix products. Figure 2-1 on page 27 shows the Server

Information tab of setnet32.exe utility on Windows where you can specify the server name, host IP address, network protocol, and service name.

Figure 2-1 setnet32 Server Information tab

Note: If you specify the name of the service (for example:

sqlexec ) rather than the port number, make sure the service name used appears in the Windows

services file located in C:\WINDOWS\system32\drivers\etc

DRDA support

Since version 11.x, Informix supports the DRDA protocol. If you plan to use the

Data Server driver packages to connect to informix database server, you must enable DRDA support.

Chapter 2. Setting up an Informix development environment

27

7884ch02.fm

Draft Document for Review August 23, 2010 10:53 am

Windows

Use

Setnet32

to configure an Informix instance to use DRDA protocol. Perform the following steps:

1. Start

setnet32

from any command window.

2. Go to Server Information tab (Figure 2-2 on page 28).

3. Select the required instance from the IBM Informix Server field. Our example is demo_my .

4. Change the name of the Informix server and specify a new name for the

DRDA alias, for example demo_my_drda

5. HostName is pre-filled, if not, enter your host name or IP address.

6. Change the Protocolname from olsoctcp to drsoctcp to make it DRDA compliant.

7. Change the Service Name specifying the service name or port number the

DRDA alias will use.

8. Click Apply and OK.

Figure 2-2 Configuring DRDA support

After adding all the connection details for the DRDA alias, the configuration file for the Informix database server must be updated to link the new server definition

28

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch02.fm

with the existing Informix instance, in our example we are using demo_my for the

Informix database server and demo_my_drda for the DRDA instance.

The DBSERVERALIASES parameter inside the configuration file is used to

specify alias for a database server. Example 2-2 shows this parameter

Example 2-2 dbservername onconfig sample

...

DBSERVERNAME demo_my # Name of default Dynamic Server

# DBSERVERNAME or DBSERVERALIASES that uses a

# DBSERVERALIASES - The list of up to 32 alternative dbservernames,

DBSERVERALIASES demo_my_drda # List of alternate dbserver names

# DBSERVERNAME or DBSERVERALIASES that uses ...

...

The database configuration file is located in etc

directory of your Informix database server. The environment variable ONCONFIG is used to specify the name of this file. The complete path using environment variables for the database configuration file is:

򐂰 On a UNIX platform, $INFORMIXDIR\etc\$ONCONFIG

򐂰 On a Windows platform, %INFORMIXDIR%\etc\%ONCONFIG%

The Informix database engine must be restarted for the changes to take effect.

After these step is done, your instance is now ready to accept connections as a

DRDA compliant server.

On windows, you can enable the DRDA support for the demonstration instance

during the installation if you use the Custom install. Figure 2-3 shows the

installation panel where you can enable the DRDA support.

Chapter 2. Setting up an Informix development environment

29

7884ch02.fm

Draft Document for Review August 23, 2010 10:53 am

Figure 2-3 Enable DRDA support for the default instance

Linux and UNIX

On Linux and UNIX systems, you can enable the DRDA support by editing some of the Informix configuration files:

򐂰 Edit your sqlhosts file specified in the $INFORMIXSQLHOSTS environment variable and add the following line:

<drda_name> drsoctcp <hostname> <drda_service_name>

– drda_name, is the name for the drda alias

– drsoctcp, protocol used by the new alias

– hostname, name or IP address of the machine running the Informix server

– drda_service_name, name of the TCP service or port number for the drda instance

򐂰 Edit the Informix server configuration file located in the etc directory of your

Informix server directory to include the new database definition as an alias for the existing Informix server.

You can use the environment variables to access this file, for example,

$INFORMIXDIR/etc/$ONCONFIG . This is the file containing a list of configuration

30

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch02.fm

parameters for the informix server. Example 2-3 shows the configuration file

used in our database server.

Example 2-3 Linux onconfig sample

informix@irk:/usr3/11.50$ grep DBSERV $INFORMIXDIR/etc/$ONCONFIG

# DBSERVERNAME - The name of the default database server

# DBSERVERALIASES - The list of up to 32 alternative dbservernames,

# DBSERVERNAME or DBSERVERALIASES that uses a

DBSERVERNAME demo_my

DBSERVERALIASES demo_my_drda

The Informix server must be restarted for these changes to take effect.

You can find additional information about the sqlhost file at http://publib.boulder.ibm.com/infocenter/idshelp/v115/topic/com.ibm.admin.doc/i ds_admin_0158.htm

2.2 Client setup

Informix is a low-administration, easy-to-use, and embeddable database that supports various application development languages and technologies such as

Java, .NET, PHP, and Web services. Informix can handle XML data easily and can be extended to handle new data sets using DataBlades.

In this section, we describe how to install and configure the Informix Client products to support the application development you need.

2.2.1 Client options

IBM offers the following Client products to develop and use an IBM Informix database server:

򐂰

IBM Informix Client Software Development Kit (Client SDK), includes several

APIs designed for develop against an Informix database.

򐂰 IBM Informix Connect (IConnect), runtime version of Client SDK

򐂰

IBM Informix JDBC driver, Java driver optimized for Informix databases

򐂰 IBM Data Server Client. Includes all the API tools needed for development against IBM databases such as DB2 and Informix plus functionality for database administration and client/server configuration

򐂰

IBM Data Server Runtime Client, runtime version of the IBM Data Server

Client.

Chapter 2. Setting up an Informix development environment

31

7884ch02.fm

Draft Document for Review August 23, 2010 10:53 am

򐂰 IBM Data Server Driver Package, lightweight version of the IBM Data Server

Runtime only including the interfaces and drivers.

򐂰

IBM Data Server Driver for JDBC and SQLJ, Java driver for IBM Data

Servers.

The Informix Client SDK and IConnect products have distinct functionalities:

򐂰 Client SDK contains a group of application-programming interfaces (APIs) that developers can use to write applications for Informix, plus other client components. Informix Client SDK must be installed on computers that application programmers will use to write applications.

򐂰

IConnect contains runtime libraries of the Client SDK APIs, plus other client components. Install IConnect on computers that end-users will use to connect to Informix database servers.

Same rule applies to the IBM Data Server products. Packages designed for development like the IBM Data Server Client should not be used to deploy an application. Some components such as the Informix JDBC driver do not have a specific runtime version, so the same product can be used for both cases.

In addition to these products, there are some open source drivers such as PHP or Ruby driver, which can be used to develop against an IBM Informix database.

Figure 2-4 on page 33 illustrates the options available to develop against an IBM

informix database.

32

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch02.fm

Figure 2-4 Available Client products for application development

2.2.2 Setting up IBM Informix Client Software Development Kit

IBM Informix Client Software Development Kit (Client SDK) is a collection of components for developing and running client applications that connect to the

Informix database server. Client SDK bundles with the following components and utilities:

򐂰 ESQL/C with XA support

򐂰

IBM Informix Object Interface for C++

򐂰 IBM Informix OLE DB Provider (Windows only)

򐂰

IBM Informix ODBC Driver with MTS support

򐂰 IBM Informix .NET Provider (Windows only)

򐂰

IBM Informix GLS

򐂰 The Global Security Kit (GSKit)

򐂰

Password Communication Support Modules (CSM)

򐂰 Documentation Viewer

򐂰

The finderr

utility on UNIX systems and the Informix Error Messages utility on Windows systems

򐂰 The ILogin utility (Windows only)

Chapter 2. Setting up an Informix development environment

33

7884ch02.fm

Draft Document for Review August 23, 2010 10:53 am

Starting from version 3.50.xC5 the IBM Data Server Driver Package is also bundled with the Windows version of Informix Client SDK and IConnect.

Informix Client SDK provides access to all the IBM Informix database servers.

Table 2-1 lists the Informix database servers that supports Informix Client SDK.

Table 2-1 Supported database servers

Database server

IBM Informix

IBM Informix Extended Parallel Server

IBM Informix Standard Engine

IBM Informix Online

Versions

7.x, 9.x,10.x and 11.50

8.50 and higher

7.25

5.20 and higher

Some components such as Informix OLE DB Provider do not allow a connection to an IBM Informix Standard Engine server. Refer to the component release notes for more information http://publib.boulder.ibm.com/infocenter/idshelp/v115/topic/com.ibm.relnotes.do

c/relnotes_csdk350xc7.html

Installation

Before you install Client SDK, perform the following preliminary tasks:

򐂰 Determine locations:

– Media location: This is the directory location where all the media files reside.

– Installation location: This is the location where Installer will place all the binaries and the configuration files. This directory is represented by the environment variable $INFORMIXDIR . If $INFORMIXDIR is set, this will be the default install location.

– Java location: The script used during the install process requires the use of a Java virtual machine (JVM). A JVM is bundled together with the Client

SDK package, but if required, It is possible to specify a different JVM for the install process. The minimum version is Sun JRE is 1.4.2

򐂰 Prepare the environment

You only need to check if you have the

informix

user and the

informix

group on your computer, otherwise create them. For additional information about this topic refer to the section Preparing to install IDS and client products at: http://publib.boulder.ibm.com/infocenter/idshelp/v115/topic/com.ibm.igul.do

c/ids_in_005x.htm

34

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch02.fm

Informix provides various methods for Client installation. Here we demonstrate the GUI mode installation for both UNIX and Windows environments.

Installing Client SDK on UNIX using GUI

Perform these steps to install Client SDK installation in GUI mode:

1. Start the installation GUI with the following command from the root user.

./installclientsdk -gui

Remember to set the DISPLAY environment variable to the window which you

want to project the Installation. Figure 2-5 shows the Welcome panel.

Figure 2-5 Installation of Client SDK on UNIX

2. On the license agreement panel, select I accept the terms and the license

agreement.

3. Figure 2-6 on page 36 shows the next panel for specifying the directory to

where you want to install the Client. Enter the full path name.

Chapter 2. Setting up an Informix development environment

35

7884ch02.fm

Draft Document for Review August 23, 2010 10:53 am

Figure 2-6 Directory where you like to install

4. On choosing setup type panel (Figure 2-7), select Typical or Custom. The

difference between Custom and Typical is that the Custom mode allows you to select the features to be installed.

Figure 2-7 Do you want to install with the custom option or the typical one.

36

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch02.fm

5. Figure 2-8 shows the features that you can select on the Custom mode. If you

would like to install whatever the installer offers, select the Typical mode.

Figure 2-8 Custom options to choose

6. The installer presents the summary of available space and the components

you have chosen for installation, see Figure 2-9 on page 38. At this stage you,

can go back and change the installation selections. Click Next to start the installation.

Chapter 2. Setting up an Informix development environment

37

7884ch02.fm

Draft Document for Review August 23, 2010 10:53 am

Figure 2-9 Installation summary

7. Figure 2-10 shows that the Installation is complete without any errors.

Figure 2-10 Installation complete without any errors

At this stage the Client SDK installation is complete. If the Informix database server is located on a different machine, you may need to setup the connection information and modify the sqlhosts file, using the details of your Informix server.

38

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch02.fm

Installing Client SDK on Windows

Installation on Windows for Client is similar to UNIX installation except that at the end, the Windows installation has the option to install IBM Data Server Driver

Package. If you select the option to install these drivers, refer to “Installing IBM

Data Server Driver Package” on page 41 for Installation details.

Configuration utility

On Windows, the Client SDK comes bundled with the setnet32.exe

utility for configuring the Client SDK. The Clint SDK has default values set and is ready to use unless you want to change the protocol, server information, or any environment variable under which the client application runs.

The

Setnet32

utility sets environment variables and network parameters that IBM

Informix products use at run time. The environment variables and connectivity parameters are stored in the Windows system registry and are valid for every

IBM Informix Client product that you install except the Informix JDBC driver.

The Setnet32 utility has the following tabs:

򐂰 Environment tab allows you to set environment variables.

򐂰

Server Information tab allows you to set database server network information.

򐂰 Host Information tab allows you to set your host computer and login information.

򐂰

About Setnet32 tab provides the information about the

Setnet32

utility.

For more information about these tabs, refer to the Client SDK installation PDF file that comes with the Client SDK product.

Special consideration for 32/64 bit products

Beginning with version 3.50.FC4, you can install both 32-bit and 64-bit Client

SDK on the same Windows machine.

Before installing the version 3.50.FC4 product, you must uninstall the existing version 3.50.FC3 or earlier Client SDK from your machine.

To uninstall your existing products, do one of the following:

򐂰 Use the Add/Remove program, or

򐂰

Run the setup.exe from the installed product media. When the Maintenance

Menu appears, select Remove.

Your new 32-bit and 64-bit products must be installed in separate directories.

The default location for the 32-bit Informix Client SDK is

C:\Program Files (x86)\IBM\Informix\Client-SDK

Chapter 2. Setting up an Informix development environment

39

7884ch02.fm

Draft Document for Review August 23, 2010 10:53 am

The 64-bit Informix Client SDK default directory is

C:\Program Files\IBM\Informix\Client-SDK

The 64-bit product installation adds a suffix to the Program group folder and the

Add/Remove entry. This suffix provides an easy identification between the 32-bit

(no suffix) and 64-bit (suffix) product installations. For more information, refer to the release notes.

2.2.3 Setting up

IBM Data Server drivers

There are several types of IBM Data Server Clients and drivers available:

IBM Data Server Clients:

򐂰

IBM Data Server Client, contains all the APIs and tools needed for development against DB2 and Informix databases including tools for remote administration.

򐂰 IBM Data Server Runtime Client, contains all the APIs but only the minimum number of utilities for setup and configure the development environment.

򐂰

IBM Data Server Driver Package, contains only the APIs and drivers without any additional tool.

The client products contain the APIs and drivers plus additional tools designed for remote database administration and configuration of the client environment.

IBM Data Server Drivers:

򐂰 IBM Data Server Driver for JDBC and SQLJ

򐂰 IBM Data Server Driver for ODBC and CLI

򐂰 IBM Data Server Driver for .NET

򐂰 IBM Data Server Open Source drivers such as PHP or Ruby

Some of these components can also be download and installed as a separate product.

Each IBM Data Server Client and driver provides a particular type of support:

򐂰

For Java applications only, use IBM Data Server Driver for JDBC and SQLJ.

򐂰 For applications using ODBC or CLI only, use IBM Data Server Driver for

ODBC and CLI

򐂰

For applications using ODBC, CLI, .NET, OLE DB, PHP, Ruby, JDBC, or

SQLJ, use IBM Data Server Driver Package.

򐂰 IBM Data Server Runtime Client and IBM Data Server Client includes all of above drivers and some functions of DB2.

40

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch02.fm

In this section we discuss the installation and configuration of the following drivers for UNIX and Windows platforms:

򐂰

IBM Data Server Driver for JDBC and SQLJ

򐂰

IBM Data Server Driver for ODBC and CLI

򐂰

IBM Data Server Driver Package

For the installation and configuration of IBM Data Server Runtime Client and IBM

Data Server Client, refer to http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/index.jsp?topic=/com.ibm.s

wg.im.dbclient.install.doc/doc/c0022615.html

Installing IBM Data Server Driver Package

The IBM Data Server Driver Package is a lightweight solution and the recommended package for end user code deployment. It provides robust runtime support for applications using ODBC, CLI, .NET, OLE DB, PHP, Ruby, JDBC, or

SQLJ without the need of installing Data Server Runtime Client or Data Server

Client. Here we discuss the installation of the drivers presented under the IBM

Data Server Driver Package.

Installation of driver package on UNIX and Linux

You can download the IBM Data Server Driver Package and individual drivers such as IBM Data Server Driver for JDBC and SQLJ from IBM Support and

downloads website the at http://www.ibm.com/support/docview.wss?rs=4020&uid=swg21385217

Uncompress and extract IBM Data Server Drivers Package to an empty directory. after download.

If you want to install the complete IBM Data Server Driver Package, run the installIDSDriver

command. This driver package includes database drivers for

Java, ODBC/CLI, PHP, and Ruby on Rails, each of which is stored in its own subdirectory. The Java and ODBC/CLI drivers are compressed.

If you like to install individual drivers contained in the driver package, follow these steps (first two steps are common for all drivers):

1. Uncompress the Data Server Driver Package archive onto the target machine.

2. For the Java and ODBC/CLI drivers, uncompress the driver file into the chosen install directory.

3. Install the driver you need:

– Java

Chapter 2. Setting up an Informix development environment

41

7884ch02.fm

Draft Document for Review August 23, 2010 10:53 am

This driver provides support for client applications written in Java using

JDBC. The path and file name of the Java driver are

• Path: jdbc_sqlj_driver

/platform

• File name: db2_db2driver_for_jdbc_sqlj.zip

For the additional details refer to “Installing IBM Data Server Driver for

JDBC and SQLJ” on page 47

– ODBC and CLI

The open source drivers included in the IBM Data Server Driver Package such as PHP or Ruby driver, require the use of the Data Server CLI driver for connection to the database engine. If you plan to use any of these driver you need to install the ODBC this driver.

• Path: odbc_cli_driver

/platform.

• File name: ibm_data_server_driver_for_odbc_cli.tar.Z

For additional information refer to “Installing IBM Data Server Driver for

ODBC and CLI” on page 48

– PHP

The IBM_DB2 and PDO_IBM are the PHP extensions for IBM Data

Servers including Informix. Installing the IBM_DB2 or PDO_IBM extensions enables any application in the PHP environment to interact with

Informix database servers. The extensions included with the IBM Data

Server Driver Package might be of a lower version as compared to the one available on the PHP repository. You should download the latest extension from PHP repository page as it might contain important fixes and new features available:

• For IBM_DB2: Download from http://pecl.php.net/package/ibm_db2

• For PDO_IBM: Download from http://pecl.php.net/package/pdo_ibm

The PHP driver path and file names in the IBM Data Server Driver

Packages are

• Path: php_driver/platform/php32

or php_driver/platform/php64

• Files: ibm_db2_n.n.n.so

and pdo_ibm_n.n.n.so

, where n represents the version of the extension.

The following is installation information:

• Prerequisite: The PHP drivers require the ODBC/CLI driver that is also included in the IBM Data Server Driver Package to be installed.

• Installation instructions:

Following links explain how to install PECL extensions:

Through the source code:

42

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch02.fm

http://www.php.net/manual/en/install.pecl.phpize.php

Through PECL command: http://www.php.net/manual/en/install.pecl.pear.php

Installing IBM_DB2 extension: http://www.php.net/manual/en/ibm-db2.installation.php

Installing PDO_IBM extension: http://www.php.net/pdo_ibm

– Ruby on Rails

The IBM_DB adapter and driver as a gem enables any application in the

Ruby environment, including Rails, to interact with IBM data servers. The path, file name, and installation information for Ruby on Rails driver are

• Path: ruby_driver/platform

• File: ibm_db-0.10.0.gem

• Prerequisite: The Ruby on Rails driver requires the ODBC/CLI driver that is also included in the IBM Data Server Driver Package to be installed.

• To install the Ruby on Rails driver, from the location of the gem file, run the following command gem install ibm_db-0.10.0.gem

At this stage you are ready to use any of the driver mentioned above on UNIX or

Linux.

Installation of driver package on Windows

You can obtain the Data Server Driver Package for windows from the same site as the Package for UNIX: http://www.ibm.com/support/fixcentral/

The file for Windows is an .exe file which is the install file for the driver package.

The installations steps are as below:

1. Start the installation by executing the.exe file. Figure 2-11 on page 44 shows

the welcome window.

Chapter 2. Setting up an Informix development environment

43

7884ch02.fm

Draft Document for Review August 23, 2010 10:53 am

Figure 2-11 Welcome panel for Data Server Driver Package

2. On the Software License Agreement panel, accept the license agreement.

3. Specify the installation directory in the Custom Setup panel (Figure 2-12). You

can change the installation directory to other location then the default.

Figure 2-12 Change the Install directory

44

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch02.fm

4. The IBM data server driver copy name is used to identify a location where

IBM Data Server Driver Package is installed on the computer. Enter the copy name for the location you have chosen, the default is IBDBCL1. See

Figure 2-13 on page 45.

Figure 2-13 Set the IBM data server driver copy name

5. Verify the installation selections on the summary panel (Figure 2-14). If

everything is correct, proceed the installation by clicking Install.

Chapter 2. Setting up an Informix development environment

45

7884ch02.fm

Draft Document for Review August 23, 2010 10:53 am

Figure 2-14 The summary of Install

6. When the Installer completes, you see the complete panel as shown in

Figure 2-15 on page 46. After clicking Finish, you are done with the

installation of Data Server driver for Informix, and are ready to use one.

Figure 2-15 Last panel of Installer

46

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch02.fm

Note: The Windows installer of the IBM Data Server Driver Package does not

provide any option for install individual components. All the driver and interfaces included in the package are installed by default.

Installing IBM Data Server Driver for JDBC and SQLJ

The installation procedures is as follows:

1. Obtain Java SDK.

Before you install the IBM Data Server Driver for JDBC and SQLJ, you must have an SDK for Java installed on your computer:

– For JDBC 3.0 functions, you need Java SDK 1.4.2 or later.

– For JDBC 4.0 functions, you need Java SDK 6 or later.

2. Download the zip file for the latest version of the IBM Data Server Driver for

JDBC and SQLJ from http://www.ibm.com/software/data/support/data-server-clients/download.html

.

3. Unzip the IBM Data Server Driver for JDBC and SQLJ zip file to the installation location. The zip file contains the following files:

– db2jcc.jar

– db2jcc4.jar

– sqlj.zip

– sqlj4.zip

4. Modify the CLASSPATH environment variable to include the appropriate files,

You can set the CLASSPATH using the command:

java -classpath <dir>\<file>.jar

– For JDBC:

Include db2jcc.jar in the CLASSPATH if you plan to use the version of the

IBM Data Server Driver for JDBC and SQLJ that includes only JDBC 3.0 and earlier functions.

Include db2jcc4.jar in the CLASSPATH if you plan to use the version of the

IBM Data Server Driver for JDBC and SQLJ that includes JDBC 4.0 and earlier functions.

Important: Include either db2jcc.jar or db2jcc4.jar in the CLASSPATH.

Do not include both files.

– For SQLJ

The steps are similar to the JDBC except that the files to be included in

CLASSPATH are sqlj.zip and sqlj4.zip.

Chapter 2. Setting up an Informix development environment

47

7884ch02.fm

Draft Document for Review August 23, 2010 10:53 am

For more information regarding configuration and customizing of the IBM Data

Server Driver for JDBC and SQLJ, refer to http://publib.boulder.ibm.com/infocenter/idshelp/v115/topic/com.ibm.jccids.doc/ ids_jcc_0008.htm

Installing IBM Data Server Driver for ODBC and CLI

The IBM Data Server Driver for ODBC and CLI solution is designed mainly for independent software vendor (ISV) deployments.To install the IBM Data Server

Driver for ODBC and CLI, perform the following steps:

1. Depending on your operating system, download the compressed file from https://www14.software.ibm.com/webapp/iwm/web/preLogin.do?land=en_US&source

=swg-informixfpd

2. Uncompress or unzip the file to a installation directory of your choice.

3. On Mac OS X, set the DYLD_LIBRARY_PATH environment variable to the clidriver/lib directory path.

For specific information about the setup and configuration of the ODBC refer to

3.2, “Setup and configuration” on page 54.

2.2.4 Setting up Informix JDBC

Informix JDBC is a platform independent, industry standard driver that provides enhanced support for distributed transactions. It consists of a set of interfaces and classes written in the Java programming language which can run on AIX,

HP-UX, Linux, Solaris, Windows, and all other platforms that support Java. It also supports extensibility with a user-defined data type (UDT) routine manager that simplifies the creation and use of UDTs.

JCC support is available through the IBM Data Server Driver package which has a driver to run Java application using JCC.

This section describes the installation of JDBC driver for Informix that is bundled with the Informix database server. There is a separate JDBC directory with a jar file inside when you extract the Informix database server install media .

The IBM Informix JDBC Driver, Version 3.50 strives to be compliant with the Sun

Microsystems JDBC 3.0 specification. Nearly all the features that are required for the Sun Microsystems JDBC 3.0 specification have the specified behavior. For the Sun Microsystems JDBC 3.0 driver optional features, if the feature is supported by IBM Informix Version 11.50, then it is supported by Informix JDBC

Driver, Version 3.50.

48

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch02.fm

IBM Informix JDBC Driver is a native-protocol, pure-Java driver (Type 4). This means that when you use IBM Informix JDBC Driver in a Java program that uses the JDBC API to connect to an Informix database, your session connects directly to the database or database server, without a middle tier

Installation

The JDBC driver installation procedure is same for both Windows and UNIX platforms.

To install the JDBC driver in console mode, use the following command: java -cp dir/setup.jar run -console

For silent Install on both Windows and UNIX, run the following command from a command prompt: java -cp <dir>/setup.jar run -silent -P product.installLocation=<destination-dir> where:

<dir> is the location of setup.jar file.

<destination-dir> is the directory where you want to install the JDBC Driver.

The installation is complete when the command has finished executing. If you want to log information during the installation, specify the -log parameter.

Perform these steps to install Informix JDBC Driver in GUI mode on Windows:

1. Start the GUI mode installation with the following command: java -cp dir/setup.jar run

Figure 2-16shows the Welcome panel.

Chapter 2. Setting up an Informix development environment

49

7884ch02.fm

Draft Document for Review August 23, 2010 10:53 am

Figure 2-16 Starting panel for JDBC informix Install

2. Accept the license agreement on the IBM License Acceptance Panel.

3. Specify the installation directory or use the default location as shown in

Figure 2-17.

Figure 2-17 Specify the Install directory

4. Review the information on the summary panel (Figure 2-18 on page 51) and

continue to complete the installation.

50

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch02.fm

Figure 2-18 Summary screen

Configuration

To use IBM Informix JDBC Driver in an application, you must set your

CLASSPATH environment variable to point to the driver files. The CLASSPATH environment variable tells the Java Virtual Machine and other applications where to find the Java class libraries used in a Java program-log parameter.

UNIX

There are two ways to set your CLASSPATH environment variable:

򐂰 Add the full path name of ifxjdbc.jar to CLASSPATH: setenv CLASSPATH /jdbcdriv/lib/ifxjdbc.jar:$CLASSPATH

򐂰 Unpack ifxjdbc.jar and add its directory to CLASSPATH: cd /jdbcdriv/lib jar xvf ifxjdbc.jar

setenv CLASSPATH /jdbcdriv/lib:$CLASSPATH

Windows

Use one of the following methods to set your CLASSPATH environment variable:

򐂰 Add the full path name of ifxjdbc.jar to CLASSPATH: set CLASSPATH=c:\jdbcdriv\lib\ifxjdbc.jar;%CLASSPATH%

򐂰 Unpack ifxjdbc.jar and add its directory to CLASSPATH: cd c:\jdbcdriv\lib jar xvf ifxjdbc.jar

set CLASSPATH=c:\jdbcdriv\lib;%CLASSPATH%

At this stage you are ready to develop a Java application using JDBC.

Chapter 2. Setting up an Informix development environment

51

7884ch02.fm

Draft Document for Review August 23, 2010 10:53 am

52

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch03.fm

3

Chapter 3.

Working with the ODBC driver

This chapter discusses the configuration and development of applications using

Open Database Connection (ODBC) interfaces to access an Informix database server.

This chapter describes the following:

򐂰 Types of ODBC drivers available

򐂰 Configuration

򐂰 Supported data types and mapping between SQL, C, and ODBC

򐂰 Perform basic database operations

򐂰 How to work with extended data types

򐂰 Error handling

򐂰 Diagnose typical problems

© Copyright IBM Corp. 2010. All rights reserved.

53

7884ch03.fm

Draft Document for Review August 23, 2010 10:53 am

3.1 ODBC and Informix

Open Database Connectivity (ODBC) is a software API method based on the

X/Open Call Level Interface to access data from a database management system. ODBC allows developers to write database applications without having to know a proprietary interface for a specific database. In an ODBC environment, the ODBC driver is the component that directly communicates with the database server. It receives calls from the application or the ODBC Driver Manager and converts those calls into messages that the database server understand.

The available ODBC drivers for Informix are:

򐂰 IBM Informix ODBC Driver

򐂰 IBM Data Server Driver for ODBC and CLI (CLI Driver)

3.2 Setup and configuration

In this section, we discuss the setup and configuration parameters of the ODBC driver.

3.2.1 IBM Informix ODBC Driver

The Informix ODBC Driver is installed by default as part of the Informix Client

SDK package. It is based on the Microsoft Open Database Connectivity (ODBC)

Version 3.0 standard.

Table 3-1 lists the Informix database server that support Informix ODBC.

Table 3-1 Supported databases

Database server

IBM Informix

IBM Informix Extended Parallel Server

IBM Informix Standard Engine

IBM Informix Online

Versions

10.0,11.10,11.50

8.50 and higher

7.25

5.20 and higher

Windows configuration

On a Windows machine the ODBC drivers is automatically registered within the system during the Informix installation process.

54

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch03.fm

The default installation directory is

C:\Program Files\IBM\Informix\Client-SDK. The INFORMIXDIR environment variable should point to the directory where the product was installed.

Note: If you install a 32-bit version of Informix Client-SDK on a Windows x64,

the default directory is C:\Program Files (x86)\IBM\Informix\Client-SDK

The ODBC driver requires loading additional libraries that are located in the

%INFORMIXDIR%\bin

directory, make sure this directory is part of your PATH variable.

The name of the ODBC driver depends on the version:

򐂰 IBM INFORMIX ODBC DRIVER: For the Windows 32-bit driver, see

Figure 3-1.

Figure 3-1 Windows x86 ODBC driver administrator

򐂰

IBM INFORMIX ODBC DRIVER (64-bit): for the Windows 64-bit driver. See

Figure 3-2 on page 56.

Chapter 3. Working with the ODBC driver

55

7884ch03.fm

Draft Document for Review August 23, 2010 10:53 am

Figure 3-2 Windows x64 ODBC driver administrator

To create an Informix ODBC Data Source (DSN), open the ODBC Administrator, choose a DSN type, and select the Informix ODBC driver, the DSN-configuration parameters are common to both drivers (32-bit and 64-bit).

Note: The default ODBC Data Source Administrator on a Windows x64

machine is the 64-bit version. If you want to create a 32-bit ODBC DSN you must use the 32-bit version

C:\WINDOWS\SysWOW64\odbcad32.exe

Figure 3-3 on page 57 shows the Informix ODBC Connection tab.

56

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch03.fm

Figure 3-3 Connection parameters

Table 3-2 lists the required DSN parameters. If you have already defined an

Informix server using the Setnet32 tool, part of Informix Client SDK, most of these values would be automatically updated when selecting an Informix server from the dropdown box.

Table 3-2 Required DSN values

Parameter Description

Data source name Name of the DSN

Server name

Host name

Service

Protocol

Database

Name of the Informix database server

Name or IP address of the computer where the database server runs

Name or value of the tcp service used by the database server

Communication Protocol used by the database server

Name of the database to which the DSN connects by default

You can set optional configuration parameters in the Environment and Advanced

tabs (Figure 3-4 on page 58).

Chapter 3. Working with the ODBC driver

57

7884ch03.fm

Draft Document for Review August 23, 2010 10:53 am

Figure 3-4 Environment parameters

Table 3-3 describe the parameters for the Environment tab.

Table 3-3 Environment parameters

Parameter Description

Client Locale Locale for the client machine

Database Locale Locale used when the database was created

Use Server Database Locale Using this option the Database Locale is automatically retrieved from the database

Translation Library Codeset conversion library

Translation Option

Cursor Behavior

VMB Character

Options for a third party conversion library

Close or preserve a cursor when a transaction is resolved

How to report the length for Varying Multi byte characters

Size of the communication data package Fetch Buffer Size

Isolation Level Default Isolation Level for the connection

58

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch03.fm

Note: The codeset value for the

Client Locale

parameter is determined by the codeset used in the application which, in most cases, is the same as the operating system. The default codeset on a Windows machine is

CP1252.

The default codeset for an Informix database is

en_us.8859-1

(ISO 8859-1).

Some versions of the IBM Informix database server (for example, Version 9.40 and Version 10.00) allow a connection from a client with a mismatched

DB_LOCALE value. This option is no longer available. A client application must set the Database Locale parameter (DB_LOCALE) to the same value as the locale of the database (locale used at creation time).

The typical syntax for an Informix locale is language_territory@codeset .

Figure 3-5 shows the Advanced configuration parameters.

Figure 3-5 Advanced parameters

Table 3-4 describes the parameters for the Advanced tab.

Table 3-4 Advanced parameters

Parameter

Auto Commit Optimization

Open-Fetch-Close Optimization

Description

Optimize client-server communication deferring the commit work after all the cursors are close.

Optimize client-server communication automatically closing the cursor after all the rows have been retrieved.

Chapter 3. Working with the ODBC driver

59

7884ch03.fm

Draft Document for Review August 23, 2010 10:53 am

Parameter

Insert Cursors

Scrollable Cursors

Report KeySet Cursors

Description

Buffers all the rows send by an insert cursor and uses only one package to send the data to the server.

Enable scrollable cursors.

Report support for KeySet-driver cursors.

Report Standard ODBC Types Only Report standard ODBC types Only. Extended types are mapped to standard ODBC types.

Describe Decimal Floating Point as

SQL_REAL / SQL_DOUBLE

Do Not Use Lvarchar

Decimal columns without a scale are reported as SQL_REAL or SQL_DOUBLE.

Do not report Lvarchar columns when using

SQL_VARCHAR.

Report Char columns as Wide Char columns length in Chars for

SQLGetDiagRecW

Char columns described by SQLDescribeCol are reported as Wide char columns

(SQLWCHAR)

Returns the number of characters rather than the number of bytes.

You can obtain more information about each one of these parameters by placing

the cursor over a parameter and pressing the F1, see Figure 3-6 on page 61.

60

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch03.fm

Figure 3-6 ODBC DSN Help

UNIX configuration

On UNIX platforms, the default installation directory for Informix Client SDK is

/opt/IBM/informix.

The INFORMIXDIR environment variable should point to the directory where the product was installed.

On UNIX platforms, an ODBC driver manager is not normally supplied as part of the operating system. Informix Client SDK does not include an ODBC driver manager library, however, the Client SDK does have a Driver Manager

Replacement (DMR) library which provides most of the features of an ODBC driver manager.

If the application does not use an ODBC driver manager such as UnixODBC

Driver Manager or Data Direct Driver Manager, the application must be linked directly to the Informix ODBC libraries. The ODBC libraries are located at

$INFORMIXDIR/lib/cli.

Table 3-5 shows the ODBC libraries included with Client SDK.

Chapter 3. Working with the ODBC driver

61

7884ch03.fm

Draft Document for Review August 23, 2010 10:53 am

Table 3-5 UNIX ODBC libraries

Library

libifcli.a or libcli.a

libifcli.so or iclis09b.so

libthcli.a

libthcli.so or iclit09b.so

libifdrm.so or idmrs09a.so

Description

Static version for single (nonthreaded)

Shared version for single (nonthreaded)

Static version for multithreaded library

Shared version for multithreaded library

Shared library for DMR (thread safe)

The shared-library path environment variable specifies the library search path.

This variable should contains at least $INFORMIX/lib , $INFORMIXDIR/lib/esql , and $INFORMIXDIR/lib/cli for the ODBC driver to work.

There are three configuration files for the ODBC driver:

򐂰 sqlhosts

򐂰 odbc.ini

򐂰 odbcinst.ini

Note: the information in the

sqlhosts file is also used by all the other Client

SDK components, as well as by the Informix database server. Be aware that any changes in this file may have an impact in other clients and servers.

On Windows, instead of using a text file, this information is stored in the registry through the Setnet32 tool.

The sqlhosts file

This text file contains most of the information required to connect to an IBM

Informix database server.

The default location for this file is $INFORMIXDIR/etc/sqlhosts . You can use the

INFORMIXSQLHOSTS environment variable to point to a different location.

Example 3-1 shows a simple sqlhost file.

Example 3-1 sqlhosts file

#server protocol hostname service/port on_demo onsoctcp kodiak 9088

For more information about the sqlhosts file, refer to the Client/Server

Communications manual at:

62

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch03.fm

http://publib.boulder.ibm.com/infocenter/idshelp/v115/topic/com.ibm.admin.doc/i ds_admin_0158.htm

The odbcinst.ini file

This file contains a list of installed ODBC drivers on the UNIX machine and specific attributes for each driver, such as the location of the shared library.

The default location of this file is under the home directory as

$HOME/.odbcinst.ini. A sample odbcinst.ini

file is located in the

$INFORMIXDIR/etc directory.

Example 3-2 shows a simple odbcinst.ini file.

Example 3-2 odbcinst.ini

;---------------------------------------------------------------------------

[ODBC Drivers]

IBM INFORMIX ODBC DRIVER=Installed

[IBM INFORMIX ODBC DRIVER]

Driver=/extra/informix/lib/cli/iclit09b.so

Setup=/extra/informix/lib/cli/iclit09b.so

APILevel=1

ConnectFunctions=YYY

DriverODBCVer=03.51

FileUsage=0

SQLLevel=1 smProcessPerConnect=Y

The odbinst.ini

file has two sections:

򐂰

ODBC Drivers: List the ODBC drivers installed in the system.

򐂰

Driver Properties: List the properties for a specific ODBC driver.

Table 3-6 lists the parameters in the properties section.

Table 3-6 Parameters in the Driver Properties section

Keyword Description

Driver Location of the ODBC library

Setup

APILevel

ConnectFunctions

Location of the Setup library

ODBC interface conformance level that the driver supports

DriverODBCVer

Support for SQLConnect, SQLDriverConnect, and

SQLBrowserConnect

Supported version of the ODBC driver

Chapter 3. Working with the ODBC driver

63

7884ch03.fm

Draft Document for Review August 23, 2010 10:53 am

Keyword

FileUsage

SQLLevel

Description

How handle File-system DSN

Type of SQL-92 grammar supported

The odbc.ini file

The odbc.ini file is the data source configuration information. The default location of this file is under the home directory as

$HOME/.odbc.ini.

Alternatively, you can use the ODBCINI environment variable to point the odbc.ini to a different location. A sample odbc.ini file is located in the

$INFORMIXDIR/etc directory.

Example 3-3 shows a simple odbc.ini file.

Example 3-3 odbc.ini

[ODBC Data Sources]

Infdrv1=IBM INFORMIX ODBC DRIVER

;

[Infdrv1]

Driver=/extra/informix/lib/cli/iclis09b.so

Description=IBM INFORMIX ODBC DRIVER

Database=stores_demo

LogonID=odbc pwd=odbc

Servername=demo_on

CursorBehavior=0

CLIENT_LOCALE=en_us.8859-1

DB_LOCALE=en_us.8859-1

TRANSLATIONDLL=/extra/informix/lib/esql/igo4a304.so

;

[ODBC]

;UNICODE=UCS-4

;

; Trace file Section

;

Trace=0

TraceFile=/tmp/odbctrace.out

InstallDir=/extra/informix

TRACEDLL=idmrs09a.so

This file contains three sections:

򐂰 ODBC Data Sources: DSN name and description of the driver used

򐂰 Data Source Specification: Configuration parameters for this particular DSN

򐂰 ODBC: Global options such as Unicode mode or Tracing

64

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch03.fm

Table 3-7 lists the available parameters for the odbc.ini configuration file.

Table 3-7 Parameters for the odbc.ini file

Keyword

Driver

Description

Database

LogonID pwd

Server

CLIENT_LOCALE

DB_LOCALE

TRANSLATIONDLL

CURSORBEHAVIOR

DefaultUDTFetchType

ENABLESCROLLABLECURSORS

ENABLEINSERTCURSORS

OPTIMIZEAUTOCOMMIT

NEEDODBCTYPESONLY

OPTOFC

REPORTKEYSETCURSORS

FETCHBUFFERSIZE

DESCRIBEDECIMALFLOATPOINT

USESERVERDBLOCALE

DONOTUSELVARCHAR

Description

Location of the ODBC shared library

DSN description

Database name

User Id

Password

Database server

Locale used by the client application

Locale of the database

Location of the codeset conversion library

Close or preserve a cursor when a transaction is resolved

Default type for a UDT (SQL_C_BINARY or SQL_C_CHAR)

Enable Scrollable cursors

Optimize insert cursors process

Defer the commit message after all cursor are closed

Extended types are mapped to standard

ODBC types

Close cursors after all the rows have been fetched

Report support for keyset-driven cursors

Set the size of the fetch buffer

Describe float types as SQL_REAL or

SQL_DOUBLE

Use the server database locale

Don’t report Lvarchar columns when using

SQL_VARCHAR

Chapter 3. Working with the ODBC driver

65

7884ch03.fm

Draft Document for Review August 23, 2010 10:53 am

Keyword Description

REPORTCHARCOLASWIDECHARCOL Char columns described by

SQLDescribeCol are reported as Wide char columns (SQLWCHAR)

ISOLATIONLEVEL Default isolation level

UNICODE Type of Unicode (UCS-2, UCS-4)

TRACE

TRACEFILE

TRACEDLL

Trace enable or disable

Location of the trace file

Trace library name (idmrs09a.so)

3.2.2 IBM Data Server Driver for ODBC and CLI

The IBM Data Server Driver for ODBC and CLI (CLI Driver) is installed as part of the IBM Data Server Driver Package or as a separate product. The IBM Data

Server Package is bundle with the Informix Client SDK product. It allows you to connect to IBM Informix and IBM DB2 databases with the same set of libraries.

The communication protocol used is DRDA instead of the native Informix SQLI.

This driver is supported against Informix Version 11.10 and Version 11.50.

Windows configuration

The default install directory for the IBM Data Server Driver is

C:\Program Files\IBM\IBM DATA SERVER DRIVER

The ODBC driver is registered in the Windows system during the installation of the IBM Data Server Driver package. The name of the ODBC driver is IBM DB2

ODBC Driver.

Figure 3-7 shows the Drivers tab of the ODBC Data Source Administrator listing both ODBC drivers:

򐂰 IBM DB2 ODBC DRIVER

򐂰 IBM INFORMIX ODBC DRIVER

66

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch03.fm

Figure 3-7 ODBC Data Source Administrator

To create an ODBC Data Source (DSN) using the IBM Data Server Driver, open the ODBC Administrator, choose a DSN type, and select the IBM DB2 ODBC

Driver.

Figure 3-8 shows the Add Dialog.

Figure 3-8 DSN Add dialog

If there is no database alias defined, you must add one with the connection

details of your IBM Informix database server. See Figure 3-9 on page 68.

Chapter 3. Working with the ODBC driver

67

7884ch03.fm

Draft Document for Review August 23, 2010 10:53 am

Figure 3-9 DSN Settings dialog

Figure 3-10 shows the Advanced settings dialog box.

Figure 3-10 DSN Advanced Settings dialog

Table 3-8 on page 69 lists the minimum required parameters to connect to an

IBM Informix server.

68

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch03.fm

Table 3-8 CLI Parameters

CLI parameter Description

Hostname

Port

Name of the machine where the Informix server is running

TCP Port used by the DRDA Informix alias

Protocol

Database

Transport protocol (TCPIP)

Database server

The configuration settings are stored as a File-DSN (text file contains all the information required to connect to the database) in the

%USERPROFILE%\db2cli.ini

file. Example 3-4 shows a simple db2cli.ini file.

Example 3-4 db2cli.ini

[test]

Database=stores_demo

Protocol=TCPIP

Port=9089

Hostname=kodiak

For a complete description of all the CLI parameters, refer to the DB2 Information

Center at: http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/index.jsp?topic=/com.ibm.d

b2.luw.apdv.cli.doc/doc/r0007964.html

UNIX configuration

On UNIX platforms, the default installation directory for IBM Data Server Client package is /opt/IBM/db2/V9.7

. The library for the ODBC driver is

libdb2.a

that is located in the lib directory of your Data Server installation.

Same as on a Windows machine, the ODBC configuration is stored in the db2cli.ini

file which by default is included in the cfg directory of your Data

Server installation, or is pointed by the DB2CLIINI environment variable

Example 3-5 shows a simple db2cli.ini file.

Example 3-5 db2cli.ini

[test]

Database=stores_demo

Protocol=TCPIP

Port=9089

Hostname=kodiak

Chapter 3. Working with the ODBC driver

69

7884ch03.fm

Draft Document for Review August 23, 2010 10:53 am

For more information about the db2cli.ini file, refer to the db2cli.ini initialization

file section at http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/index.jsp?topic=/com.ibm.d

b2.luw.apdv.cli.doc/doc/c0007882.html

3.2.3 Verifying connectivity

On a Windows system you can use the ODBC Data Source Administrator to verify the connection with the Informix database server.

When using the IBM Informix ODBC driver, you can verify the connection using

the Apply & Test Connection option. See Figure 3-113-11.

Figure 3-11 Informix ODBC connection test

With the IBM Data Server Driver for ODBC, you can perform the connection test

using the Connect option. See Figure 3-12 on page 71.

70

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch03.fm

Figure 3-12 IBM Data Server Driver connection test

Informix Client SDK on UNIX does not include any tool to test an ODBC DSN.

You can use the C samples in $INFORMIXDIR\demo\cli to check if the ODBC DSN is working.

The IBM Data Server Driver for ODBC includes a CLI client, db2cli , that can be

used for testing the connection. Example 3-6 shows a a typical output.

Example 3-6 db2cli output

$ db2cli

IBM DATABASE 2 Interactive CLI Sample Program

(C) COPYRIGHT International Business Machines Corp. 1993,1996

All Rights Reserved

Licensed Materials - Property of IBM

US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.

> quickconnect 1 1 test informix password

SQLAllocEnv: rc = 0 (SQL_SUCCESS)

CLI henv = 1, Test Driver henv = 1

SQLAllocConnect: rc = 0 (SQL_SUCCESS)

CLI hdbc = 1, Test Driver hdbc = 1

SQLConnect: rc = 0 (SQL_SUCCESS)

>

Chapter 3. Working with the ODBC driver

71

7884ch03.fm

Draft Document for Review August 23, 2010 10:53 am

3.3 Developing an ODBC application

In this section we describe how to connect to a database server, type mapping between standard ODBC and IBM Informix, and how to perform basic operations with the ODBC driver.

3.3.1 Connecting to the database

These are the typical steps an ODBC application performs:

1. Connect to the database.

To connect to the database, the application must pass the connection details to the ODBC driver. These details could be included directly in the connection string or stored as a Data Source Name (DSN).

2. Process SQL statements.

The application sends SQL request to the ODBC driver to perform database operations (insert, select, delete, update, and so on).

3. Resolves any open transaction.

If the application is using transaction, it should resolve (commit or rollback) any open transactions.

4. Terminate the connection and free the allocated resources.

These steps are done using the ODBC API functions. See Figure 3-13 on page 73 for a typical sequence of calls. The labels inside the gray boxes

correspond with the ODBC API functions used.

72

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch03.fm

Figure 3-13 Typical ODBC calls used by applications

Example 3-7 Shows a simple C program which connects to an ODBC DSN.

Example 3-7 test_connect.c sample

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#ifdef WIN32

#include <io.h>

#include <windows.h>

#include <conio.h>

#endif

#include "infxcli.h" int main (long argc, char* argv[])

{

Chapter 3. Working with the ODBC driver

73

7884ch03.fm

Draft Document for Review August 23, 2010 10:53 am

SQLHDBC hdbc;

SQLHENV henv;

SQLRETURN rc = 0;

SQLCHAR connStrIn[1000];

SQLCHAR connStrOut[1000];

SQLSMALLINT connStrOutLen;

if (argc != 2)

{

fprintf (stdout, "Please specify the name of a DSN!\n");

return(1);

}

else

{ if (strstr (argv[1],"DRIVER")==NULL) sprintf((char *) connStrIn, "DSN=%s;", (char *)argv[1]); else sprintf((char *) connStrIn, "%s;", (char *)argv[1]);

}

rc = SQLAllocHandle (SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (rc != SQL_SUCCESS)

{

fprintf (stdout, "Environment Handle Allocation failed!\n");

return (1);

}

rc = SQLSetEnvAttr (henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) SQL_OV_ODBC3, 0);

if (rc != SQL_SUCCESS)

{

fprintf (stdout, "SQLSetEnvAttr failed!\n");

return (1);

}

rc = SQLAllocHandle (SQL_HANDLE_DBC, henv, &hdbc);

if (rc != SQL_SUCCESS)

{

fprintf (stdout, "Connection Handle Allocation failed!\n");

return (1);

}

rc = SQLDriverConnect (hdbc, NULL, connStrIn, SQL_NTS, connStrOut, 1000,

&connStrOutLen, SQL_DRIVER_NOPROMPT);

if (rc != SQL_SUCCESS)

{

fprintf (stdout, "Connectedion failed!\n");

return (1);

}

fprintf (stdout, "Connected\n");

SQLDisconnect (hdbc);

74

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

SQLFreeHandle (SQL_HANDLE_DBC, hdbc);

SQLFreeHandle (SQL_HANDLE_ENV, henv);

return (rc);

}

7884ch03.fm

You can compile this code on a Windows system using the following command cl /DWIN32 -I%INFORMIXDIR%\incl\cli odbc32.lib test_connect.c

Example 3-8 shows how to compile and run the sample.

Example 3-8 test_connec.c output

c:\work>cl /DWIN32 /D_CRT_SECURE_NO_DEPRECATE -I%INFORMIXDIR%\incl\cli odbc32.lib /nologo test_connect.c

test_connect.c

D:\work>test_connect

Please specify the name of a DSN!

D:\workt>test_connect dummy_dsn

Connection failed!

D:\work>test_connect test

Connected

D:\work>

You can use the sample C program to perform a DSN-less connection.

Example 3-9 shows the sample C program with a DSN-less connection string

using the Informix ODBC driver and the Data Server driver for ODBC.

Example 3-9 DSN-less connection

C:\work>test_connect "DRIVER={IBM INFORMIX ODBC

DRIVER};SERVER=demo_on;DATABASE=stores_demo;HOST=kodiak;PROTOCOL=onsoctcp;SERVI

CE=9088;UID=informix;PWD=password;";

Connected

C:\work>test_connect "driver={IBM DB2 ODBC

DRIVER};Database=stores_demo;hostname=kodiak;port=9089;protocol=TCPIP; uid=informix; pwd=password"

Connected

C:\work>

Chapter 3. Working with the ODBC driver

75

7884ch03.fm

Draft Document for Review August 23, 2010 10:53 am

3.3.2 Type mapping

The data types used on the database differ from the data types used by your application. This section shows the data type mapping needed when working with specific Informix data types with the Informix ODBC driver.

When a query is executed by the application, the data returned by the Informix server may be in a different format than what the application uses. The ODBC driver converts the data passed between the application and the database server. This process is invisible to the application. The only requirement for the application is to specify the correct data types when calling the ODBC driver functions.

The application sets ValueType and ParameterType when calling the bind functions.

Example 3-10 shows the definition for one of the bind functions,

SQLBindParameter() . The ODBC driver converts the data type specified in

ValueType to the data type specified in ParameterType.

Example 3-10 SQLBindParameter definition

SQLBindParameter(

SQLHSTMT StatementHandle, /* hstmt */

SQLUSMALLINT ParameterNumber, /* ipar */

SQLSMALLINT InputOutputType, /* fParamType */

SQLSMALLINT ValueType, /* fCType */

SQLSMALLINT ParameterType, /* fSqlType */

SQLUINTEGER ColumnSize, /* cbColDef */

SQLSMALLINT DecimalDigits, /* ibScale */

SQLPOINTER ParameterValuePtr, /* rgbValue */

SQLINTEGER BufferLength, /* cbValueMax */

SQLINTEGER *StrLen_or_IndPtr); /* pcbValue */

Example 3-11shows a SQLBindParameter() call where the application is binding

a

SQL_C_BINARY

parameter with a

SQL_INFX_UDT_FIXED

value.

Example 3-11 Using SQLBindParameter()

SQLBindParameter (

hstmt,

1,

SQL_PARAM_INPUT,

SQL_C_BINARY,

SQL_INFX_UDT_FIXED,

loptr_size,

0,

loptr_buffer,

76

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

loptr_size,

&loptr_valsize);

7884ch03.fm

Table 3-9 shows the Informix specific data type mapping used with the Informix

ODBC driver.

Table 3-9 Mapping for specific Informix data types

Informix SQL Informix ODBC driver

BIGINT SQL_INFX_BIGINT

BIGSERIAL

BLOB

BOOLEAN

BYTE

SQL_INFX_BIGINT

SQL_IFMX_UDT_BLOB

SQL_BIT

SQL_LONGVARBINARY

CLOB

DATETIME

DISTINCT

IDSSECURITYLABEL

INT8

INTERVAL DAY

INTERVAL DAY TO HOUR

INTERVAL DAY TO MINUTE

SQL_IFMX_UDT_CLOB

SQL_TIMESTAMP

Any

Built-in DISTINCT OF VARCHAR(128)

SQL_BIGINT

SQL_INTERVAL_DAY

SQL_INTERVAL_DAY_TO_HOUR

SQL_INTERVAL_DAY_TO_MINUTE

INTERVAL DAY TO SECOND

INTERVAL HOUR

INTERVAL HOUR TO MINUTE

INTERVAL HOUR TO SECOND

INTERVAL MINUTE

INTERVAL MINUTE TO SECOND

INTERVAL MONTH

INTERVAL SECOND

INTERVAL YEAR

INTERVAL YEAR TO MONTH

SQL_INTERVAL_DAY_TO_SECOND

SQL_INTERVAL_HOUR

SQL_INTERVAL_HOUR_TO_MINUTE

SQL_INTERVAL_HOUR_TO_SECOND

SQL_INTERVAL_MINUTE

SQL_INTERVAL_MINUTE _TO_SECOND

SQL_INTERVAL_MONTH

SQL_INTERVAL_SECOND

SQL_INTERVAL_YEAR

SQL_INTERVAL_YEAR_TO_MONTH

Chapter 3. Working with the ODBC driver

77

7884ch03.fm

Draft Document for Review August 23, 2010 10:53 am

Informix SQL

LIST, MULTISET, SET

LVARCHAR

MONEY

NCHAR

NVARCHAR

OPAQUE (fixed)

OPAQUE (varying)

ROW

SERIAL

SERIAL8

TEXT

Informix ODBC driver

Any

SQL_VARCHAR

SQL_DECIMAL

SQL_CHAR

SQL_VARCHAR

SQL_INFX_UDT_FIXED

SQL_INFX_UDT_VARYING

Any

SQL_INTEGER

SQL_BIGINT

SQL_LONGVARCHAR

For a complete list of Data Type mapping, refer to the IBM Informix ODBC Driver

Guide at http://publib.boulder.ibm.com/infocenter/idshelp/v115/topic/com.ibm.odbc.doc/si i04979050.htm#sii04979050

If your application requires only Standard ODBC data types, you can enable the

Report Standard ODBC Types

option in your DSN or connection string. When this option is enabled, the ODBC driver handle Smart Large Objects (BLOB and

CLOB) as if they were simple large objects (byte and text), the driver automatically generates the smart-large-object calls ( ifx_lo_open , ifx_lo_write , and so on).

This option also changes the mapping for user define types (including

MULTISET, SET, ROW, and LIST) to SQL_C_CHAR.

These options are also available as the ODBC attributes:

򐂰

SQL_INFX_ATTR_ODBC_TYPES_ONLY

򐂰

SQL_INFX_ATTR_LO_AUTOMATIC

򐂰

SQL_INFX_ATTR_DEFAULT_UDT_FETCH_TYPE

78

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch03.fm

3.3.3 Performing database operations

In this section we show samples of how to use the ODBC driver to perform basic operations with an Informix database. Most of these tasks are common to any

ODBC application so we do not explain them in detail.

This section includes:

򐂰

Simple SQL statements (INSERT, UPDATE, and DELETE)

򐂰

Fetching data

򐂰

Using parameters

򐂰

Calling SQL routines

򐂰

Using transactions

Simple SQL statements

You can run SQL statements directly using the SQLExecDirect() function. This function is commonly use when there is no need to run the SQL statement more than once. The ODBC driver would prepare the statement, execute it, and free the resources in one operation.

Example 3-12 shows a sample of

using SQLExecDirect() to set the LOCK WAIT time out.

Example 3-12 SQLExecDirect() sample. Simple_sql.c

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#ifdef WIN32

#include <io.h>

#include <windows.h>

#include <conio.h>

#endif

#include "infxcli.h" int main (long argc, char* argv[])

{

SQLHDBC hdbc;

SQLHENV henv;

SQLHSTMT hstmt;

SQLRETURN rc = 0;

SQLCHAR connStrIn[1000];

SQLCHAR connStrOut[1000];

SQLSMALLINT connStrOutLen;

int sqllen;

SQLCHAR *sqlstmt;

Chapter 3. Working with the ODBC driver

79

7884ch03.fm

Draft Document for Review August 23, 2010 10:53 am

if (argc != 3)

{

fprintf (stdout, "Please specify the name of a DSN and the SQL Statement to run!\n");

return(1);

}

else

{ if (strstr (argv[1],"DRIVER")==NULL) sprintf((char *) connStrIn, "DSN=%s;", (char *)argv[1]); else sprintf((char *) connStrIn, "%s;", (char *)argv[1]);

sqllen = strlen((char *)argv[2]);

sqlstmt = (SQLCHAR *) malloc (sqllen + sizeof(char));

strcpy((char *)sqlstmt, (char *)argv[2]);

}

rc = SQLAllocHandle (SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

if (rc != SQL_SUCCESS)

{

fprintf (stdout, "Environment Handle Allocation failed!\n");

return (1);

}

rc = SQLSetEnvAttr (henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) SQL_OV_ODBC3, 0);

if (rc != SQL_SUCCESS)

{

fprintf (stdout, "SQLSetEnvAttr failed!\n");

return (1);

}

rc = SQLAllocHandle (SQL_HANDLE_DBC, henv, &hdbc);

if (rc != SQL_SUCCESS)

{

fprintf (stdout, "Connection Handle Allocation failed!\n");

return (1);

}

rc = SQLDriverConnect (hdbc, NULL, connStrIn, SQL_NTS, connStrOut, 1000,

&connStrOutLen, SQL_DRIVER_NOPROMPT);

if (rc != SQL_SUCCESS)

{

fprintf (stdout, "Connection failed!\n");

return (1);

}

fprintf (stdout, "Connected\n");

rc = SQLAllocHandle (SQL_HANDLE_STMT, hdbc, &hstmt );

if (rc != SQL_SUCCESS)

80

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

{

fprintf (stdout, "Statement Handle Allocation failed!\n");

return (1);

}

rc = SQLExecDirect (hstmt, sqlstmt, SQL_NTS);

if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO)

{

fprintf (stdout, "SQLExecDirectW() failed!\n");

return (1);

}

fprintf (stdout, "Executed SQL Statement:\n%s\n",sqlstmt);

SQLDisconnect (hdbc);

SQLFreeHandle (SQL_HANDLE_DBC, hdbc);

SQLFreeHandle (SQL_HANDLE_ENV, henv);

return (rc);

}

7884ch03.fm

Example 3-13 shows the result of running the sample program with different SQL

statements. Here we input the SQL statement directly from the command line, in a real application, the SQL is normally constructed based on the customer input.

In this simple example, we also did not provide error information if the execution fails. You can obtain error information using the

SQLGetDiagRec()

function which

is cover in the 3.3.5, “Error handling” on page 108.

Example 3-13 Output of SQLDirectExec sample

c:\work>cl /DWIN32 /D_CRT_SECURE_NO_DEPRECATE -I%INFORMIXDIR%\incl\cli odbc32.lib /nologo simple_sql.c

simplesql.c

c:\work>simples_sql.exe test "set lock mode to wait 10"

Connected

Executed SQL Statement: set lock mode to wait 10 c:\work>simple_sql.exe test "create temp table temp1(c1 int)"

Connected

Executed SQL Statement: create temp table temp1(c1 int) c:\work>simple_sql.exe test "invalid_SQL"

Connected

SQLExecDirectW() failed!

Chapter 3. Working with the ODBC driver

81

7884ch03.fm

Draft Document for Review August 23, 2010 10:53 am c:\work>

Fetching data

Example 3-14 demonstrates how to run a SELECT statement to retrieve data

from the server. To make the code clear we have removed all the error handling.

Example 3-14 Select.c sample

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#ifdef WIN32

#include <io.h>

#include <windows.h>

#include <conio.h>

#endif

#include "infxcli.h" int main (long argc, char* argv[])

{

SQLHDBC hdbc;

SQLHENV henv;

SQLHSTMT hstmt;

SQLRETURN rc = 0;

SQLCHAR connStrIn[1000];

SQLCHAR connStrOut[1000];

SQLSMALLINT connStrOutLen;

SQLCHAR sqlstmt[100];

SQLCHAR code[2+1];

SQLCHAR sname[15+1];

SQLLEN lcode=0;

SQLLEN lsname=0;

sprintf((char *) connStrIn, "DSN=demo_on");

sprintf((char *) sqlstmt, "SELECT code, sname FROM state where code<'CA'");

SQLAllocHandle (SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

SQLSetEnvAttr (henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) SQL_OV_ODBC3, 0);

SQLAllocHandle (SQL_HANDLE_DBC, henv, &hdbc);

SQLDriverConnect (hdbc, NULL, connStrIn, SQL_NTS, connStrOut, 1000, &connStrOutLen,

SQL_DRIVER_NOPROMPT);

fprintf (stdout, "Connected\n");

SQLAllocHandle (SQL_HANDLE_STMT, hdbc, &hstmt );

SQLExecDirect (hstmt, sqlstmt, SQL_NTS);

fprintf (stdout, "Executed SQL Statement:\n%s\n",sqlstmt);

SQLBindCol (hstmt, 1, SQL_C_CHAR, &code, 3, &lcode);

82

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

SQLBindCol (hstmt, 2, SQL_C_CHAR, &sname, 16, &lsname);

while (SQLFetch(hstmt)!=SQL_NO_DATA_FOUND)

fprintf (stdout, "Fetched row: %s, %s\n",code, sname);

SQLCloseCursor(hstmt);

SQLDisconnect (hdbc);

SQLFreeHandle (SQL_HANDLE_DBC, hdbc);

SQLFreeHandle (SQL_HANDLE_ENV, henv);

return (rc);

}

7884ch03.fm

Example 3-15 shows the output of this sample.

Example 3-15 Output of Select.c

C:\work>cl /DWIN32 /D_CRT_SECURE_NO_DEPRECATE -I%INFORMIXDIR%\incl\cli odbc32.lib /nologo select.c

select.c

C:\work>select

Connected

Executed SQL Statement:

SELECT code, sname FROM state where code<'CA'

Fetched row: AK, Alaska

Fetched row: AL, Alabama

Fetched row: AR, Arkansas

Fetched row: AZ, Arizona

C:\work>

Using parameters

In most of the cases an application would run the same SQL statement several times, so it makes sense if the SQL statement is prepared and then used with different values.

Example 3-16 demonstrates how to run a simple SQL SELECT statement using

an input parameter. The SQL statement is prepared and then executed with one parameter.

Example 3-16 Example of a parametrized query. Select_param.c

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#ifdef WIN32

#include <io.h>

Chapter 3. Working with the ODBC driver

83

7884ch03.fm

Draft Document for Review August 23, 2010 10:53 am

#include <windows.h>

#include <conio.h>

#endif

#include "infxcli.h" int main (long argc, char* argv[])

{

SQLHDBC hdbc;

SQLHENV henv;

SQLHSTMT hstmt;

SQLRETURN rc = 0;

SQLCHAR connStrIn[1000];

SQLCHAR connStrOut[1000];

SQLSMALLINT connStrOutLen;

SQLCHAR sqlstmt[100];

SQLCHAR inputcode[2+1];

SQLCHAR code[2+1];

SQLCHAR sname[15+1];

SQLLEN lcode = 0;

SQLLEN lsname = 0;

SQLSMALLINT datatype, decimaldigits, nullable;

SQLUINTEGER paramsize;

sprintf((char *) connStrIn, "DSN=demo_on");

sprintf((char *) sqlstmt, "SELECT code, sname FROM state where code < ?");

sprintf((char *) inputcode, "CA");

SQLAllocHandle (SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

SQLSetEnvAttr (henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) SQL_OV_ODBC3, 0);

SQLAllocHandle (SQL_HANDLE_DBC, henv, &hdbc);

SQLDriverConnect (hdbc, NULL, connStrIn, SQL_NTS, connStrOut, sizeof(connStrOut),

&connStrOutLen, SQL_DRIVER_NOPROMPT);

fprintf (stdout, "Connected\n");

SQLAllocHandle (SQL_HANDLE_STMT, hdbc, &hstmt );

SQLPrepare (hstmt, sqlstmt, strlen(sqlstmt));

SQLDescribeParam(hstmt, 1, &datatype, &paramsize, &decimaldigits, &nullable);

SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, datatype, paramsize, decimaldigits, inputcode, 0, NULL);

SQLExecute (hstmt);

fprintf (stdout, "Executed SQL Statement:\n%s\nUsing: '%s'\n",sqlstmt,inputcode);

SQLBindCol (hstmt, 1, SQL_C_CHAR, &code, sizeof(code), &lcode);

SQLBindCol (hstmt, 2, SQL_C_CHAR, &sname, sizeof(sname), &lsname);

while ((rc = SQLFetch(hstmt))!=SQL_NO_DATA_FOUND)

fprintf (stdout, "Fetched: %s, %s\n",code, sname);

SQLCloseCursor(hstmt);

84

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

SQLDisconnect (hdbc);

SQLFreeHandle (SQL_HANDLE_DBC, hdbc);

SQLFreeHandle (SQL_HANDLE_ENV, henv);

return (rc);

}

7884ch03.fm

Example 3-17 shows the SQL statement the program prepares and the

parameter used for the placeholder.

Example 3-17 Output for Select_param.c

C:\work>cl /DWIN32 /D_CRT_SECURE_NO_DEPRECATE -ID:\infx\csdk350tc7\incl\cli odbc32.lib /nologo select_param.c

select_param.c

C:\work>select_param

Connected

Executed SQL Statement:

SELECT code, sname FROM state where code < ?

Using: 'CA'

Fetched: AK, Alaska

Fetched: AL, Alabama

Fetched: AR, Arkansas

Fetched: AZ, Arizona

C:\work>

Calling SQL routines

In this section we demonstrate how to call a SQL routine from an ODBC application. The following is a simple stored procedure that returns the user name and session ID.

create procedure get_sid(user char(20)) returning char(100); return 'user= '||trim(user)|| ' session= '||dbinfo('sessionid'); end procedure;

We use the ODBC standard syntax for calling a database routine:

{? = call client_routine(?, ?,...)}

T he first placeholder (“?”) is used only when the first parameter of the routine is an output parameter. If the first parameter is not an output parameter, you can run the routine (stored procedure or SQL function) using the following syntax:

{call client_routine(?, ?, ?, ?)}

In Example 3-18 on page 86 we illustrate how to call the

get_sid()

SQL function.

Chapter 3. Working with the ODBC driver

85

7884ch03.fm

Draft Document for Review August 23, 2010 10:53 am

Example 3-18 SPL Function sample. Function.c

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#ifdef WIN32

#include <io.h>

#include <windows.h>

#include <conio.h>

#endif

#include "infxcli.h" int main (long argc, char* argv[])

{

SQLHDBC hdbc;

SQLHENV henv;

SQLHSTMT hstmt;

SQLRETURN rc = 0;

SQLCHAR connStrIn[1000];

SQLCHAR connStrOut[1000];

SQLSMALLINT connStrOutLen;

SQLCHAR sqlstmt[100];

SQLCHAR errorn[20+1];

SQLCHAR result[100+1];

SQLLEN lresult = 0;

sprintf((char *) connStrIn, "DSN=demo_on");

sprintf((char *) sqlstmt, "{? = call get_sid(?)}");

sprintf((char *) errorn, "informix");

SQLAllocHandle (SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

SQLSetEnvAttr (henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) SQL_OV_ODBC3, 0);

SQLAllocHandle (SQL_HANDLE_DBC, henv, &hdbc);

SQLDriverConnect (hdbc, NULL, connStrIn, SQL_NTS, connStrOut, sizeof(connStrOut),

&connStrOutLen, SQL_DRIVER_NOPROMPT);

fprintf (stdout, "Connected\n");

SQLAllocHandle (SQL_HANDLE_STMT, hdbc, &hstmt );

SQLBindParameter(hstmt, 1, SQL_PARAM_OUTPUT, SQL_C_CHAR, SQL_CHAR,sizeof(result),0,

result, sizeof(result), &lresult);

SQLBindParameter(hstmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(errorn),0, errorn, 0, NULL);

SQLExecDirect (hstmt, sqlstmt, SQL_NTS);

SQLFetch(hstmt);

fprintf (stdout, "Executed SQL Statement:\n%s\nUsing: '%s'\n",sqlstmt,errorn);

fprintf (stdout, "Value returned: %s\n",result);

SQLCloseCursor(hstmt);

86

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

SQLDisconnect (hdbc);

SQLFreeHandle (SQL_HANDLE_DBC, hdbc);

SQLFreeHandle (SQL_HANDLE_ENV, henv);

return (rc);

}

7884ch03.fm

Example 3-19 shows the input parameter passed to the

get_sid()

procedure and the return values.

Example 3-19 Output of Function.c

C:\work>cl /DWIN32 /D_CRT_SECURE_NO_DEPRECATE -ID:\infx\csdk350tc7\incl\cli odbc32.lib /nologo function.c

function.c

C:\work>function

Connected

Executed SQL Statement:

{? = call get_sid(?)}

Using: 'informix'

Value returned: user: informix session: 213

C:\work>

Local transactions

The default transaction mode for the Informix ODBC driver is auto-commit. This means that the transaction is automatically committed if the SQL statement is run successfully.

You can switch to manual-commit by setting the SQL_AUTOCOMMIT_OFF attribute using the SQLSetConnectAttr() function. When an application sets

SQL_AUTOCOMMIT_OFF , the next SQL statement automatically starts a transaction that will remain open until the application calls SQLEndTran() .

In manual mode, all the statements executed by the application are committed or rolled back when the application calls SQLEndTran() .

Having auto-commit set may be more convenient when running simple SQL statements because there is less tasks to care about in the application code.

However, it gives less control to the developer than using the manual-commit mode. When using auto-commit, there is no option of rolling back a particular change in the database, neither to insert a multiple rows as a batch operation, which may improve the performance of the application.

Example 3-20 on page 88 illustrates how to run a local transaction in manual

mode.

Chapter 3. Working with the ODBC driver

87

7884ch03.fm

Draft Document for Review August 23, 2010 10:53 am

Example 3-20 Transaction.c

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#ifdef WIN32

#include <io.h>

#include <windows.h>

#include <conio.h>

#endif

#include "infxcli.h" int main (long argc, char* argv[])

{

SQLHDBC hdbc;

SQLHENV henv;

SQLHSTMT hstmt;

SQLRETURN rc = 0;

SQLCHAR connStrIn[1000];

SQLCHAR connStrOut[1000];

SQLSMALLINT connStrOutLen;

SQLCHAR sqlstmt[100];

SQLINTEGER cnum = 101;

SQLSMALLINT datatype, decimaldigits, nullable;

SQLUINTEGER paramsize;

sprintf((char *) connStrIn, "DSN=demo_on");

sprintf((char *) sqlstmt, "INSERT INTO orders(order_num,order_date,customer_num)

VALUES (0,current,?)");

SQLAllocHandle (SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

SQLSetEnvAttr (henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) SQL_OV_ODBC3, 0);

SQLAllocHandle (SQL_HANDLE_DBC, henv, &hdbc);

SQLDriverConnect (hdbc, NULL, connStrIn, SQL_NTS, connStrOut, sizeof(connStrOut),

&connStrOutLen, SQL_DRIVER_NOPROMPT);

fprintf (stdout, "Connected\n");

SQLAllocHandle (SQL_HANDLE_STMT, hdbc, &hstmt );

SQLSetConnectAttr (hdbc, SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF, (SQLINTEGER)

NULL);

SQLPrepare (hstmt, sqlstmt, strlen(sqlstmt));

SQLDescribeParam(hstmt, 1, &datatype, &paramsize, &decimaldigits, &nullable);

SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_SHORT, datatype, paramsize, decimaldigits, &cnum, 0, NULL);

while (cnum<105)

{

88

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch03.fm

SQLExecute (hstmt);

fprintf (stdout, "Executed SQL Statement:\n%s\nUsing: '%d'\n",sqlstmt,cnum);

cnum++;

}

rc = SQLEndTran (SQL_HANDLE_DBC, hdbc, SQL_ROLLBACK);

fprintf (stdout, "Transaction Rolled back\n");

SQLDisconnect (hdbc);

SQLFreeHandle (SQL_HANDLE_DBC, hdbc);

SQLFreeHandle (SQL_HANDLE_ENV, henv);

return (rc);

}

Example 3-21 shows the output of the previous example. A local transaction is

created, five rows are inserted in the orders

table and then, the transaction is rolled back using

SQLEndTran()

.

Example 3-21 Output of Trasaction.C

C:\work>cl /DWIN32 /D_CRT_SECURE_NO_DEPRECATE -ID:\infx\csdk350tc7\incl\cli odbc32.lib /nologo transact.c

transact.c

C:\work>del pp*

C:\work>transact.exe

Connected

Executed SQL Statement:

INSERT INTO orders(order_num,order_date,customer_num) VALUES (0,current,?)

Using: '101'

Executed SQL Statement:

INSERT INTO orders(order_num,order_date,customer_num) VALUES (0,current,?)

Using: '102'

Executed SQL Statement:

INSERT INTO orders(order_num,order_date,customer_num) VALUES (0,current,?)

Using: '103'

Executed SQL Statement:

INSERT INTO orders(order_num,order_date,customer_num) VALUES (0,current,?)

Using: '104'

Transaction Rolled back

C:\work>

Distributed transactions

On Windows you can run a distributed transaction using the Microsoft

Distributed Transaction Coordinator (MSDTC) service.

Chapter 3. Working with the ODBC driver

89

7884ch03.fm

Draft Document for Review August 23, 2010 10:53 am

Example 3-22 demonstrate how to run a distributed transaction. The example

opens two connections to two different database servers and enlists both connections into the same distributed transaction.

Example 3-22 Transaction_dtc.cpp

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#ifdef WIN32

#include <io.h>

#include <windows.h>

#include <conio.h>

#include <txdtc.h>

#include <xolehlp.h>

#endif

#include "infxcli.h" int main (long argc, char* argv[])

{

SQLHDBC hdbc, hdbc2;

SQLHENV henv;

SQLHSTMT hstmt, hstmt2;

SQLRETURN rc = 0;

SQLCHAR connStrIn[100],connStrIn2[100];

SQLCHAR connStrOut[1000];

SQLSMALLINT connStrOutLen;

SQLCHAR sqlstmt[100];

SQLINTEGER cnum = 101;

SQLSMALLINT datatype, decimaldigits, nullable;

SQLUINTEGER paramsize;

ITransactionDispenser *pTransactionDispenser = NULL;

ITransaction * pITransaction;

sprintf((char *) connStrIn , "DSN=server_1");

sprintf((char *) connStrIn2, "DSN=server_2");

sprintf((char *) sqlstmt, "INSERT INTO orders(order_num,order_date,customer_num)

VALUES (0,current,101)");

SQLAllocHandle (SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

SQLSetEnvAttr (henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) SQL_OV_ODBC3, 0);

SQLAllocHandle (SQL_HANDLE_DBC, henv, &hdbc);

SQLAllocHandle (SQL_HANDLE_DBC, henv, &hdbc2);

// Get DTC

DtcGetTransactionManager(NULL, NULL,IID_ITransactionDispenser, 0, 0, NULL, (void**)

&pTransactionDispenser);

90

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch03.fm

SQLDriverConnect (hdbc, NULL, connStrIn, SQL_NTS, connStrOut, sizeof(connStrOut),

&connStrOutLen, SQL_DRIVER_NOPROMPT);

fprintf (stdout, "Connected to %s\n",connStrIn);

SQLDriverConnect (hdbc2, NULL, connStrIn2, SQL_NTS, connStrOut, sizeof(connStrOut),

&connStrOutLen, SQL_DRIVER_NOPROMPT);

fprintf (stdout, "Connected to %s\n",connStrIn2);

//Start the transaction on DTC

pTransactionDispenser->BeginTransaction

(NULL,ISOLATIONLEVEL_READCOMMITTED,0,NULL,&pITransaction);

//Enlist the connections in distributed transaction

SQLSetConnectAttr(hdbc, SQL_ATTR_ENLIST_IN_DTC,

(SQLPOINTER)pITransaction,SQL_IS_INTEGER);

SQLSetConnectAttr(hdbc2, SQL_ATTR_ENLIST_IN_DTC,

(SQLPOINTER)pITransaction,SQL_IS_INTEGER);

SQLAllocHandle (SQL_HANDLE_STMT, hdbc, &hstmt );

SQLExecDirect (hstmt, sqlstmt, SQL_NTS);

fprintf (stdout, "Executed SQL Statement:\n%s\nUsing: '%d'\n",sqlstmt,cnum);

SQLAllocHandle (SQL_HANDLE_STMT, hdbc2, &hstmt2 );

if (SQLExecDirect (hstmt2, sqlstmt, SQL_NTS)!=SQL_SUCCESS)

{

fprintf(stdout, "Rolling back global transaction\n");

pITransaction->Abort(NULL,FALSE,FALSE);

}

else

{

pITransaction->Commit( 0, XACTTC_SYNC_PHASEONE, 0 );

pITransaction->Release();

fprintf(stdout, "Transaction Committed\n");

}

SQLFreeHandle(SQL_HANDLE_STMT,hstmt2);

SQLFreeHandle(SQL_HANDLE_STMT,hstmt);

SQLDisconnect (hdbc2);

SQLDisconnect (hdbc);

SQLFreeHandle (SQL_HANDLE_DBC, hdbc2);

SQLFreeHandle (SQL_HANDLE_DBC, hdbc);

SQLFreeHandle (SQL_HANDLE_ENV, henv);

return (rc);

}

Example 3-23 shows how to compile the sample and the output of the program.

Example 3-23 Output of Transact_dtc.cpp

C:\work>cl /DWIN32 /D_CRT_SECURE_NO_DEPRECATE -I%INFORMIXDIR%\incl\cli odbc32.lib xoleHlp.lib /nologo transaction_dtc.cpp

transaction_dtc.cpp

Chapter 3. Working with the ODBC driver

91

7884ch03.fm

Draft Document for Review August 23, 2010 10:53 am

C:\work>transaction_dtc

Connected to DSN=server_1

Connected to DSN=server_2

Executed SQL Statement:

INSERT INTO orders(order_num,order_date,customer_num) VALUES (0,current,101)

Using: '101'

Transaction Committed

C:\work>

Note: Remember that the DSN must be accessible to the MSDTC service. In

Example 3-22 on page 90,

test_1 and t est_2 are both created as

System-DSN.

3.3.4 Handling special data types

This section describe how to work with the Informix specific data types such as

Smart Large Objects and complex data types.

Smart Large Object

Smart Large Objects are a type of large objects supported by Informix. Smart

Large Objects are logically stored in a table column but physically stored in a specific type of dbspaces called Smart Blob Space (SBS).

The information stored in the table column is structure which contains information about the large object, like the pointer to location in the Smart Blob Space containing the data or special attributes. Informix has two types of smart large objects.

򐂰

BLOB: Stores binary data.

򐂰

CLOB: Stores character data.

A client application uses these data structures to perform random I/O operations on the large data, such as open, read, or write operations. There are two options for accessing Smart Large Objects from an ODBC application:

򐂰 Use the smart-large-object ODBC API.

If the application requires random access to the large data, it must use the smart-large-object functions. These functions give the application a greater control over the smart-large-object data in terms of object properties, concurrency access, and logging.

򐂰 Use Smart Large Object Automation.

92

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch03.fm

The ODBC driver automatically uses the ODBC API for handling large objects. The application can access Smart Large Objects as standard ODBC data types ( SQL_LONGVARBINARY and SQL_LONGVARCHAR ).

To enable Smart Large Object Automation use the Report Standard ODBC

Types Only DSN option under the DSN Advanced tab or set the

SQL_INFX_ATTR_LO_AUTOMATIC

connection attribute.

Data structures for Smart Large Objects

Table 3-10 describes the data structures used by the smart-large-object

functions.

Table 3-10 Smart Large Object data structures

Data structure Name Description

lofd file descriptor loptr pointer structure

File descriptor to access smart-large-object data

Contains the security information and pointer for a Smart Large Object. This is the data stored with the table columns.

lospec lostat specification structure Contains the storage characteristics for a

Smart Large Object status structure contains the status information for a Smart

Large Object

Client functions to access Smart Large Objects

Table 3-11 lists the SQL functions that you can use in your ODBC program to

access the Informix smart large objects.

Table 3-11 Smart Large Object client functions

Function Description

ifx_lo_alter(loptr, lospec) Alters the storage attributes like Logging or

Last-access ifx_lo_close(lofd) ifx_lo_col_info(colname, lospec)

Closes a Smart Large Object

Updates column-level storage characteristics ifx_lo_create(lospec, flags, loptr, lofd) Creates and opens a new Smart Large Object ifx_lo_def_create_spec(lospec) Creates a smart-large-object specification structure ifx_lo_open(lofd, loptr, flags) Opens a Smart Large Object

Chapter 3. Working with the ODBC driver

93

7884ch03.fm

Draft Document for Review August 23, 2010 10:53 am

Function

ifx_lo_read(lofd, buf) ifx_lo_readwithseek(lofd, buf, offset, whence) ifx_lo_seek(), ifx_lo_seek(lofd, offset, whence, seek_pos) ifx_lo_specget_estbytes(lospec, estbytes) ifx_lo_specget_extsz(lospec, extsz) ifx_lo_specget_flags(lospec, flags) ifx_lo_specget_maxbytes(lospec, maxbytes) ifx_lo_specget_sbspace(lospec, sbspace) ifx_lo_specset_estbytes(lospec, estbytes) ifx_lo_specset_extsz(lospec, extsz) ifx_lo_specset_flags(lospec, flags) ifx_lo_specset_maxbytes(lospec, maxbytes) ifx_lo_specset_sbspace(lospec, sbspace) ifx_lo_stat(lofd, lostat) ifx_lo_stat_atime(lostat, atime) ifx_lo_stat_cspec(lostat, lospec) ifx_lo_stat_ctime(lostat, ctime) ifx_lo_stat_refcnt(lostat, refcount) ifx_lo_stat_size(lostat, size) ifx_lo_tell(lofd, seek_pos) ifx_lo_truncate(lofd, offset) ifx_lo_write(lofd, buf)

Description

Reads data from an Smart Large Object

Reads starting at a specific location

Sets the file position for the next operation

Returns the estimated size

Returns the allocation extent size

Returns create-time flags

Returns the maximum number of bytes

Returns the sbspace name

Sets the estimated number of bytes

Sets the allocation extent size

Sets the create-time flags

Sets the maximum number of bytes

Sets the sbspace name

Initializes a smart-large-object status structure

Returns the last-access time

Returns the specification structure

Returns the last-time change

Returns the number of references

Returns the size

Returns the current file position

Truncates a Smart Large Object at a given position

Writes data

94

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch03.fm

Function

ifx_lo_writewithseek(lofd, buf, offset, whence)

Description

Writes data at a specific location

Calling client functions from ODBC

An application must use the standard ODBC syntax to call the smart-large-object functions. The syntax is as follows:

{? = call function_name (?, ?,...)}

The following is the example of calling the ifx_lo_open() function:

{? = call ifx_lo_open(?, ?, ?)}

Creating a Smart Large Object

To create a Smart Large Object, you must create a BLOB descriptor and then insert the BLOB into the database.

Use the following steps to create a new Smart Large Object:

1. Allocate memory for the specification structure using lospec .

2. Create a lospec using ifx_lo_def_create_spec()

.

3. Initialize the specification structure using lospec .

4. Allocate memory for the pointer structure using loptr

.

5. Create the object using ifx_lo_create() .

6. Write the data into the object using ifx_lo_write()

.

7. Perform a SQL operation (INSERT, UPDATE, and so on).

8. Close the Smart Large Object using ifx_lo_close()

.

Example 3-24 shows how to insert a BLOB into the database.

Example 3-24 Create_lo.c

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#ifdef WIN32

#include <io.h>

#include <windows.h>

#include <conio.h>

#include <fcntl.h>

#include <sys/stat.h>

#endif

Chapter 3. Working with the ODBC driver

95

7884ch03.fm

Draft Document for Review August 23, 2010 10:53 am

#include "infxcli.h" int main (long argc, char* argv[])

{

SQLHDBC hdbc;

SQLHENV henv;

SQLHSTMT hstmt;

SQLRETURN rc = 0;

SQLCHAR connStrIn[1000], connStrOut[1000], sqlstmt[100];

SQLSMALLINT connStrOutLen;

SQLINTEGER cnum = 101;

SQLSMALLINT datatype, decimaldigits, nullable;

SQLUINTEGER paramsize;

SQLCHAR colname[25] = "catalog.advert_descr";

SQLINTEGER colname_size = SQL_NTS;

SQLCHAR* file_name = (SQLCHAR *) "create_lo.c";

SQLCHAR* blob_data;

SQLSMALLINT blob_size;

SQLINTEGER blob_wsize, mode = LO_RDWR, cbMode = 0;

int fd=0;

struct stat statbuf;

/* BLOB file descriptor */

SQLINTEGER lofd;

SQLINTEGER lofd_valsize = 0;

/* BLOB pointer structure */

SQLCHAR* loptr_buffer;

SQLSMALLINT loptr_size;

SQLINTEGER loptr_valsize = 0;

/* BLOB specification structure */

SQLCHAR* lospec_buffer;

SQLSMALLINT lospec_size;

SQLINTEGER lospec_valsize = 0;

sprintf((char *) connStrIn, "DSN=demo_on");

sprintf((char *) sqlstmt, "INSERT INTO catalog(catalog_num,advert_descr) VALUES

(0,?)");

/* Read the file to insert in the BLOB */

stat(file_name,&statbuf);

blob_size = statbuf.st_size;

blob_data = malloc (blob_size + 1);

fd = _open (file_name, O_RDONLY);

_read (fd, blob_data, blob_size);

_close(fd);

blob_data[blob_size] = '\0';

blob_wsize = blob_size;

SQLAllocHandle (SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

SQLSetEnvAttr (henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) SQL_OV_ODBC3, 0);

SQLAllocHandle (SQL_HANDLE_DBC, henv, &hdbc);

96

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch03.fm

SQLDriverConnect (hdbc, NULL, connStrIn, SQL_NTS, connStrOut, sizeof(connStrOut),

&connStrOutLen, SQL_DRIVER_NOPROMPT);

SQLAllocHandle (SQL_HANDLE_STMT, hdbc, &hstmt );

/* Obtain the size of the lospec and allocate memory */

SQLGetInfo (hdbc, SQL_INFX_LO_SPEC_LENGTH, &lospec_size, sizeof(lospec_size), NULL);

lospec_buffer = malloc (lospec_size);

/* Call ifx_lo_def_create_spec() to create a lospec */

SQLBindParameter (hstmt, 1, SQL_PARAM_INPUT_OUTPUT, SQL_C_BINARY,

SQL_INFX_UDT_FIXED, (UDWORD)lospec_size, 0, lospec_buffer, lospec_size,

&lospec_valsize);

SQLExecDirect (hstmt, (SQLCHAR *) "{call ifx_lo_def_create_spec(?)}", SQL_NTS);

SQLFreeStmt (hstmt, SQL_RESET_PARAMS);

/* Call ifx_lo_col_info() to initialise the lospec */

SQLBindParameter (hstmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, sizeof(colname),

0, colname, sizeof(colname), &colname_size);

lospec_valsize = lospec_size;

SQLBindParameter (hstmt, 2, SQL_PARAM_INPUT_OUTPUT, SQL_C_BINARY,

SQL_INFX_UDT_FIXED, (UDWORD)lospec_size, 0, lospec_buffer, lospec_size,

&lospec_valsize);

rc=SQLExecDirect (hstmt, (SQLCHAR *) "{call ifx_lo_col_info(?, ?)}", SQL_NTS);

SQLFreeStmt (hstmt, SQL_RESET_PARAMS);

/* Obtain the size of the smart loptr and allocate memory */

SQLGetInfo (hdbc, SQL_INFX_LO_PTR_LENGTH, &loptr_size, sizeof(loptr_size), NULL);

loptr_buffer = malloc (loptr_size);

/* Call ifx_lo_create() to create the BLOB */

SQLBindParameter (hstmt, 1, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_INFX_UDT_FIXED,

(UDWORD)lospec_size, 0, lospec_buffer, lospec_size, &lospec_valsize);

rc=SQLBindParameter (hstmt, 2, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, (UDWORD)0,

0, &mode, sizeof(mode), &cbMode);

loptr_valsize = loptr_size;

SQLBindParameter (hstmt, 3, SQL_PARAM_INPUT_OUTPUT, SQL_C_BINARY,

SQL_INFX_UDT_FIXED, (UDWORD)loptr_size, 0, loptr_buffer, loptr_size, &loptr_valsize);

SQLBindParameter (hstmt, 4, SQL_PARAM_OUTPUT, SQL_C_SLONG, SQL_INTEGER, (UDWORD)0,

0, &lofd, sizeof(lofd), &lofd_valsize);

SQLExecDirect (hstmt, (SQLCHAR *) "{call ifx_lo_create(?, ?, ?, ?)}", SQL_NTS);

SQLFreeStmt (hstmt, SQL_RESET_PARAMS);

/* Call ifx_lo_write to write the BLOB data */

SQLBindParameter (hstmt, 1, SQL_PARAM_INPUT, SQL_C_SLONG, SQL_INTEGER, (UDWORD)0, 0,

&lofd, sizeof(lofd), &lofd_valsize);

SQLBindParameter (hstmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR,

(UDWORD)blob_size, 0, blob_data, blob_size, &blob_wsize);

SQLExecDirect (hstmt, (SQLCHAR *) "{call ifx_lo_write(?, ?)}", SQL_NTS);

SQLFreeStmt (hstmt, SQL_RESET_PARAMS);

loptr_valsize = loptr_size;

/* Call SQLExecDirect to do the INSERT */

Chapter 3. Working with the ODBC driver

97

7884ch03.fm

Draft Document for Review August 23, 2010 10:53 am

SQLBindParameter (hstmt, 1, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_INFX_UDT_FIXED,

(UDWORD)loptr_size, 0, loptr_buffer, loptr_size, &loptr_valsize);

SQLExecDirect (hstmt, sqlstmt, SQL_NTS);

/* Call ifx_lo_close() to close the BLOB */

rc = SQLBindParameter (hstmt, 1, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER,

(UDWORD)0, 0, &lofd, sizeof(lofd), &lofd_valsize);

SQLExecDirect (hstmt, (SQLCHAR *) "{call ifx_lo_close(?)}", SQL_NTS);

free (lospec_buffer);

free (loptr_buffer);

free (blob_data);

SQLFreeStmt (hstmt, SQL_CLOSE);

SQLFreeHandle (SQL_HANDLE_STMT, hstmt);

SQLDisconnect (hdbc);

SQLFreeHandle (SQL_HANDLE_DBC, hdbc);

SQLFreeHandle (SQL_HANDLE_ENV, henv);

return (rc);

}

Accessing a Smart Large Object

Reading a Smart Large Object from the database involves the following steps:

1. Allocate memory for the smart-large-object pointer structure (loptr).

2. Perform the SELECT statement

3. Bind the smart-large-object pointer structure variable with loptr retrieved from the database.

4. Call

ifx_lo_open() to open the smart-large-object with the loptr fetched from the database. This step open the smart-large-object on the database.

5. Obtain the size of the smart-large-object status structure (lostat) and allocate enough memory.

6. Call ifx_lo_stat() to obtain the BLOB status structure, so we can retrieve the estimated size of the BLOB in the next step.

7. Call ifx_lo_stat_size() to retrieve the size of the BLOB data and allocate enough memory.

8. Call

ifx_lo_read() to retrieve the BLOB data.

9. Perform any operation with the BLOB data.

10.Call ifx_lo_close()

to close the BLOB.

Example 3-25 on page 99 shows a simple application that select a CLOB column

from the database.

98

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch03.fm

Example 3-25 Select_lo.c

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#ifdef WIN32

#include <io.h>

#include <windows.h>

#include <conio.h>

#include <fcntl.h>

#include <sys/stat.h>

#endif

#include "infxcli.h" int main (long argc, char* argv[])

{

SQLHDBChdbc;

SQLHENVhenv;

SQLHSTMThstmt;

/* BLOB file descriptor */

SQLLENlofd;

SQLLENlofd_valsize = 0;

/* BLOB pointer structure */

SQLCHAR*loptr_buffer;

SQLSMALLINTloptr_size;

SQLLENloptr_valsize = 0;

/* BLOB status structure */

SQLCHAR*lostat_buffer;

SQLSMALLINTlostat_size;

SQLLENlostat_valsize = 0;

/* BLOB data */

SQLCHAR*lo_data;

SQLLENlo_data_valsize = 0;

SQLRETURNrc = 0;

SQLCHAR*dsn = "demo_on";

SQLCHAR*selectStmt = (SQLCHAR *) "SELECT advert_descr FROM catalog where catalog_num

= 10075";

SQLINTEGERmode = LO_RDONLY;

SQLLENlo_size;

SQLLENcbMode = 0, cbLoSize = 0;

SQLAllocHandle (SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

SQLSetEnvAttr (henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) SQL_OV_ODBC3, 0);

SQLAllocHandle (SQL_HANDLE_DBC, henv, &hdbc);

SQLConnect (hdbc, dsn, SQL_NTS, (SQLCHAR *) "", SQL_NTS, (SQLCHAR *) "", SQL_NTS);

SQLAllocHandle (SQL_HANDLE_STMT, hdbc, &hstmt );

/* Get the size of the loptr */

SQLGetInfo (hdbc, SQL_INFX_LO_PTR_LENGTH, &loptr_size, sizeof(loptr_size), NULL);

Chapter 3. Working with the ODBC driver

99

7884ch03.fm

Draft Document for Review August 23, 2010 10:53 am

loptr_buffer = malloc (loptr_size);

SQLExecDirect (hstmt, selectStmt, SQL_NTS);

/* Bind the loptr with the resulset column */

SQLBindCol (hstmt, 1, SQL_C_BINARY, loptr_buffer, loptr_size, &loptr_valsize);

SQLFetch (hstmt);

SQLCloseCursor (hstmt);

/* Call ifx_lo_open() using the loptr fetched from the database */

SQLBindParameter (hstmt, 1, SQL_PARAM_OUTPUT, SQL_C_LONG, SQL_INTEGER, (UDWORD)0, 0,

&lofd, sizeof(lofd), &lofd_valsize);

SQLBindParameter (hstmt, 2, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_INFX_UDT_FIXED,

(UDWORD)loptr_size, 0, loptr_buffer, loptr_size, &loptr_valsize);

SQLBindParameter (hstmt, 3, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, (UDWORD)0, 0,

&mode, sizeof(mode), &cbMode);

SQLExecDirect (hstmt, (SQLCHAR *) "{? = call ifx_lo_open(?, ?)}", SQL_NTS);

SQLFreeStmt (hstmt, SQL_RESET_PARAMS);

/* Get the size of the lostat and allocate enough memory */

SQLGetInfo (hdbc, SQL_INFX_LO_STAT_LENGTH, &lostat_size, sizeof(lostat_size), NULL);

lostat_buffer = malloc(lostat_size);

/* Call ifx_lo_stat() to get the BLOB lostat */

SQLBindParameter (hstmt, 1, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, (UDWORD)0, 0,

&lofd, sizeof(lofd), &lofd_valsize);

SQLBindParameter (hstmt, 2, SQL_PARAM_INPUT_OUTPUT, SQL_C_BINARY,

SQL_INFX_UDT_FIXED, (UDWORD)lostat_size, 0, lostat_buffer, lostat_size,

&lostat_valsize);

SQLExecDirect (hstmt, (SQLCHAR *) "{call ifx_lo_stat(?, ?)}", SQL_NTS);

SQLFreeStmt (hstmt, SQL_RESET_PARAMS);

/* Call ifx_lo_stat_size to get the size of the BLOB data and allocate enough memory*/

SQLBindParameter (hstmt, 1, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_INFX_UDT_FIXED,

(UDWORD)lostat_size, 0, lostat_buffer, lostat_size, &lostat_valsize);

SQLBindParameter (hstmt, 2, SQL_PARAM_OUTPUT, SQL_C_LONG, SQL_BIGINT, (UDWORD)0, 0,

&lo_size, sizeof(lo_size), &cbLoSize);

SQLExecDirect (hstmt, (SQLCHAR *) "{call ifx_lo_stat_size(?, ?)}", SQL_NTS);

SQLFreeStmt (hstmt, SQL_RESET_PARAMS);

lo_data = malloc (lo_size + 1);

/* Call ifx_lo_read() to get the BLOB data */

SQLBindParameter (hstmt, 1, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, (UDWORD)0, 0,

&lofd, sizeof(lofd), &lofd_valsize);

SQLBindParameter (hstmt, 2, SQL_PARAM_OUTPUT, SQL_C_CHAR, SQL_CHAR, lo_size, 0, lo_data, lo_size, &lo_data_valsize);

SQLExecDirect (hstmt, (SQLCHAR *) "{call ifx_lo_read(?, ?)}", SQL_NTS);

lo_data[lo_size] = '\0';

SQLFreeStmt (hstmt, SQL_RESET_PARAMS);

/* Call ifx_lo_close() to close the BLOB */

SQLBindParameter (hstmt, 1, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, (UDWORD)0, 0,

&lofd, sizeof(lofd), &lofd_valsize);

SQLExecDirect (hstmt, (SQLCHAR *) "{call ifx_lo_close(?)}",SQL_NTS);

100

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch03.fm

fprintf(stdout,"%s",lo_data);

free (loptr_buffer);

free (lostat_buffer);

free (lo_data);

SQLFreeStmt (hstmt, SQL_CLOSE);

SQLFreeHandle (SQL_HANDLE_STMT, hstmt);

SQLDisconnect (hdbc);

SQLFreeHandle (SQL_HANDLE_DBC, hdbc);

SQLFreeHandle (SQL_HANDLE_ENV, henv);

return (rc);

}

Use Smart Large Object automation

Developing an application to handle Smart Large Object using the Smart Large

Object automation method does not require any special attention, just use

SQL_LONGBINARY

and

SQL_LONGVARCHAR

as data type.

Example 3-26 Illustrates how to insert a large-object with the

SQL_INFX_ATTR_LO_AUTOMATIC

enabled

Example 3-26 Lo_auto.c

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#ifdef WIN32

#include <io.h>

#include <windows.h>

#include <conio.h>

#include <fcntl.h>

#include <sys/stat.h>

#endif

#include "infxcli.h" int main (long argc, char* argv[])

{

SQLHDBC hdbc;

SQLHENV henv;

SQLHSTMT hstmt;

SQLCHAR* dsn="demo_on";

SQLCHAR sqlstmt[128];

SQLCHAR str[128];

SQLLEN str_len = SQL_NTS;

Chapter 3. Working with the ODBC driver

101

7884ch03.fm

Draft Document for Review August 23, 2010 10:53 am

SQLSMALLINT BufferLength = 128;

SQLINTEGER int_val;

SQLRETURN rc = 0;

SQLAllocHandle (SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

SQLSetEnvAttr (henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) SQL_OV_ODBC3, 0);

SQLAllocHandle (SQL_HANDLE_DBC, henv, &hdbc);

SQLConnect (hdbc, dsn, SQL_NTS, (SQLCHAR *) "", SQL_NTS, (SQLCHAR *) "", SQL_NTS);

SQLAllocHandle (SQL_HANDLE_STMT, hdbc, &hstmt );

/* Set SQL_INFX_ATTR_ODBC_TYPES_ONLY connection attribute to FALSE*/

SQLSetConnectAttr(hdbc, SQL_INFX_ATTR_ODBC_TYPES_ONLY, (SQLPOINTER) SQL_FALSE,

SQL_IS_UINTEGER);

/* Set SQL_INFX_ATTR_LO_AUTOMATIC connection attribute to TRUE*/

SQLSetConnectAttr(hdbc, SQL_INFX_ATTR_LO_AUTOMATIC, (SQLPOINTER) SQL_TRUE,

SQL_IS_UINTEGER);

SQLAllocHandle (SQL_HANDLE_STMT, hdbc, &hstmt );

/* Preare the SQL statement */

sprintf(sqlstmt, "INSERT INTO catalog(catalog_num,advert_descr) VALUES (0,?)");

SQLPrepare (hstmt, sqlstmt, SQL_NTS);

/* Bind the input parameter and Execute the SQL */

SQLBindParameter (hstmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_LONGVARCHAR,

BufferLength, 0, &str, 0, &str_len);

SQLExecute (hstmt);

SQLFreeStmt (hstmt, SQL_CLOSE);

SQLFreeHandle (SQL_HANDLE_STMT, hstmt);

SQLDisconnect (hdbc);

SQLFreeHandle (SQL_HANDLE_DBC, hdbc);

SQLFreeHandle (SQL_HANDLE_ENV, henv);

return (rc);

}

Complex data types

Rows and Collections are composite values that consist of one or more elements. You can use the execute SQL statements to access an entire row or collection. However, you can not access individual elements within a row or collection.

To access composite values from the ODBC driver you must use the Client functions for Rows and Collections.

Client functions for Rows and Collections

The ODBC functions for handling Rows and Collections start with the prefix

ifx_rc_ . Table 3-12 on page 103 lists the available functions.

102

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch03.fm

Table 3-12 Row and Collection Client functions

Function Description

ifx_rc_count() Returns the number of elements or fields that are in a row or collection ifx_rc_create() ifx_rc_delete() ifx_rc_describe()

Creates a buffer for a row or collection

Deletes an element from a collection

Returns information about the complex data type or and individual element ifx_rc_fetch() ifx_rc_free() ifx_rc_insert() ifx_rc_isnull()

Returns the value of an element that is in a row or collection

Frees a row or collection handle

Inserts a new element into a collection

Evaluate if a complex type is NULL or not ifx_rc_setnull() Set a complex type to NULL ifx_rc_typespec() Returns the type specification for a row or collection ifx_rc_update() Updates the value for an element that is in a row or collection

Creating a complex data type

Example 3-27 shows how to perform an INSERT operation using the Informix

ODBC functions ifx_rc_xxx. We are using a simple table customer_rc defined as follows:

CREATE ROW TYPE name_t ( fname VARCHAR(15), lname VARCHAR(15)

);

CREATE TABLE customer_rc ( customer_num SERIAL, customer_name name_t, contact_dates LIST(DATETIME YEAR TO DAY NOT NULL)

);

Example 3-27 Create_rc.c

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#ifdef WIN32

#include <io.h>

#include <windows.h>

Chapter 3. Working with the ODBC driver

103

7884ch03.fm

Draft Document for Review August 23, 2010 10:53 am

#include <conio.h>

#include <fcntl.h>

#include <sys/stat.h>

#endif

#include "infxcli.h" int main (long argc, char* argv[])

{

SQLHDBChdbc;

SQLHENVhenv;

SQLHSTMThstmt;

/* Row variables */

HINFX_RChrow;

HINFX_RChlist;

SQLCHAR*dsn = "demo_on";

SQLRETURNrc = 0;

SQLINTEGERi, in;

SQLLENdata_size = SQL_NTS;

SQLSMALLINTposition = SQL_INFX_RC_ABSOLUTE;

SQLSMALLINTjump;

SQLCHARrow_data[2][15] = {"Ludwig", "Pauli"};

SQLLENrow_data_size = SQL_NTS;

SQLCHARlist_data[2][25] = {"2008-08-16","2008-08-16"};

SQLLENlist_data_size = SQL_NTS;

SQLCHAR*insertStmt = (SQLCHAR *) "INSERT INTO customer_rc VALUES (0, ?, ?)";

SQLLENcbHrow = 0, cbHlist = 0, cbPosition = 0, cbJump = 0;

/* Connection */

SQLAllocHandle (SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

SQLSetEnvAttr (henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) SQL_OV_ODBC3, 0);

SQLAllocHandle (SQL_HANDLE_DBC, henv, &hdbc);

SQLConnect (hdbc, dsn, SQL_NTS, (SQLCHAR *) "", SQL_NTS, (SQLCHAR *) "", SQL_NTS);

SQLAllocHandle (SQL_HANDLE_STMT, hdbc, &hstmt );

/* Call ifx_rc_create() to allocate a row handle */

SQLBindParameter (hstmt, 1, SQL_PARAM_OUTPUT, SQL_C_BINARY, SQL_INFX_RC_ROW, sizeof(HINFX_RC), 0, &hrow, sizeof(HINFX_RC), &cbHrow);

SQLBindParameter (hstmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, 0, 0, (SQLCHAR *)

"ROW(fname VARCHAR(15), lname VARCHAR(15))", 0, &data_size);

SQLExecDirect (hstmt, (SQLCHAR *) "{? = call ifx_rc_create(?)}", SQL_NTS);

/* Call ifx_rc_create() to allocate a list handle */

SQLBindParameter (hstmt, 1, SQL_PARAM_OUTPUT, SQL_C_BINARY, SQL_INFX_RC_LIST, sizeof(HINFX_RC), 0, &hlist, sizeof(HINFX_RC), &cbHlist);

SQLBindParameter (hstmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, 0, 0, (SQLCHAR *)

"LIST (DATETIME YEAR TO DAY NOT NULL)", 0, &data_size);

SQLExecDirect (hstmt, (SQLCHAR *) "{? = call ifx_rc_create(?)}", SQL_NTS);

SQLFreeStmt (hstmt, SQL_RESET_PARAMS);

/* call ifx_rc_update() to insert elements into the row */ for (i=0; i<2; i++)

104

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch03.fm

{

SQLBindParameter (hstmt, 1, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_INFX_RC_ROW, sizeof(HINFX_RC), 0, hrow, sizeof(HINFX_RC), &cbHrow);

SQLBindParameter (hstmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, 25, 0, row_data[i], 0, &row_data_size);

SQLBindParameter (hstmt, 3, SQL_PARAM_INPUT, SQL_C_SHORT, SQL_SMALLINT, 0, 0,

&position, 0, &cbPosition);

&jump, 0, &cbJump);

SQLExecDirect (hstmt, (SQLCHAR *)"{call ifx_rc_update(?, ?, ?, ?)}", SQL_NTS);

} jump = i + 1;

SQLBindParameter (hstmt, 4, SQL_PARAM_INPUT, SQL_C_SHORT, SQL_SMALLINT, 0, 0,

/* Call ifx_rc_insert() to insert elements into the list */ for (i=0; i<2; i++)

{

SQLBindParameter (hstmt, 1, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_INFX_RC_LIST, sizeof(HINFX_RC), 0, hlist, sizeof(HINFX_RC), &cbHlist);

SQLBindParameter (hstmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR,SQL_DATE, 25, 0, list_data[i], 0, &list_data_size);

SQLBindParameter (hstmt, 3, SQL_PARAM_INPUT, SQL_C_SHORT, SQL_SMALLINT, 0, 0,

&position, 0, &cbPosition); jump = i + 1;

SQLBindParameter (hstmt, 4, SQL_PARAM_INPUT, SQL_C_SHORT, SQL_SMALLINT, 0, 0,

&jump, 0, &cbJump);

SQLExecDirect (hstmt, (SQLCHAR *)"{call ifx_rc_insert( ?, ?, ?, ? )}", SQL_NTS);

}

SQLFreeStmt (hstmt, SQL_RESET_PARAMS);

SQLBindParameter (hstmt, 1, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_INFX_RC_COLLECTION, sizeof(HINFX_RC), 0, hrow, sizeof(HINFX_RC), &cbHrow);

SQLBindParameter (hstmt, 2, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_INFX_RC_COLLECTION, sizeof(HINFX_RC), 0, hlist, sizeof(HINFX_RC), &cbHlist);

SQLExecDirect (hstmt, insertStmt, SQL_NTS);

SQLBindParameter (hstmt, 1, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_INFX_RC_ROW, sizeof(HINFX_RC), 0, hrow, sizeof(HINFX_RC), &cbHrow);

SQLExecDirect(hstmt, (SQLCHAR *)"{call ifx_rc_free(?)}", SQL_NTS);

/* Free the list handle */

SQLBindParameter (hstmt, 1, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_INFX_RC_LIST, sizeof(HINFX_RC), 0, hlist, sizeof(HINFX_RC), &cbHlist);

SQLExecDirect(hstmt, (SQLCHAR *)"{call ifx_rc_free(?)}", SQL_NTS);

SQLFreeStmt (hstmt, SQL_CLOSE);

SQLFreeHandle (SQL_HANDLE_STMT, hstmt);

SQLDisconnect (hdbc);

SQLFreeHandle (SQL_HANDLE_DBC, hdbc);

SQLFreeHandle (SQL_HANDLE_ENV, henv);

return (rc);

}

Chapter 3. Working with the ODBC driver

105

7884ch03.fm

Draft Document for Review August 23, 2010 10:53 am

Example 3-28 shows the information inserted into the

customer_rc table after the execution of the example.

Example 3-28 customer_rc table

> select * from customer_rc

> ; customer_num 1 customer_name ROW('Ludwig','Pauli') contact_dates LIST{'2008-08-16','2008-08-16'}

1 row(s) retrieved.

>

Accessing a complex data type

Example 3-29 demonstrates how to select a Row type with the ODBC driver.

Example 3-29 Select_row.c.

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#ifdef WIN32

#include <io.h>

#include <windows.h>

#include <conio.h>

#include <fcntl.h>

#include <sys/stat.h>

#endif

#include "infxcli.h" int main (long argc, char* argv[])

{

SQLHDBC hdbc;

SQLHENV henv;

SQLHSTMT hstmt, hstmt_row;

HINFX_RC hrow;

SQLCHAR *dsn="demo_on";

SQLRETURN rc = 0;

SQLINTEGER i;

SQLSMALLINT position = SQL_INFX_RC_ABSOLUTE, jump = 0;

SQLLEN cbHrow = 0, cbPosition = 0, cbJump = 0, cbRCData = 0;

SQLLEN data_size = SQL_NTS, cbrow = 0;

106

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch03.fm

SQLCHAR* sqlstmt = (SQLCHAR *) "SELECT customer_name FROM customer_rc WHERE customer_num = 1";

SQLCHAR row_data[200];

/* Connection */

SQLAllocHandle (SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

SQLSetEnvAttr (henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) SQL_OV_ODBC3, 0);

SQLAllocHandle (SQL_HANDLE_DBC, henv, &hdbc);

SQLConnect (hdbc, dsn, SQL_NTS, (SQLCHAR *) "", SQL_NTS, (SQLCHAR *) "", SQL_NTS);

SQLAllocHandle (SQL_HANDLE_STMT, hdbc, &hstmt);

SQLAllocHandle (SQL_HANDLE_STMT, hdbc, &hstmt_row);

/* Call ifx_rc_create() to allocate a row handle */

SQLBindParameter (hstmt, 1, SQL_PARAM_OUTPUT, SQL_C_BINARY, SQL_INFX_RC_ROW, sizeof(HINFX_RC), 0, &hrow, sizeof(HINFX_RC), &cbHrow);

SQLBindParameter (hstmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, 0, 0, (SQLCHAR *)

"row", 0, &data_size);

SQLExecDirect (hstmt, (SQLCHAR *) "{? = call ifx_rc_create(?)}", SQL_NTS);

SQLFreeStmt (hstmt, SQL_RESET_PARAMS);

/* Bind the row handle with the resulset column */

SQLExecDirect (hstmt, sqlstmt, SQL_NTS);

SQLBindCol (hstmt, 1, SQL_C_BINARY, (SQLPOINTER) hrow, sizeof(HINFX_RC), &cbHrow);

SQLFetch (hstmt);

/* Get the row data */

fprintf(stdout, "Row data:\n");

for (i=0; i<2; i++)

{ strcpy((char *) row_data, "<null>");

SQLBindParameter (hstmt_row, 1, SQL_PARAM_OUTPUT, SQL_C_CHAR, SQL_CHAR, 0, 0, row_data, 200, &cbRCData);

SQLBindParameter (hstmt_row, 2, SQL_PARAM_INPUT, SQL_C_BINARY,

SQL_INFX_RC_COLLECTION, sizeof(HINFX_RC), 0, hrow, sizeof(HINFX_RC), &cbHrow);

SQLBindParameter (hstmt_row, 3, SQL_PARAM_INPUT, SQL_C_SHORT, SQL_SMALLINT, 0,

0, &position, 0, &cbPosition); jump = i + 1;

SQLBindParameter (hstmt_row, 4, SQL_PARAM_INPUT, SQL_C_SHORT, SQL_SMALLINT, 0, 0,

&jump, 0, &cbJump);

/* Call ifx_rc_fetch() to fetch individual elements from the row */

SQLExecDirect (hstmt_row, (SQLCHAR *) "{ ? = call ifx_rc_fetch( ?, ?, ? ) }",

SQL_NTS);

SQLFreeStmt (hstmt_row, SQL_RESET_PARAMS);

} fprintf(stdout, "\t\t%s\n", row_data);

/* Call ifx_rc_free() to free the row handle */

SQLBindParameter(hstmt, 1, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_INFX_RC_ROW, sizeof(HINFX_RC), 0, hrow, sizeof(HINFX_RC), &cbrow);

SQLExecDirect(hstmt, (SQLCHAR *)"{call ifx_rc_free(?)}", SQL_NTS);

Chapter 3. Working with the ODBC driver

107

7884ch03.fm

Draft Document for Review August 23, 2010 10:53 am

SQLFreeStmt (hstmt, SQL_CLOSE);

SQLFreeHandle (SQL_HANDLE_STMT, hstmt);

SQLDisconnect (hdbc);

SQLFreeHandle (SQL_HANDLE_DBC, hdbc);

SQLFreeHandle (SQL_HANDLE_ENV, henv);

return (rc);

}

Example 3-30 shows the output of Example 3-29 on page 106.

Example 3-30 Output of Select_row.c

C:\work>cl /DWIN32 /D_CRT_SECURE_NO_DEPRECATE -ID:\infx\csdk350tc7\incl\cli odbc32.lib /nologo select_row.c

select_row.c

C:\work>select_row

Row data:

Ludwig

Pauli

C:\work>

3.3.5 Error handling

In this section we show how to obtain additional information when an ODBC function fails.

Error handling sample

When an ODBC function fails, it stores information in the diagnostic record. This record contains information such as error messages, warning, and status information about the success or failure of the ODBC call.

An ODBC application can retrieve the diagnostic record or individual fields using the SQLGetDiagRec() and SQLGetDiagField() ODBC functions.

Example 3-31 shows a typical usage of SQLGetDiagRec().

Example 3-31 Connect_error.c

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#ifdef WIN32

#include <io.h>

#include <windows.h>

108

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch03.fm

#include <conio.h>

#endif

#include "infxcli.h" int main (long argc, char* argv[])

{

SQLHDBC hdbc;

SQLHENV henv;

SQLRETURN rc = 0;

SQLCHAR connStrIn[1000];

SQLCHAR connStrOut[1000];

SQLSMALLINT connStrOutLen;

UCHAR SqlState[200] = "", ErrorMsg[200] = "";

SQLINTEGER IsamError = 0;

SDWORD NativeError = 0L;

SWORD ErrorMsgp = 0;

SQLSMALLINT recnum = 1;

if (argc != 2)

{

fprintf (stdout, "Please specify the name of a DSN!\n");

return(1);

}

else

{ if (strstr (argv[1],"DRIVER")==NULL) sprintf((char *) connStrIn, "DSN=%s;", (char *)argv[1]); else sprintf((char *) connStrIn, "%s;", (char *)argv[1]);

}

rc = SQLAllocHandle (SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

rc = SQLSetEnvAttr (henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) SQL_OV_ODBC3, 0);

rc = SQLAllocHandle (SQL_HANDLE_DBC, henv, &hdbc);

rc = SQLDriverConnect (hdbc, NULL, connStrIn, SQL_NTS, connStrOut, 1000,

&connStrOutLen, SQL_DRIVER_NOPROMPT);

if (rc != SQL_SUCCESS)

{

SQLGetDiagRec(SQL_HANDLE_DBC, hdbc, recnum, SqlState, &NativeError, ErrorMsg,

199, &ErrorMsgp);

fprintf(stdout, "SqlState = %s\n Native Error = %d\n Error Message = %s\n",

SqlState, NativeError, ErrorMsg);

fprintf (stdout, "Connection failed!\n");

return (1);

}

fprintf (stdout, "Connection Successful\n");

SQLDisconnect (hdbc);

SQLFreeHandle (SQL_HANDLE_DBC, hdbc);

SQLFreeHandle (SQL_HANDLE_ENV, henv);

return (rc);

Chapter 3. Working with the ODBC driver

109

7884ch03.fm

Draft Document for Review August 23, 2010 10:53 am

}

Example 3-32 shows the output of Example 3-31 on page 108. In addition to the

ODBC SQLSTATE error we return the Informix native error and the description for the error.

Example 3-32 Output of Connect_error.c

C:\work>cl /DWIN32 /D_CRT_SECURE_NO_DEPRECATE -I%INFORMIXDIR%\incl\cli odbc32.lib /nologo connect_error.c

connect_error.c

C:\work>connect_error wrongDNS

SqlState = IM002

Native Error = 0

Error Message = [Microsoft][ODBC Driver Manager] Data source name not found and no default driver specified

Connection failed!

C:\work>connect_error demo_on;UID=wronguser

SqlState = 28000

Native Error = -951

Error Message = [Informix][Informix ODBC Driver][Informix]Incorrect password or user wronguser@localhost is not known on the database server.

Connection failed!

C:\work>

Because this function is called quite often, it make sense to have a function to

display the error message. Example 3-33 Illustrates a typical error handling

function.

Example 3-33 Simple_select_werr.c

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#ifdef WIN32

#include <io.h>

#include <windows.h>

#include <conio.h>

#endif

#include "infxcli.h"

void CheckDiag (SQLSMALLINT handle_type, SQLHANDLE handle, char *text)

{

RETCODErc = SQL_SUCCESS;

UCHARSqlState[200] = "", ErrorMsg[200] = "";

110

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch03.fm

SQLINTEGERIsamError = 0;

SDWORDNativeError = 0L;

SWORDErrorMsgp = 0;

SQLSMALLINTrecnum = 1;

fprintf (stdout,"Error in %s \n",text);

while (rc != SQL_NO_DATA_FOUND) {

rc = SQLGetDiagRec(handle_type, handle, recnum, SqlState, &NativeError,

ErrorMsg, 199, &ErrorMsgp);

if (rc != SQL_NO_DATA_FOUND) {

SQLGetDiagField(handle_type, handle, recnum, SQL_DIAG_ISAM_ERROR,

&IsamError, SQL_IS_INTEGER, NULL);

fprintf (stdout," SqlState = %s\n Native Error = %d\n Error Message = %s\n

ISAM Error = %d\n", SqlState, NativeError, ErrorMsg, IsamError);

}

recnum++;

}

} int main (long argc, char* argv[])

{

SQLHDBC hdbc;

SQLHENV henv;

SQLHSTMT hstmt;

SQLRETURN rc = 0;

SQLCHAR connStrIn[1000];

SQLCHAR connStrOut[1000];

SQLSMALLINT connStrOutLen;

int sqllen;

SQLCHAR *sqlstmt;

if (argc != 3)

{

fprintf (stdout, "Please specify the name of a DSN and the SQL Statement to run!\n");

return(1);

}

else

{ if (strstr (argv[1],"DRIVER")==NULL) sprintf((char *) connStrIn, "DSN=%s;", (char *)argv[1]); else sprintf((char *) connStrIn, "%s;", (char *)argv[1]);

sqllen = strlen((char *)argv[2]);

sqlstmt = (SQLCHAR *) malloc (sqllen + sizeof(char));

strcpy((char *)sqlstmt, (char *)argv[2]);

}

SQLAllocHandle (SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);

SQLSetEnvAttr (henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER) SQL_OV_ODBC3, 0);

Chapter 3. Working with the ODBC driver

111

7884ch03.fm

Draft Document for Review August 23, 2010 10:53 am

SQLAllocHandle (SQL_HANDLE_DBC, henv, &hdbc);

SQLDriverConnect (hdbc, NULL, connStrIn, SQL_NTS, connStrOut, 1000, &connStrOutLen,

SQL_DRIVER_NOPROMPT);

fprintf (stdout, "Connected\n");

SQLAllocHandle (SQL_HANDLE_STMT, hdbc, &hstmt );

rc = SQLExecDirect (hstmt, sqlstmt, SQL_NTS);

if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO)

{

CheckDiag(SQL_HANDLE_STMT, hstmt,"SQLExecDirect()");

fprintf (stdout, "SQLExecDirectW() failed!\n");

return (1);

}

fprintf (stdout, "Executed SQL Statement:\n%s\n",sqlstmt);

SQLDisconnect (hdbc);

SQLFreeHandle (SQL_HANDLE_DBC, hdbc);

SQLFreeHandle (SQL_HANDLE_ENV, henv);

return (rc);

}

We create a function called

CheckDiag()

to retrieve the diagnostic information: void CheckDiag (SQLSMALLINT handle_type, SQLHANDLE handle, char *text)

Example 3-34 shows the output of the previous sample.

Example 3-34 Output of Simple_select_werr.c

C:\work>simple_sql_werror demo_on "wrong sql"

Connected

Error in SQLExecDirect()

SqlState = 42000

Native Error = -201

Error Message = [Informix][Informix ODBC Driver][Informix]A syntax error has occurred.

ISAM Error = 0

SQLExecDirectW() failed!

C:\work>simple_sql_werror demo_on "DELETE from wrongtable"

Connected

Error in SQLExecDirect()

SqlState = 42S02

Native Error = -206

Error Message = [Informix][Informix ODBC Driver][Informix]The specified table

(wrongtable) is not in the database.

ISAM Error = -111

SQLExecDirectW() failed!

112

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

C:\work>

7884ch03.fm

Note: If an error is generated by the database server, the error message

contains the string

[Informix]

before the description of the error. For example:

Error in SQLExecDirect()

SqlState = 42S02

Native Error = -206

Error Message = [Informix][Informix ODBC Driver][Informix]The specified table (test) is not in the database.

ISAM Error = -111

SQLExecDirectW() failed!

ODBC SQLSTATE errors with Informix ODBC Driver

The error returned by the ODBC function is based on the X/Open standard

SQLSTATE errors. For the SQLSTATE codes, refer to the Informix ODBC Driver

Guide at http://publib.boulder.ibm.com/infocenter/idshelp/v115/topic/com.ibm.odbc.doc/si i091033222.htm#sii091033222

3.3.6 Troubleshooting

In this section we discuss typical problems when using the Informix ODBC drivers and available traces.

Environment

Make sure the setup of your Informix Client is correct. If your application fails to load the ODBC driver, check if the Informix Client or Data Server Client libraries are accessible to you application.

򐂰 The environment variable PATH should contain the

bin

directory of your Client package.

򐂰

The shared library PATH variable on an UNIX machine should contain the directory where the shared libraries are located.

򐂰 Make sure that the INFORMIXDIR variable is set correctly (as an environment variable or stored in the registry using the Setnet32 tool).

򐂰

32-bit applications requires 32-bit drivers to work. Make sure the drivers you have install are of the same type as your application.

If your application is failing to connect, make sure the connection details are valid.

Chapter 3. Working with the ODBC driver

113

7884ch03.fm

Draft Document for Review August 23, 2010 10:53 am

Informix Client SDK on Windows contains a simple connection tool called

ilogin

which can be used to check if you have connection with the database server. If ilogin fails to connect, all the other drivers would also fail.

򐂰

Check that the values stored in the registry with Setnet32 are valid.

򐂰 If you are using 32-bit and 64-bit drivers on the same machine remember that on Windows, there are two registry hives to stored the connectivity information, so make sure both are correct.

Tracing

When developing an application using the ODBC driver, most problems are caused by passing incorrect parameters to the ODBC functions.

ODBC Trace

You can generate a trace file of all the calls to the ODBC driver using the ODBC

Trace facility.

On a Windows machine, you can enable ODBC Trace using the ODBC Data

Source Administrator. Figure 3-14 shows the Tracing tab.

Figure 3-14 Enabling trace

Note: Remember to select Machine-Wide tracing for all user identities if

your application runs as a service or with a different user.

Example 3-35 on page 115 shows some of the entries in an ODBC trace file.

114

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch03.fm

Example 3-35 ODBC trace

...

rccreate 99c-db8 EXIT SQLBindParameter with return code 0

(SQL_SUCCESS)

HSTMT 01D51DC0

UWORD 2

SWORD 1 <SQL_PARAM_INPUT>

SWORD 1 <SQL_C_CHAR>

SWORD 1 <SQL_CHAR>

SQLULEN 25

SWORD 0

PTR 0x002CFEC8

SQLLEN 0

SQLLEN * 0x002CFF50 (-3) rccreate 99c-db8 ENTER SQLBindParameter

HSTMT 01D51DC0

UWORD 3

SWORD 1 <SQL_PARAM_INPUT>

SWORD 5 <SQL_C_SHORT>

SWORD 5 <SQL_SMALLINT>

SQLULEN 0

SWORD 0

PTR 0x002CFF68

SQLLEN 0

SQLLEN * 0x002CFF54

...

On a UNIX machine, ODBC trace is active if the

Trace

parameter in the [ODBC] section of the odbc.ini

configuration file is set to

1

.

Example 3-36 shows the Trace settings for the odbc.ini file.

Example 3-36 Trace in odbc.ini

;

; Trace file Section

;

Trace=1

TraceFile=/tmp/odbctrace.out

InstallDir=/opt/IBM/informix

TRACEDLL=idmrs09a.so

SQLIDEBUG

All the Informix clients uses the SQLI protocol to communicate with the database server.

Chapter 3. Working with the ODBC driver

115

7884ch03.fm

Draft Document for Review August 23, 2010 10:53 am

In addition to the ODBC trace, you can generate a SQLIDEBUG trace which contains all the message between the client application and the database server.

You can enable SQLIDEBUG trace at the Client side by defining the environment variable as follows:

SQLIDEBUG=2:path_to_trace_files

Or at the server side by running the following command: onmode -p 1 sqli_dbg

Note: On a Windows machine, when using the server side tracing, the

SQLIDEBUG files are created in

C:\temp\sqli

. This directory must exists before enabling the trace.

On a UNIX machine the trace files are created in

/tmp/sqli

Example 3-37 demonstrates how to set SQLIDEBUG trace on the client.

Example 3-37 SQLIDEBUG sample

C:\work>set SQLIDEBUG=2:sqli_trace

C:\work>simple_sql_werror demo_on "wrong_sql"

Connected

Error in SQLExecDirect()

SqlState = 42000

Native Error = -201

Error Message = [Informix][Informix ODBC Driver][Informix]A syntax error has occurred.

ISAM Error = 0

SQLExecDirectW() failed!

C:\work>dir sqli_trace_2940_1016_1f428b8

Volume in drive C is W2003

Volume Serial Number is 50DA-70D7

Directory of C:\work

22/06/2010 18:39 348 sqli_trace_2940_1016_1f428b8

1 File(s) 348 bytes

0 Dir(s) 76,628,099,072 bytes free

C:\work>

The SQLIDEBUG trace files contains the SQLI packages between the server and the client. To obtain an readable output, you must run the sqliprt

tool.

116

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

Example 3-38 demonstrates how to run sqliprt.

Example 3-38 sqliprint output

C:\work>sqliprt -o trace.txt sqli_trace_2940_1016_1f428b8

C:\work>type trace.txt

SQLIDBG Version 1

C->S (4) Time: 2010-06-22 18:39:05.43700

SQ_INTERNALVER

Internal Version Number: 316

C->S (14) Time: 2010-06-22 18:39:05.43700

SQ_PROTOCOLS

SQ_EOT

S->C (14) Time: 2010-06-22 18:39:05.43700

SQ_PROTOCOLS

SQ_EOT

C->S (90) Time: 2010-06-22 18:39:05.43700

SQ_INFO

INFO_ENV

Name Length = 12

Value Length = 34

"DBTEMP"="C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp"

"SUBQCACHESZ"="10"

"OPTOFC"="0"

INFO_DONE

SQ_EOT

S->C (2) Time: 2010-06-22 18:39:05.43700

SQ_EOT

C->S (4) Time: 2010-06-22 18:39:05.43700

SQ_BEGIN

SQ_EOT

S->C (10) Time: 2010-06-22 18:39:05.43700

SQ_XACTSTAT

SQ_EOT

C->S (4) Time: 2010-06-22 18:39:05.43700

SQ_CMMTWORK

SQ_EOT

S->C (10) Time: 2010-06-22 18:39:05.43700

SQ_XACTSTAT

SQ_EOT

C->S (22) Time: 2010-06-22 18:39:05.43700

SQ_PREPARE

# values: 0

7884ch03.fm

Chapter 3. Working with the ODBC driver

117

7884ch03.fm

Draft Document for Review August 23, 2010 10:53 am

CMD.....: "wrong_sql" [9]

SQ_NDESCRIBE

SQ_WANTDONE

SQ_EOT

S->C (12) Time: 2010-06-22 18:39:05.43700

SQ_ERR

SQL error..........: -201

ISAM/RSAM error....: 0

Offset in statement: 1

Error message......: "" [0]

SQ_EOT

C:\work>

Note: On a UNIX machine, the equivalent of the sqliprt tool is

sqliprint

.

DRDADEBUG

All the IBM Data Server Drivers use the DRDA protocol to communicate with the database server.

Similar to SQLIDEBUG, you can enable DRDADEBUG trace at the server side by running the following onmode command: onmode -p 1 drda_dbg

The DRDA trace files are created in /tmp/drda for a UNIX machine and

C:\temp\drda for a Windows. You need to use the drdaprint tool to convert the trace files to a readable format.

Example 3-39 shows the use of drdaprint.

Example 3-39 DRDAPRINT

C:\temp\drda>dir

Volume in drive C is W2003

Volume Serial Number is 50DA-70D7

Directory of C:\temp\drda

22/06/2010 18:50 <DIR> .

22/06/2010 18:50 <DIR> ..

22/06/2010 18:50 2,269 drda.47

1 File(s) 2,269 bytes

2 Dir(s) 76,628,135,936 bytes free

C:\temp\drda>drdaprint

Usage: drdaprint [-f] [-o outfile] inpfile

-f: format hex dump

118

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch03.fm

C:\temp\drda>drdaprint -o trace.txt drda.47

C:\temp\drda>

Example 3-40 shows a section of the DRDA trace file.

Example 3-40 DRDATrace file

C:\temp\drda>type trace.txt

DRDADBG Version 1

1 data IDS DRDA Communication Manager

function sqljcIntReceive()

bytes 270

time 2010-06-22 18:50:13.31200

RECEIVE BUFFER(AS):

EXCSAT RQSDSS (ASCII) (EBCDIC)

0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF 0123456789ABCDEF

0000 00C3D041000100BD 10410080115EA289 ...A.....A...^.. .C}..........;si

0010 949793856DA29893 6DA685999996994B ....m...m......K mple_sql_werror.

0020 85A7F0F6F1F4F0C4 F9F4F0F0F0000000 ................ ex06140D94000...

0030 0000000000000000 0000000000000000 ................ ................

0040 0000000000000000 000000000060F0F0 .............`.. .............-00

0050 F0F1C1C4D4C9D5C9 E2E3D9C1E3D6D940 ...............@ 01ADMINISTRATOR

0060 4040404040404040 4040404040404040 @@@@@@@@@@@@@@@@

0070 E2E3D6D9C5E26DC4 F0C4C2F240404040 ......m.....@@@@ STORES_D0DB2

0080 4040404040404040 40F0001814041403 @@@@@@@@@....... 0......

0090 000A2407000A1474 0005240F00081440 ..$....t..$....@ ...............

00A0 0009000B1147D8C4 C2F261D5E3000A11 .....G....a..... ......QDB2/NT...

00B0 6DC4E4C2C9E3D600 0C115AE2D8D3F0F9 m.........Z..... _DUBITO...]SQL09

00C0 F0F7F0 ... 070

Chapter 3. Working with the ODBC driver

119

7884ch03.fm

Draft Document for Review August 23, 2010 10:53 am

120

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch04.fm

4

Chapter 4.

Working with ESQL/C

This chapter discusses about ESQL/C, an SQL Application Programming

Interface (API) that enables you to embed Structured Query Language (SQL) statements directly into a C program. ESQL/C is bundled with the Informix Client

Software Development Kit (Client SDK). The ESQL/C preprocessor,

esql

, converts each SQL statement and all IBM Informix-specific code to C-language source code and invokes the C compiler to compile it. The advantage of using

ESQL/C is that it supports all the data types as well as extended data types of

Informix and is optimized for an IBM Informix database. If you are going to use only Informix as your database server then this might be your best choice.

We discuss the basic elements of an Informix ESQL/C application and show how to perform database operations within an ESQL/C program. We end the chapter by looking at various methods in handling exceptions and troubleshooting.

© Copyright IBM Corp. 2010. All rights reserved.

121

7884ch04.fm

Draft Document for Review August 23, 2010 10:53 am

4.1 Informix ESQL/C

Informix ESQL/C consists of the following software components:

򐂰 The Informix ESQL/C libraries of C functions, which provide access to the database server.

򐂰 The Informix ESQL/C header files, which provide definitions for the data structures, constants, and macros useful to the Informix ESQL/C program.

򐂰 The

esql

command, which processes the Informix ESQL/C source code to create a C source file that it passes to the C compiler.

򐂰 The

finderr

utility on the UNIX system and the Informix Error Messages

Windows-based Informix error messages utility that enable you to obtain information about IBM Informix-specific error messages.

On Windows platforms, Informix provide the following additional utilities:

򐂰 The

Setnet32

utility is a Windows-based utility that enables you to set configuration information.

򐂰 The

ILOGIN

utility is a demonstration program that displays a dialog box with fields for the connection parameters, for testing a connection to the database server (uses the stores7 database).

Figure 4-1 gives an overview of the relationship between ESQL/C and the native

C and how the transfer of control happens. Once you have created an Informix

ESQL/C program file, you run the esql command on that file. By default, the

Informix ESQL/C preprocessor runs first and translates the embedded SQL statements in the program into Informix ESQL/C function calls that communicate with the database server. The Informix ESQL/C preprocessor produces a C source file and calls the C compiler. The C compiler then compiles your source file and links any other C source file, object file, or library file the same way as any other C program. If esql does not encounter errors in one of these steps, it generates an executable file. You can run the compiled Informix ESQL/C program as you would run any C program. When the program runs, it calls the

Informix ESQL/C library procedures; the library procedures set up communications with the database server to carry out the SQL operations.

Figure 4-1 Relationship between Informix ESQL/C and C

122

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

4.2 Setup and configuration

7884ch04.fm

Informix ESQL/C is installed, by default, as a part of the Client SDK package.

The release notes of Client SDK contains the information about which versions of the IBM Informix database server are supported. Make sure that you install the

Client SDK that is supported by the database you are going to work with.

Windows configuration

On a Windows machine, the default Client SDK installation directory is

C:\Program Files\IBM\Informix\Client-SDK

. Make sure that the INFORMIXDIR environment variable is pointing to the directory where the product was installed.The PATH environment variable should contain the following directories:

򐂰 The path to the bin directory under the installation directory, that is, the PATH variable should have $INFORMIXDIR/bin .

򐂰

The path at where native C compiler is located. (IBM Informix Client products are certified with the Microsoft Visual C++ 2005 SP1.

UNIX configuration

On UNIX platforms, the default installation directory for Informix Client SDK is

/opt/IBM/informix . The INFORMIXDIR environment variable should point to the directory where the product was installed. Add the following directories to the

PATH environment variable:

򐂰

The bin

directory under the installation directory,

$INFORMIXDIR/bin.

򐂰

The path to the native C compiler.

The sqlhosts configuration file contains the information required to connect to an

IBM Informix database server. You must set this file to include an entry of your

Informix database server name, ESQL/C required protocol, host name, and port number. By default the sqlhosts file is under the

$INFORMIXDIR/etc/ directory.

You can use the

INFORMIXSQLHOSTS

environment variable to point to a different location.

Example 4-1 shows a simple sqlhosts file.

Example 4-1 sqlhosts file

#server protocol hostname service/port demo_on onsoctcp kodiak 9088

For more information about the sqlhosts file, refer to the Client/Server

Communications manual at:

Chapter 4. Working with ESQL/C

123

7884ch04.fm

Draft Document for Review August 23, 2010 10:53 am http://publib.boulder.ibm.com/infocenter/idshelp/v115/topic/com.ibm.admin.doc/i ds_admin_0158.htm

4.3 Developing an ESQL/C application

In this section, we describe about connecting to database, performing basic database operations such as delete, insert, and updates using ESQL/C. We also look into the handling of extended data types by ESQL/C.

We use the sample instance and database that Informix server provides to demonstrate ESQL/C application development. The sample instance, demo_on , is created when the Informix server is installed. On windows the sample instance is ol_svr_custom . You can create a sample database, stores_demo , under the demo_on instance and populate it with tables and data by running the utility dbaccessdemo residing in $INFORMIXDIR/bin/.

4.3.1 Creating an ESQL/C application

The steps involved in building an Informix ESQL/C application are:

1. Develop a C program with the embedded Informix SQL statements and name it with .ec or .ecp extension. The SQL statement are qualified with EXEC SQL keyword or the $ symbol, for example:

EXEC SQL include sqlca;

EXEC SQL SELECT fname into :c1 FROM customer WHERE customer_num=:i1

$SET ISOLATION DIRTY READ;

2. Preprocess the Informix ESQL/C source file with the

esql

command. The

esql

command also invoke the C compiler to compile the program into object code.

As necessary, correct errors reported by the preprocessor and the compiler and repeat step 2.

3. Link the object code into one or more executable files using the

esql

command. The executable files have .exe extension.

4. Run the application.

You run the compiled Informix ESQL/C program as you would any C program.

When the program runs, it calls the Informix ESQL/C library procedures; the library procedures set up communications with the database server to carry out the SQL operations.

Example 4-2 on page 125 shows a simple program,

customer.ec

, that connects to the database and retrieves some data. All the SQL related statements are embedded in the C program with EXEC SQL keyword.

124

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

Example 4-2 Simple ESQL/C program

#include <stdio.h>

EXEC SQL include sqlca;

EXEC SQL include sqltypes; int main()

{

EXEC SQL BEGIN DECLARE SECTION; int i1=101; char c1[50]; char c2[50];

EXEC SQL END DECLARE SECTION; int i2;

EXEC SQL connect to 'stores_demo';

EXEC SQL select fname,lname into :c1, :c2 from customer where customer_num=:i1

; if (SQLCODE == 100)

{

printf("SQLCODE=%d\n",SQLCODE);

printf("Data not found\n");

} else

{

printf("SQLCODE=%d\n",SQLCODE);

printf("Data found \n");

printf("Last Name \t%s\n",c1);

printf("First Name \t%s\n",c2);

}

}

7884ch04.fm

Compiling ESQL/C programs

The

esql

command translates Informix ESQL/C code to C code and then calls the

C compiler to compile and link the C code.

The C compiler takes the following actions:

򐂰

Compiles the C language statements to object code.

򐂰 Links to Informix ESQL/C libraries as well as any other files or libraries you specify.

򐂰

Creates an executable file.

The general syntax for an

esql

to compile looks like below: esql <options> <source.ec> <options> <outfile>

Chapter 4. Working with ESQL/C

125

7884ch04.fm

Draft Document for Review August 23, 2010 10:53 am

By default,

esql

creates an executable by name a.out in the current directory. You can explicitly specify the name of the executable file with the -o option. For

example, the following command compile the customer.ec shown in Example 4-2 on page 125 and produce the executable file

customer.exe

. esql -o customer.ec customer.exe

If esql is running on a Windows operating system, the name of the target file defaults to the name of the first Informix ESQL/C source file on the

esql

command line. The extension is changed to either .exe or .dll depending on the type of target being generated. you can use a compiler other than the native C compiler by setting the

INFORMIXC environment variable. Table 4-1 lists the native C compilers on

various platforms.

Table 4-1 Native C compiler

Platforms Native compiler

Solaris

HP

CC aC++

Windows

AIX

Open Source

VC++ / VS2008/ VS2005 xlc gcc/g++

If you want to pass C compiler options that have the same names as Informix

ESQL/C processor options, precede them with the -cc option. For example, the following

esql

command passes the -od and -g options to the C compiler but uses the -db2 option itself: esql -cc -od -g demo1.ec -db2

Shared libraries

IBM Informix products use the Informix general libraries for interactions between the client SQL application programming interface (API) products (IBM Informix

ESQL/C and IBM Informix ESQL/COBOL) and the database server. You can choose between the following types of Informix general libraries to link with your

Informix ESQL/C application:

򐂰 Static Informix general libraries

To link a static library, the linker copies the library functions to the executable file of your Informix ESQL/C program. The static Informix general libraries

126

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch04.fm

allow an Informix ESQL/C program on computers that do not support shared memory to access the Informix general library functions.

To link static libraries use option

-static

, for example: esql -static file.ec -o file.exe

򐂰 Shared Informix general libraries

To link a shared library, the linker copies information about the location of the library to the executable file of your Informix ESQL/C program. The shared

Informix libraries allow several applications to share a single copy of these libraries, which the operating system loads, just once, into shared memory.

򐂰 Thread-safe versions of static and shared Informix general libraries

The thread-safe versions of Informix general libraries allow an Informix

ESQL/C application that has several threads to call these library functions simultaneously. The thread-safe versions of Informix libraries are available as both static libraries and shared libraries.

There are some platform specific considerations when you link shared Informix general libraries to an ESQL/C module. The environment variable that specifies

the search path at run time is different for platform, see Table 4-2.

Table 4-2 Environment variable for shared libraries.

Platform Environment variable

AIX LIBPATH

Solaris

HP-UX

Mac OS X

Linux

Windows

LD_LIBRARY_PATH

SHLIB_PATH

DYLD_LIBRARY_PATH

LD_LIBRARY_PATH

LIB

Set $INFORMIXDIR/lib and any of its subdirectories to specify the shared-library path. For example, on Linux, set the LD_LIBRARY_PATH environment variable as follows:

򐂰

Bourne shell:

LD_LIBRARY_PATH=$INFORMIXDIR/lib:$LD_LIBRARY_PATH export LD_LIBRARY_PATH

򐂰

C shell: setenv LD_LIBRARY_PATH $INFORMIXDIR/lib:$LD_LIBRARY_PATH

Chapter 4. Working with ESQL/C

127

7884ch04.fm

Draft Document for Review August 23, 2010 10:53 am

On Windows use the following command: set LIB = %INFORMIXDIR%\lib\;%LIB%

To link shared Informix general libraries with an Informix ESQL/C module, you do not need to specify a command-line option. Informix ESQL/C links shared libraries by default. The following command compiles the file.ec source file with shared Informix libraries: esql myfile.ec -o myfile.exe

Choosing between shared and static library versions

Shared libraries are most useful in multiuser environments where only one copy of the library is required for all applications. Shared libraries bring the following benefits to your Informix ESQL/C application:

򐂰

Shared libraries reduce the sizes of executable files because these library functions are linked dynamically, on an as-needed basis.

򐂰 At runtime, a single copy of a shared library can be linked to several programs, which results in less memory use.

򐂰

The effects of shared libraries in an Informix ESQL/C executable are transparent to the end user.

Although shared libraries save both disk and memory space, when an Informix

ESQL/C application uses them, it must perform the following overhead tasks:

򐂰 Dynamically load the shared library into memory for the first time

򐂰 Perform link-editing operations

򐂰 Execute library position-independent code

These overhead tasks can incur runtime penalties and are not necessary when you use static libraries.

4.3.2 Performing database operations

In this section, we discuss how to perform basic database operations in an

ESQL/C application:

򐂰

Database connections

򐂰

Simple SQL statements (SELECT, INSERT, UPDATE, and DELETE)

򐂰

Static and dynamic SQL

򐂰

Calling SQL routines (stored procedures)

򐂰

Using transactions

In the program we try to make use of most commonly used data types, for other data types, refer to

128

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch04.fm

http://publib.boulder.ibm.com/infocenter/idshelp/v115/index.jsp?topic=/com.ibm.

esqlc.doc/sii-03-sourceforchaptitle.htm

Database connections

When an Informix ESQL/C application begins execution, it has no connections to any database server. For SQL statements to run, however, such a connection must exist. To establish a connection to a database server, the Informix ESQL/C program must take the following actions:

򐂰 Use an SQL statement to establish a connection to the database server.

򐂰

Specify, in the SQL statement, the name of the database server to which to connect.

The client application connects to the default database server when the application does not explicitly specify a database server for the connection. You must set the

INFORMIXSERVER

environment variable even if the application does not establish a connection to the default database server.

if user name and password are not explicitly specified using the

InetLogin structure or the USER clause, the default user ID is used to attempt the connection. The default user ID is the login name of the user running the application.

The Example 4-3 is a statement that connects to the database

stores_demo under the instance demo_on

.

Example 4-3 Database connection statement

EXEC SQL connect to 'stores_demo@demo_on';

EXEC SQL connect to stores_demo user :username using :password;

For more information on database connections in ESQL/C, refer to http://publib.boulder.ibm.com/infocenter/idshelp/v115/topic/com.ibm.esqlc.doc/s ii12164286.htm#sii12164286

Simple SQL statements

There are several way to execute SQL statement from a ESQL/C application.

The application must choose an appropriate method based on the nature of the

SQL statement.

򐂰 SQL statements which do not return a result set of data such as INSERT,

DELETE, UPDATE or Data Definition Language (DDL) can be executed using the EXEC SQL command (same as the $ prefix) or the EXEC SQL execute immediate statement. Both methods produce the same C code.

EXEC SQL execute immediate :cmdstring;

Chapter 4. Working with ESQL/C

129

7884ch04.fm

Draft Document for Review August 23, 2010 10:53 am

$CREATE TABLE my_customer (fname char(20));

If the SQL statement is going to be executed more than one time during the life of the application, it can be prepared with the EXEC SQL PREPARE command and then execute it when required using EXEC SQL EXECUTE.

EXEC SQL prepare d_id from :stmt_buf;

EXEC SQL execute d_id;

򐂰 SQL statements returning one row can be executed using the EXEC SQL

EXECUTE INTO command, normally referred as singleton statements.

EXEC SQL SELECT specs into :mspecs FROM my_customer WHERE customer_num=2;

򐂰

SQL statements returning more than one row should be executed using a

Select Cursor.

EXEC SQL declare cursor1 cursor for SELECT fname into :var1 from customer;

EXEC SQL open cursor1;

EXEC SQL fetch cursor1;

In the Example 4-4, we demonstrate how to execute an SQL statement using

some of the methods previously described.

Example 4-4 Simple SQL statements (INSERT, UPDATE and DELETE)

#include <stdio.h>

#include <string.h>

EXEC SQL include sqlca;

EXEC SQL include sqltypes; int main()

{

EXEC SQL BEGIN DECLARE SECTION; char cmdstring[4096]; string *fname[5] = { "Ludwig","Carole", "Philip", "Anthony", "Raymond" }; string *lname[5] = { "Pauli", "Sadler", "Currie", "Higgins", "Vector" }; string *company[5] = {"All Sports Supplies","Sports Spot", "Phil's Sports", "Play

Ball!", "Los Altos Sports" }; char pref='t'; char *specs[5] = { "This is just any string ", "This is just another string ",

"This is the third string", "This is one more string", "This is the last string"}; lvarchar mspecs[250]; char *order_date[5] = {"08/01/77","08/02/77","08/03/77","08/04/77","08/05/77"}; float ship_charge[5] = {10000.59,590000.32,345577.12,987098.32,876893.22}; char *ship_duration[5] = {"10:10:10","11:11:11","22:22:22","33:33:33","44:44:44"};

EXEC SQL END DECLARE SECTION;

$WHENEVER ERROR STOP; int i;

EXEC SQL connect to 'stores_demo';

$ CREATE TABLE my_customer (

130

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch04.fm

customer_num bigserial, fname char(15), lname char(15), company char(30), preferred boolean, specs lvarchar

);

$ CREATE TABLE my_orders ( order_num bigserial, order_date date , customer_num bigint, ship_charge money(10,2), ship_duration INTERVAL hour to second

); for (i = 0; i < 5 ; i++)

{

$INSERT INTO my_customer VALUES (

0,

:fname[i],

:lname[i],

:company[i],

:pref,

:specs[i]

);

} for (i = 0; i < 5 ; i++)

{

sprintf(cmdstring, "INSERT INTO my_orders VALUES (10000001,'%s',%d,%f,'%s' );", order_date[i], i,ship_charge[i], ship_duration[i]);

EXEC SQL execute immediate :cmdstring;

} sprintf(cmdstring, "UPDATE my_customer SET specs='This is a new spec' WHERE customer_num

= 2");

EXEC SQL execute immediate :cmdstring; if (SQLCODE != 0)

printf("SQLCODE=%d\n",SQLCODE); sprintf(cmdstring, "DELETE FROM my_customer where customer_num=3");

EXEC SQL execute immediate :cmdstring; if (SQLCODE != 0)

printf("SQLCODE=%d\n",SQLCODE);

EXEC SQL SELECT specs into :mspecs FROM my_customer WHERE customer_num=2;

if (SQLCODE != 0)

printf("SQLCODE=%d\n",SQLCODE); else

printf("The spec for the customer is :%s\n", mspecs);

}

Chapter 4. Working with ESQL/C

131

7884ch04.fm

Draft Document for Review August 23, 2010 10:53 am

For additional information regarding the execution of SQL statements refer to the

IBM Informix ESQL/C Programmer's Manual at http://publib.boulder.ibm.com/infocenter/idshelp/v10/index.jsp?topic=/c om.ibm.esqlc.doc/esqlc298.htm

Static and dynamic SQL

The SQL statements contained in Example 4-4 on page 130 are all static SQL

statements. A static SQL statement is one for which all the information is known at compile time. However, in some applications the programmer does not know the contents, or possibly even the types, of SQL statements that the program needs to execute. For example, a program may prompt the user to enter a select statement, so that the programmer has no idea what columns will be accessed when the program is run. Such applications require dynamic SQL. Dynamic SQL allows an IBM Informix ESQL/C program to build an SQL statement at runtime, so that the contents of the statement can be determined by user input.

Example 4-5 shows how to use dynamic SQL in a program.

Example 4-5 Dynamic SQL statements

#include <stdio.h>

EXEC SQL include sqlca;

EXEC SQL include sqltypes; int main()

{

EXEC SQL BEGIN DECLARE SECTION; int i1; char cmdstring[2048]; char c1[50]; char c2[50];

EXEC SQL END DECLARE SECTION; int i2;

EXEC SQL connect to 'stores_demo'; printf("Enter the customer number [101-128] to see the names:"); scanf("%d", &i1);

sprintf (cmdstring, "SELECT fname,lname from customer where customer_num = ?");

EXEC SQL prepare ex_id from :cmdstring;

EXEC SQL execute ex_id into :c1,:c2 using :i1;

; if (SQLCODE == 100)

{ printf("SQLCODE=%d\n",SQLCODE); printf("Data not found\n");

} else

{

132

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

}

} printf("SQLCODE=%d\n",SQLCODE); printf("Data found \n"); printf("Last Name \t%s\n",c1); printf("First Name \t%s\n",c2);

OUTPUT:

Enter the customer number [101-128] to see the names:102

SQLCODE=0

Data found

Last Name Carole

First Name Sadle

7884ch04.fm

The SELECT statement shown in Example 4-5 on page 132 is called a singleton

SELECT as it returns only 1 row. For SELECT statements returning multiple rows

you have to use a SELECT cursor. Example 4-6 below shows how to use cursor

for the SELECT statements returning multiple rows.

Example 4-6 Using cursor for SELECT statements returning multiple rows

#include <stdio.h>

EXEC SQL include sqlca;

EXEC SQL include sqltypes; int main()

{

EXEC SQL BEGIN DECLARE SECTION; int i; char cmdstring[2048]; char c1[50]; char c2[50];

EXEC SQL END DECLARE SECTION;

EXEC SQL connect to 'stores_demo'; printf("Enter customer number [103 - 128] :"); scanf("%d", &i); sprintf (cmdstring, "SELECT fname,lname from customer where customer_num < ?;");

EXEC SQL prepare ex_id from :cmdstring;

EXEC SQL declare ex_cursor cursor for ex_id;

EXEC SQL open ex_cursor using :i;

/* Print out what DESCRIBE returns*/ for (;;)

{

EXEC SQL fetch ex_cursor into :c1,:c2;

if (strncmp(SQLSTATE, "00", 2) != 0) break; if (SQLCODE == 100)

{

Chapter 4. Working with ESQL/C

133

7884ch04.fm

Draft Document for Review August 23, 2010 10:53 am printf("SQLCODE=%d\n",SQLCODE); printf("Data not found\n");

} else

}

}

{ printf("%s\t%s\n",c1,c2);

OUTPUT:

Enter customer number [103 - 128] : 108

Ludwig Pauli

Carole Sadler

Philip Currie

Anthony Higgins

Raymond Vector

George Watson

Charles Ream

For more details on dynamic SQL and the cursors, refer to http://publib.boulder.ibm.com/infocenter/idshelp/v115/topic/com.ibm.esqlc.doc/s ii-sc3dysq-35492.htm#sii-sc3dysq-35492

Calling SQL routines

In this section we demonstrate how to call a SQL routine from an ESQL/C application. You can accomplish a wide range of objectives with SQL routines, including improving database performance, simplifying writing applications, and limiting or monitoring access to data. Because an SQL routine is stored in an executable format, you can use it for repeated tasks to improve performance.

When you invoke an SPL routine, rather than straight SQL code, you can bypass repeated parsing, validity checking, and query optimization.

Example 4-7 shows a simple program containing a SPL routine that receives

arguments price, percent tax, and returns price after adding the tax.

Example 4-7 Calling SQL routines

#include <stdio.h>

$ INCLUDE sqlca.h;

$ INCLUDE sqltypes.h; int main()

{

EXEC SQL BEGIN DECLARE SECTION; char cmdstring[2048]; float n1,n2; int i=2;

EXEC SQL END DECLARE SECTION;

EXEC SQL whenever sqlerror stop;

134

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch04.fm

EXEC SQL CONNECT TO 'stores_demo';

sprintf(cmdstring, "CREATE FUNCTION inc_price(n1 money(8,2), n2 int) RETURNING money(8,2) RETURN(n1 + (n1 *n2)/ 100); END FUNCTION;");

EXEC SQL execute immediate :cmdstring;

sprintf(cmdstring, "SELECT FIRST 5 total_price, inc_price(total_price,?) from items ;");

EXEC SQL prepare ex_id from :cmdstring;

EXEC SQL declare ex_cursor cursor for ex_id;

EXEC SQL open ex_cursor using :i;

/* Print out what DESCRIBE returns*/ for (;;)

{

EXEC SQL fetch ex_cursor into :n1,:n2; if (strncmp(SQLSTATE, "00", 2) != 0) break; if (SQLCODE == 100)

{ printf("SQLCODE=%d\n",SQLCODE); printf("Data not found\n");

} else

}

}

{ printf("%f\t%f\n",n1,n2);

}

OUTPUT:

250.000000 255.000000

960.000000 979.200012

240.000000 244.800003

20.000000 20.400000

840.000000 856.799988

Using transactions

A transaction is a collection of SQL statements that are treated as a single unit of work. All the SQL statements that you issue in an ANSI-compliant database are automatically contained in transactions. With a database that is not ANSI compliant, transaction processing is an option.

In a database that is not ANSI compliant, a transaction is enclosed by a BEGIN

WORK statement and a COMMIT WORK or a ROLLBACK WORK statement. In an

ANSI-compliant database, the BEGIN WORK statement is unnecessary, because all statements are automatically contained in a transaction. You only need to indicate the end of a transaction with a COMMIT WORK or ROLLBACK WORK statement.

Example 4-8 on page 136 shows an example using transactions.

Chapter 4. Working with ESQL/C

135

7884ch04.fm

Draft Document for Review August 23, 2010 10:53 am

Example 4-8

Using transactions

#include <stdio.h>

$include "sqlca.h";

$include "sqlhdr.h";

$include "sqltypes.h"; main()

{

EXEC SQL BEGIN DECLARE SECTION; int n1; char c1[20];

EXEC SQL END DECLARE SECTION;

EXEC SQL whenever sqlerror stop;

EXEC SQL CREATE DATABASE itso WITH LOG;

EXEC SQL CREATE TABLE t1(num serial, name char(20));

EXEC SQL BEGIN WORK;

EXEC SQL INSERT INTO t1 VALUES (0,'name1');

EXEC SQL INSERT INTO t1 VALUES (0,'name2');

EXEC SQL INSERT INTO t1 VALUES (0,'name3');

EXEC SQL ROLLBACK;

EXEC SQL BEGIN WORK;

EXEC SQL INSERT INTO t1 VALUES (0,'name4');

EXEC SQL INSERT INTO t1 VALUES (0,'name5');

EXEC SQL COMMIT;

EXEC SQL declare ifx_cursor cursor for select num,name into :n1,:c1 from t1;

EXEC SQL open ifx_cursor ; for (;;)

{

EXEC SQL fetch ifx_cursor; if (sqlca.sqlcode!=0) break; printf("%d\t%s\n",n1,c1);

}

EXEC SQL close ifx_cursor;

EXEC SQL free ifx_cursor;

}

OUTPUT:

4 name4

5 name5

136

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch04.fm

4.3.3 Data types mapping

This section contains information about the correspondence data types between

SQL and C and how to handle data types in an IBM Informix ESQL/C program.

When a query is executed by the application, the data returned by the Informix server may be in a different format than what the application uses. The ESQL/C converts the data passed between the application and the database server. This process is transparent to the application. The only requirement for the application is to specify the correct data types in ESQL/C.

Table 4-3 lists a few ESQL/C data type mapping as examples.

Table 4-3 Informix data type mapping

Informix SQL ESQL/C

BOOLEAN

BYTE boolean loc_t

LVARCHAR

NCHAR(n)

NVARCHAR(m)

SERIAL8 lvarchar fixchar [n] or string [n+1] varchar[m+1] or string [m+1] int8 or ifx_int8_t

TEXT

BLOB

CLOB

LIST(e)

MULTISET(e)

Opaque data type

ROW(...)

SET(e) loc_t ifx_lo_t ifx_lo_t collection collection lvarchar, fixed binary, or var binary row collection

For a complete list of all the Informix SQL to ESQL/C data type mapping refer to the IBM Informix ESQL/C Programmer’s Manual at http://publib.boulder.ibm.com/infocenter/idshelp/v115/index.jsp?topic=/com.ibm.

esqlc.doc/sii03147680.htm

Chapter 4. Working with ESQL/C

137

7884ch04.fm

Draft Document for Review August 23, 2010 10:53 am

4.3.4 Handling special data types

This section describe how to work with Informix specific data types. We discuss the following data types:

򐂰

Smart Large Objects (BLOB and CLOB)

򐂰

Collection data types (LIST, MULTISET, and SET)

򐂰

ROW data type

To store large objects inside database, you can use data types such as TEXT,

BYTE, BLOB, and CLOBS. Informix supports simple large objects and smart large objects. Simple large objects are the TEXT and BYTE types which are primarily there for compatibility with earlier versions of Informix applications. The smart large objects are the BLOB and CLOBs. When you write new applications that need to access large objects, use smart large objects to hold character

(CLOB) and binary (BLOB) data. Table 4-4 summarizes the advantages that

smart large objects present over simple large objects.

Table 4-4 Advantages of smart blobs over simple blobs

Large-Object feature Simple large objects Smart large objects

Maximum size of data 2 gigabytes 4 terabytes

Data accessibility Random access to data

Reading the large object

Writing the large object

Data logging

No random access to data

The database server reads a simple large object on an all or nothing basis.

The database server updates a simple large object on an all or nothing basis.

Data logging is always on.

Library functions provide access that is similar to accessing an operating-system file.

You can access specified portions of the smart large object.

The database server can rewrite only a portion of a smart large object.

Data logging can be turned on and off

Example using CLOB and BLOBs

Informix ESQL/C supports the SQL data types CLOB and BLOB with the ifx_lo_t data type. Because of the potentially huge size of smart-large-object data, the

Informix ESQL/C program does not store the data directly in a host variable.

Instead, the client application accesses the data as a file-like structure. To use

138

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch04.fm

smart-large-object variables in an Informix ESQL/C program, take the following actions:

򐂰

Declare a host variable with the ifx_lo_t

data type.

򐂰 Access the smart large object with a combination of the following three data structures:

– The LO-specification structure, ifx_lo_create_spec_t

– The LO-pointer structure, ifx_lo_t

– An integer LO file descriptor

Smart Large Objects are logically stored in a table column but physically stored in a specific type of dbspaces called Smart Blob Space (SBS). you have to create the Smart Blob Space in server before you can run this example. For the details about creating the BLOB space, refer to http://publib.boulder.ibm.com/infocenter/idshelp/v115/topic/com.ibm.admin.doc/i ds_admin_0491.htm

Example 4-9 illustrates how to work with BLOB and CLOB data types using

ESQL/C functions. The function filetoclob and filetoblob are used to enter the CLOB and BLOB data respectively. If your files are in the client machine then mention client as the second argument to the filetoblob function. If they are present at the server machine then mention server as the second argument.

The output will be a part of the file which you insert as a BLOB. In this example we used a README.txt file.

Example 4-9

ifx_lo_sample

.ec

#include <stdio.h>

$include "sqlca.h";

$include "sqlhdr.h";

$include "sqltypes.h"; main()

{ int error, ic1, oflags, cflags, extsz, imsize, isize, iebytes; time_t time; struct tm *date_time; char col_name[300]="test", sbspc[129];

EXEC SQL BEGIN DECLARE SECTION;

fixed binary 'blob' ifx_lo_t c2;

char srvr_name[256];

ifx_lo_create_spec_t *cspec;

ifx_lo_stat_t *stats;

ifx_int8_t size, c1, estbytes, maxsize;

int lofd;

long atime, ctime, mtime, refcnt;

EXEC SQL END DECLARE SECTION;

Chapter 4. Working with ESQL/C

139

7884ch04.fm

Draft Document for Review August 23, 2010 10:53 am

EXEC SQL whenever sqlerror stop;

EXEC SQL connect to 'stores_demo';

EXEC SQL create table t2 (c1 int, c2 blob);

EXEC SQL insert into t2 values (1,filetoblob ('/tmp/README.txt', 'server','t2','c2'));

EXEC SQL declare ifxcursor cursor for select c1,c2 into :c1,:c2 from t2 for update;

EXEC SQL open ifxcursor; for (;;)

{

EXEC SQL fetch ifxcursor;

if (sqlca.sqlcode!=0)

break;

lofd = ifx_lo_open(&c2, LO_RDWR, &error);

ifx_lo_read(lofd, srvr_name, 256, &error);

printf("Value: %s\n",srvr_name);

ifx_lo_write(lofd,col_name,5,&error);

ifx_lo_close(lofd);

}

EXEC SQL close ifxcursor;

EXEC SQL free ifxcursor; ifx_lo_close(lofd);

}

More details on the ESQL/C functions to create, alter and access BLOB and

CLOB data are available at http://publib.boulder.ibm.com/infocenter/idshelp/v115/index.jsp?topic=/com.ibm.

esqlc.doc/sii-03-sourceforchaptitle.htm

Example using collection data types

Collection data types (SET, LIST, and MULTISET) enable you to store and manipulate collections of data within a single row of a table. A collection data type has two components:

򐂰

A type constructor, which determines whether the collection type is a SET,

MULTISET, or LIST.

򐂰 An element type, which specifies the type of data that the collection can contain.

The elements of a collection can be of any data type. The elements of a collection are the values that the collection contains. In a collection that contains the values {'blue', 'green', 'yellow', and 'red'} , “blue” represents a single element in the collection. Every element in a collection must be of the same type.

140

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch04.fm

For example, a collection whose element type is INTEGER can contain only integer values.

Informix ESQL/C uses collection variables to access collection data types. A collection variable stores the elements from a collection column as if they were rows in a table. This virtual table can be used as part of a cursor declaration to fetch the individual elements of the collection column.

Example 4-10 shows the ESQL/C commands used to retrieve an element from a

collection column. The parents column is a collection of INT values. The collection is stored into the host variable hv1 , and used to open a cursor using the variable as a virtual table, table(:hv1) .

Example 4-10 collection_sample

EXEC SQL client collection hv1;

EXEC SQL int parent_id;

EXEC SQL select parents into :hv1 from grade12_parents where class_id = 1;

EXEC SQL declare cur1 cursor for select id from table(:hv1);

EXEC SQL open cur1;

EXEC SQL fetch cur1 into :parent_id;

The INT elements of the collection are retrieved from the host variable using the

EXEC SQL fetch cur1 command.

Example 4-11 shows a complete ESQL/C program illustrating how to insert and

select into tables containing the collection data types.

Example 4-11 Example using collection types

#include <stdio.h> static void print_collection( const char *tag,

EXEC SQL BEGIN DECLARE SECTION;

parameter client collection c

EXEC SQL END DECLARE SECTION;

)

{

EXEC SQL BEGIN DECLARE SECTION;

int4 value;

EXEC SQL END DECLARE SECTION;

mint item = 0;

EXEC SQL WHENEVER ERROR STOP;

printf("COLLECTION: %s\n", tag);

EXEC SQL DECLARE c_collection CURSOR FOR

SELECT * FROM TABLE(:c);

EXEC SQL OPEN c_collection;

while (sqlca.sqlcode == 0)

Chapter 4. Working with ESQL/C

141

7884ch04.fm

Draft Document for Review August 23, 2010 10:53 am

{

EXEC SQL FETCH c_collection INTO :value;

if (sqlca.sqlcode != 0) break;

printf("\tItem %d, value = %d\n", ++item, value);

}

EXEC SQL CLOSE c_collection;

EXEC SQL FREE c_collection;

} mint main(int argc, char **argv)

{

EXEC SQL BEGIN DECLARE SECTION;

client collection list (integer not null) lc1;

client collection set (integer not null) sc1;

client collection multiset (integer not null) mc1;

char *dbase = "stores_demo";

mint seq;

char *stmt1 =

"INSERT INTO t_collections VALUES(0, "

"'LIST{-1,0,-2,3,0,0,32767,249}', 'SET{-1,0,-2,3}', "

"'MULTISET{-1,0,0,-2,3,0}') ";

EXEC SQL END DECLARE SECTION; if (argc > 1)

dbase = argv[1];

EXEC SQL WHENEVER ERROR STOP;

printf("Connect to %s\n", dbase);

EXEC SQL connect to :dbase;

EXEC SQL CREATE TEMP TABLE t_collections

(

seq serial not null,

l1 list (integer not null),

s1 set (integer not null),

m1 multiset(integer not null)

);

EXEC SQL EXECUTE IMMEDIATE :stmt1;

EXEC SQL ALLOCATE COLLECTION :lc1;

EXEC SQL ALLOCATE COLLECTION :mc1;

EXEC SQL ALLOCATE COLLECTION :sc1;

EXEC SQL DECLARE c_collect CURSOR FOR

SELECT seq, l1, s1, m1 FROM t_collections;

EXEC SQL OPEN c_collect;

EXEC SQL FETCH c_collect INTO :seq, :lc1, :sc1, :mc1;

EXEC SQL CLOSE c_collect;

EXEC SQL FREE c_collect;

print_collection("list/integer", lc1);

print_collection("set/integer", sc1);

print_collection("multiset/integer", mc1);

142

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

EXEC SQL DEALLOCATE COLLECTION :lc1;

EXEC SQL DEALLOCATE COLLECTION :mc1;

EXEC SQL DEALLOCATE COLLECTION :sc1;

puts("OK");

return 0;

}

Example 4-12 shows the output of Example 4-11 on page 141.

Example 4-12 Collection example output

Connect to stores_demo

COLLECTION: list/integer

Item 1, value = -1

Item 2, value = 0

Item 3, value = -2

Item 4, value = 3

Item 5, value = 0

Item 6, value = 0

Item 7, value = 32767

Item 8, value = 249

COLLECTION: set/integer

Item 1, value = -1

Item 2, value = 0

Item 3, value = -2

Item 4, value = 3

COLLECTION: multiset/integer

Item 1, value = -1

Item 2, value = 0

Item 3, value = 0

Item 4, value = -2

Item 5, value = 3

Item 6, value = 0

OK

7884ch04.fm

4.3.5 Exception handling

The applications which you write require that the database server processes your

SQL statements successfully as you intend. If a query fails and you do not know it, you might display meaningless data to the user.

To handle such errors, an Informix ESQL/C program must check that every SQL statement executes as you intend.

This section discusses the two widely used exception handling in Informix applications development:

Chapter 4. Working with ESQL/C

143

7884ch04.fm

Draft Document for Review August 23, 2010 10:53 am

򐂰 Using SQLSTATE variable and the GET DIAGNOSTICS statement to check for runtime errors and warnings that your Informix ESQL/C program might generate.

򐂰

Using SQLCODE variable and the SQL Communications Area (sqlca) to check for runtime errors and warnings that your Informix ESQL/C program might generate.

For a complete information on ESQL/C Exception handling, refer to http://publib.boulder.ibm.com/infocenter/idshelp/v115/index.jsp?topic=/com.ibm.

esqlc.doc/sii-11-40709.htm

Exception handling with SQLSTATE

After the database server executes an SQL statement, it sets SQLSTATE with a value that indicates the success or failure of the statement. From this value, your program can determine if it needs to perform further diagnostics. If SQLSTATE indicates a problem, you can use the

GET DIAGNOSTICS

statement to obtain more information.

Example 4-13 shows us how to handle the exceptions using SQLSTATE and the

GET DIAGNOSTICS

statement. The

GET DIAGNOSTICS

statement returns information that is held in the fields of the diagnostics area. The diagnostics area is an internal structure that the database server updates after it executes an SQL statement. Each application has one diagnostics area.

Example 4-13 Error handling in ESQL/C

#include <stdio.h>

#include <stdio.h> void error_chk()

{

EXEC SQL BEGIN DECLARE SECTION;

mint excp_count;

char overflow[2];

mint excp_num=1;

char message[255];

mint mlen;

char sql_state_code[6];

mint i=1;

EXEC SQL END DECLARE SECTION;

printf("SQLSTATE: %s\n",SQLSTATE);

printf("SQLCODE: %d\n", SQLCODE);

printf("\n");

EXEC SQL get diagnostics :excp_count = NUMBER, :overflow = MORE;

EXEC SQL get diagnostics exception :i :sql_state_code = RETURNED_SQLSTATE, :message =

MESSAGE_TEXT, :mlen = MESSAGE_LENGTH;

printf("EXCEPTION %d: SQLSTATE=%s\n", i, sql_state_code);

144

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch04.fm

message[mlen-1] = '\0';

printf("MESSAGE TEXT: %s\n", message);

} mint main(int argc, char **argv)

{

EXEC SQL BEGIN DECLARE SECTION;

char *dbase = "stores_demo";

EXEC SQL END DECLARE SECTION;

if (argc > 1)

dbase = argv[1];

EXEC SQL WHENEVER sqlerror CALL error_chk ;

printf("Connect to %s\n", dbase);

EXEC SQL connect to :dbase;

EXEC SQL SELECT province FROM customer WHERE customer_num=1;

return 0;

}

OUTPUT:

Connect to stores_demo

SQLSTATE: IX000

SQLCODE: -217

EXCEPTION 1: SQLSTATE=IX000

MESSAGE TEXT: Column (province) not found in any table in the query (or SLV is undefined).

4.3.6 Troubleshooting

This section we provide a few frequently seen ESQL/C errors and discuss how to diagnose a problem using the trace facility.

The following are typical errors seen in ESQL/C application:

򐂰

Locale mismatch

The most common error you might encounter when writing ESQL/C application is a locale mismatch error:

-23197 Database locale information mismatch

The straight forward solution is to match all the locale related environment variables namely

CLIENT_LOCALE

,

DB_LOCALE

, and

SERVER_LOCALE

. The default values for

CLIENT_LOCALE

are en_us.8859-1 for UNIX and en_us.1252 for

Windows. You can set these by using

export

(ksh) or

setenv

(csh) commands depending on which shell you are using. On windows, you can set the locale from setnet32

.

Chapter 4. Working with ESQL/C

145

7884ch04.fm

Draft Document for Review August 23, 2010 10:53 am

To know more about these locales and related material, refer to http://publib.boulder.ibm.com/infocenter/idshelp/v115/index.jsp?topic=/com.

ibm.glsug.doc/ids_gug_035.htm

򐂰 Compile and linking errors

The error message is: error while loading shared libraries: libifsql.so: cannot open shared object file: No such file or directory

This error is generally due to wrong setting of the shared library path, refer to

4.3.1, “Creating an ESQL/C application” on page 124

for correct settings.

򐂰 Database connection errors

The error message is

-25596 The INFORMIXSERVER value is not listed in the sqlhosts file or the

Registry.

This error is due to incorrect setting of INFORMIXSERVER variable. Check if it is set to the server instance to which you want to connect.

SQLIDEBUG

ESQL/C uses the SQLI protocol to communicate with the Informix database server. The SQLIDEBUG trace allows to trace all the messages between client and server and can be used to diagnose problems such as SQL errors, unexpected return values, or performance issues.

You can enable SQLIDEBUG on both the client and the server side.

On the server side, you can enable SQLIDEBUG using the

onmode -p 1 sqli_dbg

parameter.

To set SQLIDEBUG on the client side, create the environment variable

SQLIDEBUG with the following format sqlidebug=2:path_trace_file

where

path_trace_file corresponds to the location and name of the trace file.

Example 4-14 shows how to create the variable on an UNIX platform and how to

decode the SQLI trace file using the sqliprint utility included as part of Informix

Client SDK.

Example 4-14 sqlidebug trace

informix@irk:/work$ export SQLIDEBUG=2:/tmp/sqlitrace informix@irk:/work$ informix@irk:/work$ sqliprint /tmp/sqlitrace_17008_0_8c819d0 | more

...

146

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch04.fm

C->S (16) Time: 2010-07-06 20:21:58.05185

SQ_DBOPEN

"stores7" [7]

NOT EXCLUSIVE

SQ_EOT

S->C (28) Time: 2010-07-06 20:21:58.05487

SQ_DONE

Warning..: 0x15

# rows...: 0

rowid....: 0

serial id: 0

SQ_COST

estimated #rows: 1

estimated I/O..: 1

SQ_EOT

C->S (56) Time: 2010-07-06 20:21:58.05595

SQ_PREPARE

# values: 1

CMD.....: "SELECT code, sname FROM state WHERE code = ?" [44]

SQ_NDESCRIBE

SQ_WANTDONE

...

Chapter 4. Working with ESQL/C

147

7884ch04.fm

Draft Document for Review August 23, 2010 10:53 am

148

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch05.fm

5

Chapter 5.

Working with the JDBC drivers

In this chapter, we describe how to develop a Java application using the two available

Java Database Connectivity

(JDBC) drivers. This chapter contains the following:

򐂰 Application software requirements

򐂰 Setting up the development environment

򐂰 Verifying connectivity

򐂰 Performing typical database operations

򐂰 Working with special Informix data types

򐂰 Troubleshooting

© Copyright IBM Corp. 2010. All rights reserved.

149

7884ch05.fm

Draft Document for Review August 23, 2010 10:53 am

5.1 JDBC drivers for an Informix database

Java Database Connectivity (JDBC) is the JavaSoft specification of a standard application programming interface (API) that allows Java programs to access database management systems.

The JDBC API consists of a set of interfaces and classes written in the Java programming language. Using these standard interfaces and classes, programmers can write applications that connect to databases, send queries written in structured query language (SQL), and process the results.

Since JDBC is a standard specification, one Java program that uses the JDBC

API can connect to any database management system (DBMS), as long as a driver exists for that particular DBMS.

For more information about the JDBC API, refer to JDBC documentation at http://java.sun.com/javase/6/docs/technotes/guides/jdbc/

5.1.1 JDBC drivers for Informix database

There are two types of JDBC drivers that you can use from a Java application to process data in an IBM Informix database.

򐂰 IBM Informix JDBC driver

򐂰 IBM Data Server Driver for JDBC and SQLJ

Both JDBC drivers are developed as pure-Java drivers (Type 4). This means that, when you use a Type 4 driver from a Java application, your session connects directly to the database or database server without a middle layer.

IBM Informix JDBC Driver

IBM Informix JDBC Driver is a platform-independent, industry-standard Type 4 driver that provides enhanced support for distributed transactions.

Informix JDBC Driver follows the JDBC 3.0 specifications providing support for the following IBM Informix database engines:

򐂰 IBM Informix 7.x, 9.4x, 10.0, 11.10 and 11.50

򐂰 IBM Informix Extended Parallel Server (XPS) 8.5x

򐂰 IBM Informix Standard Engine (SE) 7.x

򐂰 IBM Informix OnLine Version 5.x

To use IBM Informix JDBC Driver Version 3.50.JC6, you must use a JDK 1.4.2 or later package on your platform.

150

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch05.fm

You can download the Informix JDBC Driver from here: http://www14.software.ibm.com/webapp/download/search.jsp?go=y&rs=ifxjdbc

Example 5-1 shows the contents of the Informix JDBC Driver package

Example 5-1 Informix JDBC directory

demo doc

javadoc

release lib

ifxjdbc.jar

ifxjdbcx.jar

ifxlang.jar

ifxlsupp.jar

ifxsqlj.jar

ifxtools.jar

license proxy

This is a brief explanation of the jar files in the driver:

򐂰 ifxjdbc.jar: This is the optimized implementations of the JDBC API interfaces, classes, and methods.

򐂰

ifxjdbcx.jar: This jar file includes the implementation of datasource, connection pooling, and XA-related class files

򐂰 ifxlang.jar: This is the localized versions of all message text supported by the driver.

򐂰

ifxlsupp.jar: This jar file includes support functions for the ifxlang.jar package.

򐂰 ifxsqlj.jar: This jar includes the classes for runtime support of SQLJ programs.

򐂰

ifxtools.jar: This jar includes utilities ClassGenerator, lightweight directory access protocol (LDAP) loader, and others

IBM Data Server Driver for JDBC and SQLJ

IBM Data Server Driver for JDBC and SQLJ, formerly known as IBM Driver for

JDBC and SQLJ is a JDBC driver that uses the DRDA protocol to communicate with IBM database servers. The use of a common communication protocol such as DRDA means that the IBM Data Server Driver for JDBC and SQLJ allows you to write client applications that can use both DB2 and Informix database servers.

The IBM Data Server Driver for JDBC and SQLJ is compliant with the JDBC 3.0 and JDBC 4.0 specifications. This driver is included as part of the IBM Data

Server Driver Package, which is bundled with the IBM Informix Client SDK

Chapter 5. Working with the JDBC drivers

151

7884ch05.fm

Draft Document for Review August 23, 2010 10:53 am product. IBM Data Server Driver for JDBC and SQLJ is also available as a separate download at: http://www-01.ibm.com/support/docview.wss?rs=71&uid=swg24026929

Example 5-2 shows a listing of the files included in the IBM Data Server Driver for

JDBC and SQLJ install package highlighting some important files.

Example 5-2 Data Server Driver for JDBC directory (snippet)

db2jcc.jar

db2jcc4.jar

sqlj.zip

sqlj4.zip

jdbc4_LI_en jdbc4_LI_en.rtf

jdbc_LI_en

The Data Server Driver for JDBC and SQLJ includes the following JDBC drivers:

򐂰

򐂰

򐂰

򐂰

db2jcc.jar

: Use db2jcc.jar in the CLASSPATH if you plan to use the version of the IBM Data Server Driver for JDBC and SQLJ that includes only JDBC 3.0 and earlier functions.

db2jcc4.jar

: Use db2jcc4.jar in the CLASSPATH if you plan to use the version of the IBM Data Server Driver for JDBC and SQLJ that includes only JDBC

4.0 and earlier functions.

sqlj.zip:

Provides support for SQLJ java applications. SQLJ is used to embed

SQL statements inside Java applications.

sqlj4.zip:

Type 4 driver for SQLJ applications.

5.2 Setup and configuration

In this section, we discuss the setup and configuration parameters of the Informix

JDBC drivers. We also discuss how to verify the connection with the Informix database server.

5.2.1 Configuration

The Data Server Client Driver for JDBC requires the use of a DRDA connection, this means the Informix database server must have an alias configured for DRDA communications. Informix JDBC Driver uses the native Informix protocol or SQLI and requires no specific alias on the Informix database server when using the

Informix JDBC Driver.

152

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch05.fm

On the database server, check if the sqlhost file contains the correct listeners for the Informix database server.

Example 5-3 shows the sqlhosts file of the Informix server used by our examples.

Example 5-3 SQLHOSTS

demo_on onipcshm kefka demo_on demo_on_tcp onsoctcp kefka 9088 demo_on_drda drsoctcp kefka 9089

For information regarding how to setup and configure a DRDA alias on the

Informix server refer to 2.1.3, “Configuration” on page 25.

On the Client system, You must have one of the two JDBC drivers installed. for

the installation and configuration details, refer to 2.2.3, “Setting up IBM Data

Server drivers” on page 40 and 2.2.4, “Setting up Informix JDBC” on page 48.

To use any JDBC driver in an application, you must set your CLASSPATH environment variable to point to the driver files. The CLASSPATH environment variable tells the Java virtual machine (JVM) and other applications where to find the Java class libraries used in a Java program.

Example 5-4 shows the environment variable CLASSPATH containing the default

location of both JDBC drivers.

Example 5-4 CLASSPATH example

set CLASSPATH=C:\Program Files\IBM\IBM DATA SERVER

DRIVER\java\db2jcc.jar;C:\Program

Files\IBM\Informix_JDBC_Driver\lib\ifxjdbc.jar;C:\Program

Files\IBM\Informix_JDBC_Driver\lib\ifxjdbcx.jar;%CLASSPATH%;.;

Products such as IBM Data Studio or IBM WebSphere® Application Server have specific location and configuration files for the JDBC drivers. Always refer to each individual documentation for setup details.

You can find additional information regarding the configuration of the

CLASSPATH environment variable in refer to 2.2.3, “Setting up IBM Data Server

drivers” on page 40 and 2.2.4, “Setting up Informix JDBC” on page 48.

5.2.2 Verify Connectivity with the Informix JDBC driver

In this section we demonstrate how to verify a correct setup and configuration of the Informix JDBC Driver.

Chapter 5. Working with the JDBC drivers

153

7884ch05.fm

Draft Document for Review August 23, 2010 10:53 am

To load IBM Informix JDBC Driver, the application can use the Class.forName()

Java method, passing the name of the Informix JDBC Driver as argument.

Class.forName("com.informix.jdbc.IfxDriver");

Example 5-5 contains a basic Java program that can be used to verify the

connectivity with the Informix JDBC driver. The parameters used in the connection string are:

򐂰

The IBM Informix JDBC Driver identifier, jdbc:informix-sqli

.

򐂰 The database server host name, kefka.lenexa.ibm.com

. You can also specify the its IP address.

򐂰

The port number of the SQLI listener of the Informix server,

9088

.

򐂰 The database name, stores_demo .

򐂰

Informix instance identified by INFORMIXSERVER.

򐂰 User and password for connecting to the database server.

Example 5-5 SimpleConnection.java

import java.sql.*; public class SimpleConnection {

public static void main(String[] args) {

String url =

"jdbc:informix-sqli://kefka.lenexa.ibm.com:9088/stores_demo:INFORMIXSERVER=demo

_on;user=informix;password=Ifmx4you";

Connection conn = null;

System.out.println("URL = \"" + url + "\"");

try {

Class.forName("com.informix.jdbc.IfxDriver");

} catch (Exception e) {

System.out.println("FAILED: failed to load Informix JDBC driver.");

}

try {

conn = DriverManager.getConnection(url);

} catch (SQLException e) {

System.out.println("FAILED: failed to connect!");

}

try {

System.out.println("Connected ...");

DatabaseMetaData md = conn.getMetaData();

System.out.println("Driver name: " + md.getDriverName());

System.out.println("Driver version: " + md.getDriverVersion());

System.out.println("Database product name: "

154

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

+ md.getDatabaseProductName());

System.out.println("Database product version: "

+ md.getDatabaseProductVersion());

} catch (SQLException e) {

System.out.println("FAILED: failed to connect!");

}

try {

conn.close();

} catch (SQLException e) {

System.out.println("FAILED: failed to close the connection!");

}

System.out.println("Done!");

}

}

7884ch05.fm

Example 5-6 shows the compile line and output of the SimpleConnect.java

program.

Example 5-6 Running SimpleConnection.java

C:\RedBook>javac SimpleConnection.java

C:\RedBook>java SimpleConnection

URL =

"jdbc:informix-sqli://kefka:9088/stores_demo:INFORMIXSERVER=demo_on;user=i nformix;password=Ifmx4you"

Connected ...

Driver name: IBM Informix JDBC Driver for IBM Informix Dynamic Server

Driver version: 3.50.JC6W1

Database product name: Informix Dynamic Server

Database product version: 11.50.FC7

Done!

5.2.3 Verify Connectivity with the Data Server Driver

You can use the same Java program (Example 5-5 on page 154) to verify the

connection with the Data Server Driver for JDBC with minor change. The changes required:

򐂰 Load the Data Server JDBC driver class using the Class.forName() method:

Class.forName("com.ibm.db2.jcc.DB2Driver");

򐂰

The name of the Data Server JDBC driver in the connection string should be

jdbc:ids

.

Chapter 5. Working with the JDBC drivers

155

7884ch05.fm

Draft Document for Review August 23, 2010 10:53 am

򐂰 The port number. The port number to use the Data Server Driver client is different from the Informix JDBC client. A common mistake is to specify the

SQLI port in the URL that leads to an error like: com.ibm.db2.jcc.am.io: [jcc][t4][2030][11211][3.58.82] A communication error occurred during operations on the connection's underlying socket, socket input stream,or socket output stream. Error location: Reply.fill().

Message: Insufficient data. ERRORCODE=-4499, SQLSTATE=08001

at com.ibm.db2.jcc.am.ed.a(ed.java:319)

at com.ibm.db2.jcc.t4.a.a(a.java:416)

Example 5-7 shows the changes done to the

SimpleConnection.java

source code. There is no need to specify the INFORMIXSERVER when using the IBM

Data Server Driver for JDBC.

Example 5-7 SimpleConnection.java with Data Server JDBC driver

...

Class.forName("com.ibm.db2.jcc.DB2Driver");

} catch (ClassNotFoundException cnfe) {

System.out.println("No such class available.");

return;

}

try {

con = DriverManager

.getConnection("jdbc:ids://kefka:9089/stores_demo",

"informix", "Ifmx4you");

System.out.println("connected");

...

Example 5-8 shows how to compile and run the program. Notice that the

metadata information retrieved by the JDBC driver is slightly different than with the IBM Informix JDBC Driver.

Example 5-8 Output of SimpleConnection.java using the Data Server JDBC driver

C:\RedBook>javac SimpleConnection.java

C:\RedBook>java SimpleConnection connected

Driver name: IBM DB2 JDBC Universal Driver Architecture

Driver version: 3.58.82

Database product name: IDS/UNIX64

Database product version: IFX11500 connected

Done

156

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

5.3 JDBC type mapping

7884ch05.fm

Mapping is the way of specifying data type equivalents. Because there are variations between the SQL data types supported by each database vendor, the

JDBC API defines a set of generic SQL data types that should be used on the

Java application. In addition to these data types, defined by the JDBC driver, the

Java language itself has its own data types that may differ from the SQL types used by the database vendor. When writing a Java application, the programmer uses Java data types to manipulate the data. The application developers should understand what is the equivalent data type in JDBC and the equivalent data types on the database server.

Table 5-1 lists a few of the data type mapping required when working with an IBM

Informix database as examples.

Table 5-1 Data Type Mapping from JDBC to Informix basic data types

Java Type JDBC Type Informix Type

long BIGINT INT8, BIGINT, BIGSERIAL boolean BIT java.sql.Date DATE java.math.BigDecimal

byte[]

DECIMAL

LONGVARBINARY java.lang.String LONGVARCHAR java.math.BigDecimal NUMERIC float, java.lang.Float java.sql.Time

REAL

TIME java.sql.Timestamp TIMESTAMP

BOOLEAN

DATE

DECIMAL

BYTE or BLOB

MONEY

SMALLFLOAT

DATETIME HOUR TO

SECOND

DATETIME YEAR TO

FRACTION(5)

For the complete list of data type mappings between the Informix SQL data types and the Informix JDBC driver, refer to the JDBC Programmer’s Guide at http://publib.boulder.ibm.com/infocenter/idshelp/v115/topic/com.ibm.jdbc_pg.doc

/sii-xc-21122.htm#sii-xc-21122

Chapter 5. Working with the JDBC drivers

157

7884ch05.fm

Draft Document for Review August 23, 2010 10:53 am

For more information regarding the data types used by the IBM Data Server

Driver for JDBC and SQLJ refer to the JDBC and SQLJ, refer to: http://publib.boulder.ibm.com/infocenter/idshelp/v115/topic/com.ibm.jccids.doc/ com.ibm.db2.luw.apdv.java.doc/doc/rjvjdata.htm

5.4 Performing database operations

In this section we provide examples of how to use the IBM Informix JDBC Driver and the IBM Data Server Driver for JDBC for typical database operations such as connection to the Informix database and manipulate data.

5.4.1 Connection to the database

A Java application can obtain a connection with an Informix database in two ways:

򐂰 Use the DriverManager class. This involves loading the JDBC driver using the

Class.forName() method and obtain a connection by calling the getConnection() method.

Class.forName("com.ibm.db2.jcc.DB2Driver"); con = DriverManager.getConnection("jdbc:ids://...");

򐂰 Use a DataSource object through the javax.sql extensions.

DB2ConnectionPoolDataSource ds = new DB2ConnectionPoolDataSource();

PooledConnection poolconn = ds.getPooledConnection(); con = poolconn.getConnection();

The DriverManager class was implemented in the original JDBC 1.0 API. This class provides direct access to all the JDBC driver features, however, it requires the application to load the JDBC driver manually and to use a hard-coded connection string with the connection details.

The DataSource interface was introduced in the JDBC 2.0 API as the preferred method to obtain a JDBC connection. The application has no need to load a

JDBC driver class or provide hard-coded connection details. The interface only needs to know the name of the DataSource it want to use. The details for the database connection are stored within the DataSource definition outside the application code.

Connecting using the DriverManager

When using the DriverManager class to connect to an IBM Informix database, a connection string must be passed to the getConnection()

method with the details for the database server. These details include information such as the

158

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch05.fm

machine where the database server is running and the port number needed for the connection.

Example 5-9 shows the syntax of the connection string used with the Informix

JDBC Driver and the IBM Data Server Driver for JDBC.

Example 5-9 DriverManager connection string syntax

jdbc:[jdbc-driver]://[{ip-address|host-name}:{port-number|service-name}][/dbnam e]:INFORMIXSERVER=servername[{;user=user;password=password]

The parameters used when connecting to an Informix database are:

򐂰 jdbc-driver: Identifies a particular JDBC driver. Informix JDBC Driver uses

informix-sql

i, IBM Data Server Driver for JDBC uses

ids

or

db2

.

򐂰 ip-address or host-name: Specify the machine running the database server.

򐂰 port-number|service-name: Specify the communication port used by the database server.

򐂰 dbname: Name of the database to open after a successful connection with the server.

򐂰

INFORMIXSERVER: Identifies the name of the Informix database server to connect. This parameter is not required when using the Data Server JDBC driver.

򐂰 User and password: Provide the authentication credentials for the connection.

In addition to these standard details, common to all JDBC drivers, the connection string is also used to specify properties only relevant to a specific JDBC driver or

database server. Table 5-2 lists some of the properties specific to the Informix

JDBC driver.

Table 5-2 Informix JDBC Driver connection string.

Parameter Description

DB_LOCALE

CLIENT_LOCALE

Locale of the database in the database server.

Locale used by the Client application

INFORMIXCONTIME

SQLIDEBUG

STMT_CACHE

IFX_ISOLATION_LEVEL

Time-out value for a connection with the server

Enable the trace of the SQLI protocol

Enables SQL statement cache on the server

Specify the default Isolation Level for the session

Chapter 5. Working with the JDBC drivers

159

7884ch05.fm

Draft Document for Review August 23, 2010 10:53 am

For a complete list of the supported properties by the Informix JDBC Driver refer to http://publib.boulder.ibm.com/infocenter/idshelp/v115/topic/com.ibm.jdbc_pg.doc

/sii-02conect-66368.htm#sii-02conect-66368

The IBM Data Server Driver for JDBC supports most of the Informix JDBC Driver properties. A list of the properties supported when connecting to an Informix database server can be found at http://publib.boulder.ibm.com/infocenter/idshelp/v115/index.jsp?topic=/com.ibm.

jdbc_pg.doc/sii-02conect-66368.htm

Example 5-10 shows how to compile a basic Java code used to connect to the

Informix database. The driver name and connection string are been passed as parameters for the program.

Example 5-10 connect.java

C:\work>set CLASSPATH=ifxjdbc.jar:db2jcc.jar:.

C:\work>type connect.java

import java.sql.*; public class connect{

public static void main( String [] args ) {

Connection conn = null;

Statement is = null;

if (args.length<2) {

System.out.println("Need the JDBC driver and Connection_String as parameters");

System.out.println(" java connect \"com.informix.jdbc.IfxDriver\"

\"jdbc:informix-sqli://kodiak:9088/stores_demo

:INFORMIXSERVER=demo_on;user=informix;password=password;\" ");

return;

}

try {

Class.forName(args[0]);

conn = DriverManager.getConnection(args[1]);

System.out.println("Connected to "+conn.getMetaData().getDatabaseProductName());

conn.close();

}

catch ( Exception e ) {

System.err.println(e);

}

}

}

C:\work>javac connect.java

C:\work>java connect "com.informix.jdbc.IfxDriver"

"jdbc:informix-sqli://kodiak:9088/stores_demo:INFORMIXSERVER=demo_on;

160

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch05.fm

"

Connected to Informix Dynamic Server

C:\work>java connect "com.ibm.db2.jcc.DB2Driver"

"jdbc:ids://kodiak:9089/stores_demo:user=informix;password=password";

Connected to IDS/NT64

C:\work>

Connecting using the DataSource extensions

When using a DataSource object, the information for the database connection is stored as properties of the DataSource object. These properties are usually stored in a Java Naming and Directory (JNDI) service managed by the Java runtime or the application server.

The application requires no knowledge about the specific connection details. It makes use of the DataSource object to get a connection with the database server.

In addition to the method implemented by the JDBC driver to set standard properties, both the Informix JDBC Driver and the Data Server Driver for JDBC provide extra methods to set and retrieve properties specific to the Informix database. These properties have the same effect on the database session as the

Informix environment variables used by other Informix APIs, such as ODBC or

.NET.

Example 5-11 shows a DataSource object created using the Informix JDBC

Driver and how to set some of the DataSource properties.

Example 5-11 Datasource sample

IfxDataSource ds = new IfxDataSource(); ds.setServerName("demo_on"); ds.setDatabaseName("stores_demo"); ds.setPortNumber(9089); ds.setIfxIFXHOST("kodiak"); ds.setIfxCLIENT_LOCALE("en_US.CP1252"); ds.getConnection("informix", "password");

You can use these Informix specific properties to modify the behavior of the

JDBC driver or to control particular features of the database server. Table 5-3 on page 162 lists a portion of the DataSource properties implemented in the

Informix JDBC Driver as examples.

Chapter 5. Working with the JDBC drivers

161

7884ch05.fm

Draft Document for Review August 23, 2010 10:53 am

Table 5-3 DataSource properties

Informix variable Method

CLIENT_LOCALE public String getIfxCLIENT_LOCALE() public void setIfxCLIENT_LOCALE()

DB_LOCALE public String getIfxDB_LOCALE() public void setIfxDB_LOCALE()

IFX_ISOLATION_LEVEL public String getIfxIFX_ISOLATION_LEVEL() public void setIfxIFX_ISOLATION_LEVEL (l)

IFX_LOCK_MODE_WAIT public int getIfxIFX_LOCK_MODE_WAIT() public void setIfxIFX_LOCK_MODE_WAIT ()

SQLIDEBUG public String getIfxSQLIDEBUG () public void setIfxSQLIDEBUG ()

STMT_CACHE public String getIfxSTMT_CACHE() public void setIfxSTMT_CACHE()

USEV5SERVER public boolean isIfxUSEV5SERVER() public void setIfxUSEV5SERVER()

For a complete list of all the available properties, refer to the Getting and Setting

Informix Connection Properties section of the IBM Informix JDBC Driver

Programmer’s Guide at http://publib.boulder.ibm.com/infocenter/idshelp/v115/index.jsp?topic=/com.ibm.

jdbc_pg.doc/sii-xb-13590.htm

Because the IBM Data Server Driver for JDBC has support for both Informix and

DB2 database servers, the DataSource properties it provides is different than the

Informix JDBC Driver. Refer to the Properties for the IBM Data Server Driver for

JDBC and SQLJ for a complete list at: http://publib.boulder.ibm.com/infocenter/idshelp/v115/index.jsp?topic=/com.ibm.

jccids.doc/com.ibm.db2.luw.apdv.java.doc/doc/rjvdsprp.htm

5.4.2 Manipulating data

In this section we provide basic examples of how to perform typical data manipulation tasks using a JDBC driver with an IBM Informix database.

Simple SQL statements

A Java application can use a Statement object to run basic SQL statements against the database server. The Statement interface provides two methods:

162

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch05.fm

򐂰 executeQuery() , returns a ResultSet value. Use this method to run SQL statements that return data, for example, a SELECT SQL statement.

򐂰 executeUpdate()

. returns the number of rows effected by the SQL statement.

This method is normally used to perform INSERT, DELETE, and UPDATE operations or to run the Data Definition Language (DDL) statements.

Example 5-12 demonstrates how to perform a DELETE statement using the

executeUpdate()

method.

Example 5-12 executeUpdate sample

C:\work>type delete.java

import java.sql.*; public class delete{

public static void main( String [] args ) {

Connection conn = null;

Statement is = null;

try {

Class.forName("com.informix.jdbc.IfxDriver");

conn =

DriverManager.getConnection("jdbc:informix-sqli://kodiak:9088/stores_demo:INFOR

MIXSERVER=demo_on");

is = conn.createStatement();

int rc=is.executeUpdate("DELETE FROM state WHERE code='"+args[0]+"'");

System.out.format("Deleted %d rows",rc);

conn.close();

}

catch ( Exception e ) {

System.err.println(e);

}

}

}

C:\work>

C:\work>java delete AZ

Deleted 1 rows

C:\work>

Prepare SQL statement with parameters

The PreparedStatement object can be used to run the prepared SQL statement against the database server. Use PreparedStatement when the application use a

Chapter 5. Working with the JDBC drivers

163

7884ch05.fm

Draft Document for Review August 23, 2010 10:53 am

SQL statement repeatedly. The SQL statement can be run multiple times by the application with different values, saving the time the application takes to process and optimize a SQL statement.

Example 5-13 demonstrates how to use aa PreparedStatement object. The

example inserts a row in the state table using the parameters supplied through the command line.

Example 5-13 insert.java

C:\work>cat insert.java

import java.sql.*; import java.util.*; import java.text.*; public class insert{

public static void main( String [] args ) {

Connection conn = null;

try {

Class.forName("com.informix.jdbc.IfxDriver");

conn =

DriverManager.getConnection("jdbc:informix-sqli://kodiak:9088/stores_demo:INFOR

MIXSERVER=demo_on");

PreparedStatement pstmt=conn.prepareStatement("INSERT INTO state

VALUES(?,?,?)");

pstmt.setString(1, args[0]);

pstmt.setString(2, args[1]);

pstmt.setString(3, args[2]);

int rc=pstmt.executeUpdate();

System.out.format("Inserted %d rows",rc);

conn.close();

}

catch ( Exception e ) {

System.err.println(e);

}

}

}

C:\work>java insert AZ Arizona 0

Inserted 1 rows

C:\work>

164

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch05.fm

Retrieving data from a database table

To retrieve data from a database table or a function that returns more than one row, a JDBC application must use the ResultSet object. When the executeQuery()

method from the Statement or PreparedStatement object is call, the data is returned in the form of a ResultSet object. This object allows fetching rows from the database.

Example 5-14 demonstrates how to run an SQL SELECT statement to retrieve

data using the PreparedStatement and the ResultSet object. The result of the prepare statement is stored in the ResultSet object, dbRes

. After that, the dbRes.next()

method is used to scroll through the ResultSet data.

Example 5-14 select.java

C:\work>cat select.java

import java.sql.*; public class select {

public static void main( String [] args ) {

Connection conn = null;

ResultSet dbRes = null;

Statement is = null;

try {

Class.forName("com.informix.jdbc.IfxDriver");

conn =

DriverManager.getConnection("jdbc:informix-sqli://kodiak:9088/stores_demo:INFOR

MIXSERVER=demo_on;’);

PreparedStatement pstmt=conn.prepareStatement("SELECT * FROM state where

code<?");

pstmt.setString(1, args[0]);

pstmt.executeQuery();

dbRes = pstmt.getResultSet();

while (dbRes.next()) {

System.out.format("%s,",dbRes.getString(1));

System.out.format("%s,",dbRes.getString(2));

System.out.format("%f\n",dbRes.getDouble(3));

}

dbRes.close();

conn.close();

}

catch ( Exception e ) {

System.err.println(e);

Chapter 5. Working with the JDBC drivers

165

7884ch05.fm

Draft Document for Review August 23, 2010 10:53 am

}

}

}

C:\work>java select CA

AL,Alabama ,0.040000

AR,Arizona ,0.000000

AZ,Arizona ,0.055000

C:\work>

Transactions

Local transaction are controlled directly with the connection object. Methods such as Connection.commit() and Connection.rollback() are used to resolved a transaction.

By default, all the connections created by the Informix JDBC Driver Connection object are in AutoCommit mode. This means that every SQL statement send to the Informix database server is automatically committed. If the control over the transaction is required, you can turn off the AutoCommit mode by using the

Connection.setAutoCommit() method.

When using the Informix JDBC driver in a XA environment (XA is a standard specification for distributed transactions), the AutoCommit feature is always disable. The transaction manager is the only component that has control over the transaction.

Example 5-15 demonstrates how to disable the AutoCommit mode using

setAutoCommit(false) .

Example 5-15 localtrans.java

C:\work>cat localtrans.java

import java.sql.*; import java.util.*; import java.text.*; public class localtrans{

public static void main( String [] args ) {

Connection conn = null;

Statement is = null;

try {

Class.forName("com.informix.jdbc.IfxDriver");

166

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch05.fm

conn =

DriverManager.getConnection("jdbc:informix-sqli://kodiak:9088/stores_demo:INFOR

MIXSERVER=demo_on");

conn.setAutoCommit(false);

is = conn.createStatement();

int rc = is.executeUpdate("DELETE FROM state WHERE code='UK'");

System.out.format("Deleted %d rows\n",rc);

System.out.format("Aborting transaction\n");

conn.rollback();

conn.close();

}

catch ( Exception e ) {

e.printStackTrace();

}

}

}

C:\work>java localtrans

Deleted 1 rows

Aborting transaction

C:\work>

Running a user-define routine

The CallableStatement object provides a way to run user-defined routines

(UDRs) in a standard way, common to all the IBM database servers.

The results from the execution of the UDRs are returned as a result set or as an

OUT parameter. The SQL syntax for calling a user-defined routine using the

CallableStatement interface is:

"{? = call function_name (?, ?,...)}";

The placeholders identify the IN, OUT and INOUT parameters for the UDR.

The application can set and retrieve the value for the routine parameters using the registerOutParameter() and getxxx()

methods.

Example 5-16 shows a basic UDR defined with two OUT parameters.

Example 5-16 state_tax SQL routine

CREATE FUNCTION state_tax(OUT vtax percent,

Chapter 5. Working with the JDBC drivers

167

7884ch05.fm

Draft Document for Review August 23, 2010 10:53 am

vcode CHAR(2),

OUT vsname CHAR(20))

RETURNS BOOLEAN;

SELECT sales_tax,upper(sname)

INTO vtax, vsname FROM state

WHERE code=vcode;

RETURN 't';

END FUNCTION;

We use CallableStatement to invoke this UDR from a JDBC application.

Example 5-17 demonstrates how to set the IN and OUT for the UDR. The

BOOLEAN value is returned directly by the SQL function and retrieved using a

ResultSet object. To retrieve the OUT parameters, the example uses the getDouble() and GetString() methods.

Example 5-17 Callable.java

C:\work>cat callable.java

import java.sql.*; public class callable {

public static void main( String [] args ) {

Connection conn = null;

try {

Class.forName("com.informix.jdbc.IfxDriver");

conn =

DriverManager.getConnection("jdbc:informix-sqli://kodiak:9088/stores_demo:INFOR

MIXSERVER=demo_on;");

CallableStatement cstmt = conn.prepareCall ("{? = call state_tax(?, ?,

?)}");

cstmt.registerOutParameter(1, Types.DOUBLE);

cstmt.registerOutParameter(3, Types.CHAR);

cstmt.setString(2, "CA");

ResultSet dbRes = cstmt.executeQuery();

// Retrieve OUT parameters from the function

while (dbRes.next())

System.out.format("UDR returns = %s\n", dbRes.getBoolean(1));

// Retrieve OUT parameters from the function

System.out.format("OUT tax %s\n",cstmt.getDouble(1));

System.out.format("OUT sname %s\n",cstmt.getString(3));

168

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

dbRes.close();

cstmt.close();

conn.close();

}

catch ( Exception e ) {

System.err.println(e);

}

}

}

C:\work>java callable

UDR returns = true

OUT tax 0.0825

OUT sname CALIFORNIA

C:\work>

7884ch05.fm

5.5 Informix additional features

This section demonstrates the use of additional features of IBM Informix, such as:

򐂰 Batch Inserts

򐂰 Resultset Metadata

򐂰 Informix BIGSERIAL data type

򐂰 Informix Smart Large Objects

򐂰 Secure Socket Layer

5.5.1 Batch inserts, updates, and resultset metadata

Here we demonstrate the following:

򐂰

Batch Inserts

When performing multiple inserts (or updates) using a prepared statement, it is more efficient to do all the inserts in

bulk

. The method is to add all the inserts in a batch and then run the batch.

򐂰

Using ResultSet metadata

When you run a query from a Java program that generates a result set, there are additional information available apart from the result set itself. These additional information about the data is returned by the ResultSet metadata.

An example of using the ResultSet metadata is for a tool that will obtain table definition information from one database to another database. You can dynamically find out all the details about each column that returns data.

Chapter 5. Working with the JDBC drivers

169

7884ch05.fm

Draft Document for Review August 23, 2010 10:53 am

Example 5-18 shows the batch Insert and how to obtain the column name and

column type from ResultSet metadata. The schema for the gentemp table is:

CREATE TABLE gentemp (id INT, name VARCHAR(15) NOT NULL)

We use con.prepareStatement() method to prepare the SQL INSERT statement, then we execute the statement using the pstmt.addBatch() method which makes the INSERT statement to be part of an batch operation. After adding 10 rows to the table, the batch operation is executed using the pstmt.executeBatch() method.

The metadata information for the table is retrieved using the rs.getMetaData() method.

Example 5-18 Listing for IfxBatchDemo.java

import java.sql.*; import java.io.*; public class IfxBatchDemo {

public static void main(String args[]) throws SQLException, IOException,Exception {

String IfxURL =

"jdbc:informix-sqli://kodiak:9088/stores_demo:INFORMIXSERVER=demo_on";

Connection con = null;

int cnt = 0;

System.out.println("Start");

Class.forName("com.informix.jdbc.IfxDriver");

con = DriverManager.getConnection(IfxURL);

con.setAutoCommit(false);

Statement stmt = null;

PreparedStatement pstmt = null;

ResultSet rs = null;

ResultSetMetaData rsmd = null;

pstmt = con.prepareStatement("INSERT INTO gentemp (id,name) VALUES (?,?)");

// Fill in 10 rows

for (int i = 0; i < 10; i++) {

pstmt.setInt(1, i + 1000);

pstmt.setString(2, "String #" + i);

pstmt.addBatch();

}

int[] rows = pstmt.executeBatch();

System.out.println(" Inserted data. Rows = " + rows.length);

con.commit();

pstmt.close();

pstmt = con.prepareStatement("SELECT * FROM gentemp");

rs = pstmt.executeQuery();

rsmd = rs.getMetaData();

170

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

System.out.println(" " + "Col Names " + rsmd.getColumnName(1) + ","

+ rsmd.getColumnName(2));

System.out.println(" " + "Col Types " + rsmd.getColumnTypeName(1)

+ "," + rsmd.getColumnTypeName(2));

int row = 1;

while (rs.next()) {

System.out.println(" Row " + row + " = "

+ rs.getInt(rsmd.getColumnName(1)) + ","

+ rs.getString(rsmd.getColumnName(2)));

row++;

}

pstmt.close();

con.commit();

con.close();

}

}

7884ch05.fm

5.5.2 BIGSERIAL data type

IBM Informix version 11.50 implements the ANSI standard SQL data type

BIGINT and the BIGSERIAL data types:

򐂰 BIGINT is mapped to the JDBC standard BIGINT data type, so it can be used from a Java application as any other Informix data type.

򐂰

BIGSERIAL, (like SERIAL and SERIAL8) do not have an obvious mapping to any JDBC data type. This means the application must use Informix specific

JDBC methods to retrieved the value of these columns.

The methods to access Informix serial data types are included in the Informix

JDBC implementation of the JAVA java.sql.Statement

interface,

IfxStatement

.

You can use the methods getSerial()

, getSerial8()

, and getBigSerial()

to retrieve the last value inserted on a serial column.

Example 5-19 shows how to retrieve a BIGSERIAL value using the

IfxStatement.getBigSerial()

method. The schema for the table used in this example is:

CREATE TABLE tempbs(id BIGSERIAL, name CHAR(10));

Example 5-19 bigserial.java sample

import java.sql.*; import com.informix.jdbc.*; public class bigserial {

public static void main( String [] args ) {

Chapter 5. Working with the JDBC drivers

171

7884ch05.fm

Draft Document for Review August 23, 2010 10:53 am

Connection conn = null;

ResultSet dbRes = null;

long insertedserial = 0;

String url="jdbc:informix-sqli://kodiak:9088/stores_demo:INFORMIXSERVER=demo_on;";

try {

Class.forName("com.informix.jdbc.IfxDriver");

conn = DriverManager.getConnection(url);

IfxStatement stmt= (IfxStatement) conn.createStatement();

stmt.executeUpdate("INSERT INTO tempbs VALUES (0,'test');");

insertedserial =stmt.getBigSerial();

System.out.println("Last serial: \t"+insertedserial);

stmt.executeQuery("SELECT FIRST 1 * FROM tempbs ORDER BY rowid DESC");

dbRes = stmt.getResultSet();

while (dbRes.next()) {

System.out.format("Last row: \t%d,",dbRes.getLong(1));

System.out.format("%s\n",dbRes.getString(2));

}

dbRes.close();

conn.close();

}

catch ( Exception e ) {

System.err.println(e);

}

}

}

Example 5-19 on page 171 inserts a row in the

tempbs table and stores the last

BIGSERIAL value in the insertedSerial

variable. Example 5-20 shows how to

compile the example and its output.

Example 5-20 output of bigserial.java

C:\work>javac bigserial.java

C:\work>java bigserial

Last serial: 14

Last row: 14,test

C:\work>

172

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch05.fm

5.5.3 Informix Smart Large Objects

Smart Large Objects is a type of large objects supported by Informix. Smart

Large Objects is logically stored in a table column but physically stored in a specific type of dbspaces called Smart Blob Space.

The data stored in the table column is a structure which contains information about the large object, such as special attributes or pointers to location in the

Smart Blob Space containing the data. Informix has two types of smart large objects.

򐂰

BLOB: Stores binary data.

򐂰

CLOB: Stores character data

There are two methods to manipulate Smart Large Objects with the Informix

JDBC Driver.

򐂰 Standard JDBC 3.0 API.

Using standard JDBC methods such as getString()

, s etAsciiStream()

, or getBinaryStream()

allow an application to handle Smart Lager Objects as standard Java data types.

򐂰 Informix smart-large-object extensions.

If an application requires random access to the large data, it must use the

Informix smart-large-object extensions. These extensions to the JDBC API give the application a greater control over the smart-large-object data in terms of object properties, concurrency access, and logging.

The IfxSmartBlob interface implements most of the smart-large-object extensions, methods such as I fxLoCreate()

,

IfxLoOpen() , IfxLoRead() , and

IfxLoWrite() can be used to access the smart large object structures and manipulate the data of the object.

For a complete description of all the Informix smart-large-objects extensions, refer to the Informix JDBC Driver Guide at: http://publib.boulder.ibm.com/infocenter/idshelp/v115/index.jsp?topic=/com.

ibm.jdbc_pg.doc/sii-04data-36421.htm

Note: The IBM Data Server Driver for JDBC does not support the Informix

Smart Large Object extensions, only the standard JDBC API is available for working with Smart Large Objects

Using the standard JDBC API

Working with Smart large Objects using the JDBC API does not require any

specific Java code. Example 5-21 on page 174 demonstrates how to retrieve a

CLOB column from the Informix database using the getString()

method.

Chapter 5. Working with the JDBC drivers

173

7884ch05.fm

Draft Document for Review August 23, 2010 10:53 am

Example 5-21 getclob.java sample

C:\work>cat getclob.java

import java.sql.*; public class getclob {

public static void main( String [] args ) {

Connection conn = null;

ResultSet dbRes = null;

Statement is = null;

try {

Class.forName("com.informix.jdbc.IfxDriver");

conn = DriverManager.getConnection(

"jdbc:informix-sqli://kodiak:9088/stores_demo:INFORMIXSERVER=demo_on;");

PreparedStatement pstmt=conn.prepareStatement("SELECT * FROM catalog WHERE

catalog_num=?");

pstmt.setString(1, args[0]);

pstmt.executeQuery();

dbRes = pstmt.getResultSet();

dbRes.next();

System.out.println("Advert description: "+dbRes.getString("advert_descr"));

dbRes.close();

conn.close();

}

catch ( Exception e ) {

System.err.println(e);

}

}

}

C:\work>javac getclob.java

C:\work>java getclob 10001

Advert description: Brown leather. Specify first baseman's or infield/outfield style. Specify right- or left-handed.

C:\work>

Using the Informix extensions

The smart-large-object extensions allows a Java application to have direct control over the large object structures and data pointers used to describe the large object.

The following interfaces provide the methods needed to handle smart large objects:

174

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch05.fm

򐂰 IfxLobDescriptor, stores the internal characteristics for a smart large object.

The application must create an IfxLobDescriptor object to insert a new large object in the database.

򐂰

IfxLocator, used to identify a particular large object. An IfxLocator object can be created or retrieved from the database to perform any I/O operations with the large object.

򐂰 IfxSmartBlob, represent a Smart Large Object within the Informix JDBC

Driver. Provides all the methods necessary to create, open, read, and write to a large object.

򐂰

IfxloStat, stores statistical information about a smart large object such as the size, last access time, last modified time and last status change.

򐂰 IfxBblob and IfxCblob, add extended functionality to the standard JDBC 3.0

BLOB and CLOB classes.

Example 5-22 demonstrate how to read data from a smart large object using the

IfxSmartBlob method. The code performs the following steps to select the CLOB column advert_descr :

1. Stores the advert_descr

column as an

IfxCblob

object using the getClob() method.

2. Gets the IfxLocator from the IfxCblob object through the cblob.getLocator() method.

3. Creates an

IfxSmartBlob

object and uses the

IfxLocator

to open the smart large object in smb.IfxLoOpen()

.

4. Reads the first 200 bytes of the CLOB using the smb.IfxLoRead() method.

5. Close the large object and release the

IfxLocator

.

Example 5-22 loext.java

import java.sql.*; import com.informix.jdbc.*; public class loext{

public static void main( String [] args ) {

Connection conn = null;

byte[] buffer = new byte[200];

try {

Class.forName("com.informix.jdbc.IfxDriver");

conn = DriverManager.getConnection(

"jdbc:informix-sqli://kodiak:9088/stores_demo:INFORMIXSERVER=demo_on;");

PreparedStatement pstmt=conn.prepareStatement("SELECT * FROM catalog WHERE

catalog_num=?");

pstmt.setString(1, args[0]);

Chapter 5. Working with the JDBC drivers

175

7884ch05.fm

Draft Document for Review August 23, 2010 10:53 am

pstmt.executeQuery();

ResultSet dbRes = pstmt.getResultSet();

dbRes.next();

IfxCblob cblob = (IfxCblob) dbRes.getClob("advert_descr");

IfxLocator loPtr = cblob.getLocator();

IfxSmartBlob smb = new IfxSmartBlob(conn);

int loFd = smb.IfxLoOpen(loPtr, smb.LO_RDONLY);

int bytesReaded = smb.IfxLoRead(loFd, buffer, buffer.length);

smb.IfxLoClose(loFd);

smb.IfxLoRelease(loPtr);

System.out.println("Advert description: "+new String(buffer).trim());

dbRes.close();

conn.close();

}

catch ( Exception e ) {

System.err.println(e);

}

}

}

Example 5-23 shows how to compile and the output of the

loext.java

sample

Example 5-23 output of loext.java

C:\work>javac loext.java

C:\work>java loext 10001

Advert description: Brown leather. Specify first baseman's or infield/outfield style. Specify right- or left-handed.

C:\work>

For more information regarding the use of Smart Large Object with the Informix

JDBC driver refer to the Informix JDBC Driver Guide at http://publib.boulder.ibm.com/infocenter/idshelp/v115/topic/com.ibm.jdbc_pg.doc

/sii-04data-36421.htm#sii-04data-36421

5.5.4 Secure Socket Layer (SSL)

In addition to the encrypted communications provided by the Communication

Support Module (CSM), the Informix database server supports the use of Secure

Socket Layer (SSL) communications for the encryption of the packages between client and server.

176

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch05.fm

The Informix JDBC Driver supports only CSM encryptions, you must use the IBM

Data Server Driver for JDBC to connect to an SSL-enabled Informix database server.

Before you can use SSL encryption with an Informix database, you must configure both server and client machines.

Preparing the Informix Server for SSL

To enable SSL on the Informix server, create an Informix alias using the drsocssl protocol.

Example 5-24 shows the configuration and commands used to enable SSL

communications with an IBM Informix server.

Example 5-24 SSL configuration on the Informix server

$gsk7capicmd -keydb -create -db kodiak.kdb -pw password -type cms -stash

$gsk7capicmd -cert -create -db kodiak.kdb -pw password -label testlabel -dn

"CN=bedfont.uk.ibm.com,O=ibm,C=UK" -size 1024 -default_cert yes

$gsk7capicmd -cert -extract -db kodiak.kdb -format ascii -label testlabel -pw password -target testlabel.cert

$ pwd

/usr3/11.50/ssl

$ ls -a

. kodiak.crl kodiak.rdb testlabel.cert

.. kodiak.kdb kodiak.sth

$ onstat -c | grep ssl

DBSERVERALIASES kodiak_shm,kodiak_drda,kodiak_ssl

$ grep kodiak_ssl $INFORMIXSQLHOSTS

kodiak_ssl drsocssl kodiak 9191

$

For detail information regarding the configuration of SSL with an Informix server, refer to the section Configuring a Server Instance for Secure Sockets Layer

Connections on Information Center at: http://publib.boulder.ibm.com/infocenter/idshelp/v115/index.jsp?topic=/com.ibm.

sec.doc/ids_ssl_002.htm

Preparing the Informix Client for SSL

To enable SSL encryption both client and server machine must use the same certificated file. A certified file can be imported into the client machine using the keytool utility included with the Java SDK framework.

Chapter 5. Working with the JDBC drivers

177

7884ch05.fm

Draft Document for Review August 23, 2010 10:53 am

Example 5-25 demonstrates how to import the

testlabel.cert

certificate file

created in Example 5-24 on page 177 to enable a trusted relationship between

client and server. A keystore file is created to stored the keys for the SSL encrypted connection.

Example 5-25 SSL Client side configuration

C:\work>keytool -importcert -file testlabel.cert -keystore .keystore

Enter keystore password:

Re-enter new password:

Owner: CN=bedfont.uk.ibm.com, O=ibm, C=UK

Issuer: CN=bedfont.uk.ibm.com, O=ibm, C=UK

Serial number: -14b0e6b89751eab1

Valid from: Thu Jul 15 08:10:31 PDT 2010 until: Sat Jul 16 08:10:31 PDT 2011

Certificate fingerprints:

MD5: 66:FA:CF:44:9F:F3:38:40:7B:9D:93:D6:D6:1C:DB:C5

SHA1: CF:38:6F:CA:C9:A1:54:43:FC:64:AD:F6:DF:5F:CA:65:01:58:DE:DE

Signature algorithm name: SHA1withRSA

Version: 3

Trust this certificate? [no]: yes

Certificate was added to keystore

C:\work>dir .key* /b

.keystore

C:\work>

Java client

A Java application can connect to the SSL Informix server by performing the following operations:

򐂰 Set the System property javax.net.ssl.truststore to point to the keystore created. In our example, it is C:\work\.keystore

.

򐂰

Set the System property javax.net.ssl.trustStorePassword

to the password used for the certificate.

򐂰 Get a datasource object.

򐂰

Set the port number to the SSL port, 9191.

򐂰 Set the datasource property setSslConnection to true.

Example 5-26 shows a basic Java code that connects to a SSL Informix server.

Example 5-26 Listing conssl.java

import java.sql.*; import javax.sql.*;

178

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch05.fm

import java.io.*; import java.util.*; import com.ibm.db2.jcc.*; public class conssl {

public static void main(String args[]) throws SQLException, IOException,

Exception {

System.setProperty ("javax.net.ssl.trustStore","c:/work/.keystore");

System.setProperty ("javax.net.ssl.trustStorePassword","password");

DB2ConnectionPoolDataSource ds = new DB2ConnectionPoolDataSource();

ds.setUser("informix");

ds.setPassword("password");

ds.setServerName("kodiak");

ds.setDatabaseName("stores_demo");

ds.setPortNumber(9191);

ds.setDriverType(4);

ds.setSslConnection(true); // SSL

PooledConnection poolconn = ds.getPooledConnection();

Connection con = poolconn.getConnection();

DatabaseMetaData md = con.getMetaData();

System.out.println("Driver name: " + md.getDriverName());

System.out.println("Connected to "+ md.getDatabaseProductName());

System.out.println("Database product version: " +

md.getDatabaseProductVersion());

con.close();

}

}

After a successful connection, the code prints metadata information such as

driver name and database version. Example 5-27 shows the output.

Example 5-27 output of conssl.java

C:\work>javac conssl.java

C:\work>java conssl

Driver name: IBM DB2 JDBC Universal Driver Architecture

Connected to IDS/UNIX32

Database product version: IFX11500

C:\work>

Chapter 5. Working with the JDBC drivers

179

7884ch05.fm

Draft Document for Review August 23, 2010 10:53 am

5.5.5 Typical errors

Errors result from the application development environment without proper configuration and SQL syntax errors are the common seen problem in the Java applications for Informix.

Class not found errors

The following shows an class not found error message:

C:\RedBook>java IfxSimpleConnection

Exception in thread "main" java.lang.NoClassDefFoundError:

IfxSimpleConnection

Caused by: java.lang.ClassNotFoundException: IfxSimpleConnection

...

These types of error are usually from either failing to load the JDBC driver or failing to load the application class because the environment is not configured properly. To resolve this problem:

򐂰 Make sure that you have the JDBC driver jar files in you CLASSPATH.

򐂰

Make sure that you have a “.” (dot) to include your current directory in the

CLASSPATH.

Connectivity errors

When an application fails to connect to the server, you see error similar to this:

Exception in thread "main" java.sql.SQLException: com.informix.asf.IfxASFException: Attempt to connect to database server

(demo_on) failed.

at com.informix.jdbc.IfxSqliConnect.<init>(IfxSqliConnect.java:1319)

...

To resolve this problem:

򐂰

Check if the server is up and running and the ports are configured correctly on the server.

򐂰 Check the port number specified in the application. Remember, Informix

JDBC driver connects to a SQLI port and the IBM Data Server driver connects to a DRDA port.

򐂰

Check that there is no firewall between the client and server. Doing a

telnet

from the client to the server box can help to check this.

Syntax errors

The exception with SQLCODE -201 is a syntax error in a SQL statement you are trying to run. Apart from eyeballing the offending SQL, it can be helpful to know

180

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch05.fm

the location of the SQL that the server is complaining about. You can achieve this by obtaining the SQL statement offset as follows: try {

stmt.execute( SQL );

} catch(Exception e) {

System.out.println ("Error Offset :"+((IfmxConnection conn).getSQLStatementOffset() );

System.out.println(e.getMessage() );

}

5.5.6 Tracing

Tracing the communication with the Informix database server may be required for further diagnostics. The method to enable tracing depends on the Informix JDBC driver used.

IBM Informix JDBC Driver

The Informix JDBC uses the Informix SQLI protocol for the communication with the database server. A trace file with all the SQLI messages can be generated by enabling the SQLITRACE feature within the JDBC driver.

Depending on the method used for the connection, the SQLIDEBUG can be activated using a connection string keyword or a DataSource method:

򐂰

Setting trace for Informix JDBC driver using the DriverManager

DriverManager.getConnection("jdbc:informix-sqli://kodiak:9088/sysmaster:INF

ORMIXSERVER=demo_on;user=;password=;SQLIDEBUG=/tmp/jdbctrace");

򐂰

Setting trace for Informix JDBC driver using a Datasource

IfxDataSource ifxds = new IfxDataSource();

ifxds.setIfxSQLIDEBUG("c:/temp/sqli.trc");

You can run the trace through the

sqliprint

utility to render it to text form.

IBM Data Server Driver for JDBC

The IBM Data Server Driver for JDBC uses DRDA as the network protocol and produces a DRDA trace. This is a straight text output trace which can be examined directly.

You can enable DRDA trace with the JDBC using the following methods:

򐂰 Setting trace for IBM Data Server driver using the DriverManager:

DriverManager.getConnection("jdbc:ids://kodiak:9089/sysmaster:user=;passwor d=;traceFile=/jcc.trc;TraceLevel=TRACE_ALL;");

Chapter 5. Working with the JDBC drivers

181

7884ch05.fm

Draft Document for Review August 23, 2010 10:53 am

򐂰 Setting trace for IBM Data Server driver using a datasource:

DB2SimpleDataSource ds = new DB2SimpleDataSource();

ds.setTraceFile("/jcc.trc"); ds.setTraceLevel(com.ibm.db2.jcc.DB2BaseDataSource.TRACE_ALL);

ds.setTraceFileAppend(false);

Both SQLIDEBUG and DRDADEBUG traces can be activated at the server side rather than on the client machine. This is done using the Informix utility onmode included with the Informix database server. You can find more information

regarding both traces on the “Tracing” on page 114.

182

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch06.fm

6

Chapter 6.

IBM Informix with Hibernate

This chapter describes how to use the HIbernate Java package with an IBM

Informix database. we discuss the following topics:

򐂰 Description of the Hibernate

򐂰 Setup and configuration

򐂰 Application development using the Hibernate and the Informix JDBC drivers

© Copyright IBM Corp. 2010. All rights reserved.

183

7884ch06.fm

Draft Document for Review August 23, 2010 10:53 am

6.1 Hibernate for Java

This section describes the concepts of Hibernate and the Java Persistence API

(JPA) programming model.

6.1.1 Hibernate

Hibernate is an open source Java object-relational mapping (ORM) and persistence framework that allows you to map plain old Java objects to relational database tables using XML configuration files. Hibernate also provides a data query language, Hibernate Query Language (HQL) and retrieval facilities that help reduce development time spent on manual data handling in JDBC calls or

SQL statements.

Persistence data refers to any data that must be stored in the database and has to exist after the application has finished running. What Hibernate provides is a way to persist not only the typical relational data but also Java objects used by the application.

A relational database stores the information in a tabular way, tables and columns.

A relational database ensures the integrity of the data using SQL objects such as constraints and referential integrity.

An Object-orientated programming (OOP) language such as Java or C++ do not have the same data representation as relational databases. The data is represent by objects, with attributes and methods. The relationship between these objects is implemented with concepts like inheritance or polymorphism that do not exists in a relational database.

Object-relational mapping (ORM) technologies such as Hibernate tries to solved the limitations of object-orientated languages when using relational databases. object-relational mapping allows developers to focus on the business logic of the application, without the need for dealing with the data access layer. A developer only needs to load the Customer object and not care about how the information for that particular customer is stored in the database. Object-relational mapping solutions produce more robust and portable code which means faster development time.

For more information about Hibernate refer to the Hibernate Reference

Documentation at http://docs.jboss.org/hibernate/stable/core/reference/en/html/

184

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch06.fm

6.1.2 Hibernate concepts

The main concepts in the Hibernate framework are:

򐂰

Persistence

Persistence, in Hibernate terms, refers to the concept of storing the state of an Java object in the database, so it can be restored later on.

򐂰

Mapping

Mapping is the process to map SQL tables to Java objects. Mapping is done using XML mapping files or through the use of Java annotations (metadata added to the application source) in the Java code.

򐂰

Object processing

Object processing refers to the use of the mapped objects from the application code. How to save and load the state of an Java object using the

Hibernate API or the specific Hibernate Query Language (HQL).

In a simplified words, Hibernate for Java is a set of Java APIs that allows store and retrieve the state of Java objects into a database through the use of a JDBC driver.

Figure 6-1 illustrates the typical components of a Hibernate application.

Figure 6-1 Hibernate components

Chapter 6. IBM Informix with Hibernate

185

7884ch06.fm

Draft Document for Review August 23, 2010 10:53 am

The components in Figure 6-1 on page 185 are:

򐂰

Application: This represents the Java application.

򐂰 Java object: It is the object the application wants to persist (keep it in the database).

򐂰

Hibernate properties: This is the configuration file for the Hibernate framework, named hibernate.cfg.xml that contains information such as the connection details for the database server or the SQL dialect to use.

򐂰 XML Mapping: This is an XML file which contains the mappings between Java

Objects and database Objects.

򐂰

JDBC: This is the JDBC driver used for the database connection. Both

Informix JDBC driver, IBM Informix JDBC Driver, and IBM Data Server Driver for JDBC can be used with Hibernate.

򐂰 Informix database: This is the IBM Informix database server.

In addition to the object-relational mapping, Hibernate also provides a connection management and a transaction management services to be used with a Java application. These topics are not cover in this section. For information regarding the use and configuration of the Connection and Transaction management services refer to Transactions and Concurrency section of the Hibernate

Reference Documentation at http://docs.jboss.org/hibernate/core/3.3/reference/en/html/transactions.html

6.2 Setup and configuration

This section describes the installation and configuration of Hibernate to be used against an IBM Informix database.

6.2.1 Installation

Hibernate is an open source project which can be downloaded through the

SourceForge website at http://sourceforge.net/projects/hibernate/files

The latest version of the Hibernate API is 3.5.3 that fully implements the Java

Persistence API 2.0 (JPA). The zip package name is hibernate-distribution-3.5.3-Final-dist.zip

Example 6-1 on page 187 shows the contents of the Hibernate zip package.

186

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

Example 6-1 Hibernate distribution content

changelog.txt

documentation

javadocs

manual

hibernate-testing.jar

hibernate3.jar

hibernate_logo.gif

lgpl.txt

lib

bytecode

jpa

hibernate-jpa-2.0-api-1.0.0.Final.jar

optional

c3p0

ehcache

infinispan

jbosscache

oscache

proxool

swarmcache

required

antlr-2.7.6.jar

commons-collections-3.1.jar

dom4j-1.6.1.jar

javassist-3.9.0.GA.jar

jta-1.1.jar

slf4j-api-1.5.8.jar

project

7884ch06.fm

The package contains most of the Java libraries required to run a Hibernate application including the Hibernate documentation and the source code project files for the Hibernate libraries.

򐂰

hibernate3.jar: Hibernate Core library for Relational Persistence

򐂰 hibernate-jpa-2.0-api-1.0.0.Final.jar: Hibernate definition of the Java

Persistence 2.0 API

򐂰

antlr-2.7.6.jar: Framework for grammatical descriptions containing Java

򐂰 commons-collections-3.1.jar: Types that extend and augment the Java

Collections Framework

򐂰

dom4j-1.6.1.jar: XML framework for Java

򐂰 javassist-3.9.0.GA.jar: JAVA programming ASSISTant

򐂰

jta-1.1.jar: The javax.transaction package

򐂰 slf4j-api-1.5.8.jar: API for the Simple Logging Facade for Java

Chapter 6. IBM Informix with Hibernate

187

7884ch06.fm

Draft Document for Review August 23, 2010 10:53 am

In addition to the libraries supplied by the Hibernate package, the jar packages containing the libraries for the JDBC driver that must be included in the

CLASSPATH:

򐂰 ifxjdbc.jar: IBM Informix JDBC Driver

򐂰 db2jcc.jar: IBM Data Server Driver for JDBC

򐂰

Note: The slf4j-api-1.5.8.jar package does not contain the complete set of

libraries for the Simple Logging Facade for Java (SLFJ). A package providing a implementation for the SLFJ logger must be used in conjunction with Hibernate API.

There are several implementations of the SLFJ logger available at: http://www.slf4j.org/download.html

In our examples we use slf4j-simple-1.6.1.jar and slf4j-nop-1.6.1.jar that provide simple-logging and discarded-logging.

The Hibernate package is also available as a Maven 2 artifact. Maven is an open source software project management that uses XML files based on the Project

Object model (POM) to manage all the attributes and dependencies files of a

Java project. For more information about Maven refer to the Apache Maven

Project documentation at http://maven.apache.org/what-is-maven.html

6.2.2 Configuration

In this section we discuss the configuration setting required to develop Informix application with Hibernate.

CLASSPATH

CLASSPATH is an environment variable that tells the Java compiler and the Java

Virtual Machine (JVM) where to look for Java class files and Java libraries.

To be able to use Hibernate with a Java program, the core library, hibernate3.jar, and all the libraries in the lib/required directory must be included in the application CLASSPATH. An implementation of the SLFJ logger and the JDBC driver is also required for Hibernate to work.

Example 6-2 shows an UNIX script used to create the CLASSPATH environment

variable. We use discarded-logging slf4j-nop-1.6.1.jar and the Informix JDBC

Driver ifxjdbc.jar for our examples.

Example 6-2 Hibernate classpath script

export CLASSPATH=$CLASSPATH:.

188

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch06.fm

export CLASSPATH=$CLASSPATH:/work/lib/commons-collections-3.1.jar

export CLASSPATH=$CLASSPATH:/work/lib/dom4j-1.6.1.jar

export CLASSPATH=$CLASSPATH:/work/lib/hibernate-jpa-2.0-api-1.0.0.Final.jar

export CLASSPATH=$CLASSPATH:/work/lib/hibernate3.jar

export CLASSPATH=$CLASSPATH:/work/lib/javassist-3.9.0.GA.jar

export CLASSPATH=$CLASSPATH:/work/lib/jta-1.1.jar

export CLASSPATH=$CLASSPATH:/work/lib/slf4j-api-1.6.1.jar

export CLASSPATH=$CLASSPATH:/work/lib/antlr-2.7.6.jar

export CLASSPATH=$CLASSPATH:/work/lib/slf4j-nop-1.6.1.jar

export CLASSPATH=$CLASSPATH:/work/lib/ifxjdbc.jar

Hibernate configuration file

Hibernate provides two alternative methods for specify configuration parameters:

򐂰 hibernate.properties: A standard java properties text file

򐂰 hibernate.cfg.xml: An XML formatted file

Both files contains the same configuration details for the Hibernate service, If both files exist, the XML configuration file overrides the settings in the properties file.

The configuration file (hibernate.properties or hibernate.cfg.xml) contains the information Hibernate needs to connect to the database server. Details such as name of the JDBC driver class, ConnectionString, authentication details are kept in this file.

The Hibernate libraries require the configuration file (hibernate.properties or

hibernate.cfg.xml) to be located in the root directory of the CLASSPATH.

Example 6-3 shows a hibernate.cfg.xml file using the Informix JDBC Driver.

Example 6-3 hibernate.cfg.xml sample

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE hibernate-configuration PUBLIC

"-//Hibernate/Hibernate Configuration DTD 3.0//EN"

"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

<session-factory name="Informix_Session">

<!-- properties -->

<property name="connection.driver_class">

com.informix.jdbc.IfxDriver

</property>

<property name="connection.url">

jdbc:informix-sqli://kodiak:9088/stores_demo:INFORMIXSERVER=demo_on;

</property>

<property name="hibernate.connection.username">

Chapter 6. IBM Informix with Hibernate

189

7884ch06.fm

Draft Document for Review August 23, 2010 10:53 am

informix

</property>

<property name="hibernate.connection.password">

password

</property>

<property name="dialect">

org.hibernate.dialect.InformixDialect

</property>

<property name="hibernate.show_sql">false</property>

<property name="hbm2ddl.auto">update</property>

<!-- mapping files -->

<mapping resource="State.hbm.xml"/>

</session-factory>

</hibernate-configuration>

In addition to the JDBC information, the configuration file also contains configuration details for the Hibernate service.

The property dialect

is used to specify the SQL dialect for the database server.

A Hibernate dialect is a Java class containing specific details regarding the SQL syntax needed to communicate with a particular database.

When using the IBM Informix JDBC Driver with Hibernate, the dialect must be set to orb.hibernate.dialect.InformixDialect

. The dialect for the IBM Data

Server Driver for JDBC is org.hibernate.dialect.DB2Dialect

.

These classes are included in the hibernate3.jar package and contains a basic, non-optimized implementation of the Informix dialect.

Note: A patch that adds Informix SQL optimizations to the original Hibernate

dialect for Informix databases can be found on the International Informix Users

Group website at: http://www.iiug.org/opensource/files/hibernate-3.3.2_informix.tar.gz

The XML configuration file allows the inclusion of XML mapping files. The property mapping resource is used to specify the XML file containing the

mapping between the SQL table and the Java object. In Example 6-3 on page 189 we include the

State.hbm.xml mapping file as part of the hibernate configuration.

<mapping resource="State.hbm.xml"/>

Properties such as hibernate.show_sql or hbm2ddl.auto controls the behavior of the Hibernate service. hibernate.show_sql

is used to dump all the SQL

190

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch06.fm

statements to the console which may be useful for debugging purposes. Setting hbm2ddl.auto

to update specifies that the schema for the SQL table is automatically updated if differs from the definition in the XML definition.

For more information regarding all the supported properties for the Hibernate configuration files, refer to the Hibernate Reference Documentation at: http://docs.jboss.org/hibernate/core/3.3/reference/en/html/session-configuratio n.html

XML mapping file

The XML mapping file is used to specify the relations between a Java object and an SQL database object. These mapping definitions, are used to provided

Hibernate with the information needed to persist the Java objects into the relational database. They also provide support features, such as creating the database schema and relationship between the objects.

XML mapping files are not required when using Java annotations, the mapping information is added through using annotations in the Java source code.

Example 6-4 shows a basic XML file used to map the

States table to the State

Java object.

Example 6-4 State.hbm.xml

<?xml version="1.0"?>

<!DOCTYPE hibernate-mapping PUBLIC

"-//Hibernate/Hibernate Mapping DTD//EN"

"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">

<hibernate-mapping>

<class

name="State"

table="States">

<id

name="id"

column="id">

<generator class="increment"/>

</id>

<property

name="code"

column="code"/>

<property

name="sname"

column="sname"/>

</class>

</hibernate-mapping>

Chapter 6. IBM Informix with Hibernate

191

7884ch06.fm

Draft Document for Review August 23, 2010 10:53 am

The definition includes information such as the table name and column to be used as identifier (ID), and specific attributes for the elements like the generator

class which defines a column as an identifier automatically generated by the Java libraries. These details are used by the Hibernate libraries to automatically generate SQL statements, including Data Definition Language (DDL) and Data

Manipulation Language (DML).

For a complete list of all the attributes available in an XML mapping file, refer to section Basic O/R Mapping of the Hibernate Reference Documentation at: http://docs.jboss.org/hibernate/core/3.3/reference/en/html/mapping.html#mapping

-declaration

6.3 Using Hibernate with an Informix database

In this section we demonstrate how to perform basic operations using the

Hibernate API with an IBM Informix database server.

6.3.1 Components of a Hibernate application

To develop a Hibernate application, the following tasks must be perform:

򐂰 Create the Java objects.

򐂰

Create the XML Mapping files for the Java objects.

򐂰 Create the configuration file for the Hibernate framework.

򐂰

Create the HibernateUtil helper class that provides access to the Hibernate session.

򐂰 Create the application that would use the Java persistence objects.

Java object

Hibernate supports the use of Plain Old Java Objects (POJO) for the definition of a persistence object. This means that there is special requirement when writing the Java class that represents the object.

Example 6-5 shows the contents of the

State.java

file used to define the

State object. The

State

Java object is created as any normal Java object. The object have three properties ( id

,

code

, and sname

) and the usual methods to set and get those properties such as setcode()

or setsname()

. The id

attribute is used to uniquely identify the Java persistence object.

Example 6-5 State.java

public class State {

192

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

private Long id;

private String code;

private String sname;

public State() {}

public State(String text, String text2) {

this.code = text;

this.sname = text2;

}

public Long getId() {

return id;

}

private void setId(Long id) {

this.id = id;

}

public String getcode() {

return code;

}

public void setcode(String text) {

this.code = text;

}

public String getsname() {

return sname;

}

public void setsname(String text) {

this.sname = text;

}

}

7884ch06.fm

Example 6-6 shows the CLASSPATH used in the environment and how to

compile the

State.java

source code.

Example 6-6 Compile line for State.java

C:\work>set classpath

CLASSPATH=C:\work\lib\commons-collections-3.1.jar;C:\work\lib\dom4j-1.6.1.jar;C

:\work\lib\hibernate-jpa-2.0-api-1.0.0.Final.jar;C:\work\lib\hibernate3.jar;C:\ work\lib\ifxjdbc.jar;C:\work\lib\javassist-3.9.0.GA.jar;C:\work\lib\jta-1.1.jar

;C:\work\lib\slf4j-api-1.6.1.jar;C:\work\lib\slf4j-nop-1.6.1.jar;C:\work\lib\an tlr-2.7.6.jar;.

C:\work>javac State.java

C:\work>

XML mapping file

A XML mapping file is required to link the Java object with an Informix database object. The

States

table would keep all the instances of the Java

State

object

Chapter 6. IBM Informix with Hibernate

193

7884ch06.fm

Draft Document for Review August 23, 2010 10:53 am

The common convention for the name of the XML mapping file is

objectname_hbm.xml

.

Example 6-7 shows the contents of the

State_hbm.xml

.

Example 6-7 State_hbm.xml file

<?xml version="1.0"?>

<!DOCTYPE hibernate-mapping PUBLIC

"-//Hibernate/Hibernate Mapping DTD//EN"

"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">

<hibernate-mapping>

<class

name="State"

table="States">

<id

name="id"

column="id">

<generator class="increment"/>

</id>

<property

name="code"

column="code"/>

<property

name="sname"

column="sname"/>

</class>

</hibernate-mapping>

The name of the class is

State

and is mapped to the Informix SQL table

States

.

The

State

class contains two types of elements:

򐂰 <id>: Defines the mapping from that property to the primary key column. It usually contains the generator element which is used to generate unique identifiers for the ID property.

The generator class supports different ways to generate identifiers. increment is the most basic; sequence allows to use an SQL sequence to obtain the identifier value. For a list of all the methods implemented in the generator interface, refer to the Hibernate Reference Documentation at: http://docs.jboss.org/hibernate/core/3.3/reference/en/html/mapping.html#map ping-declaration-id

򐂰

<property name>: Defines a property for the object including the name of the property and the name of the mapped database table column.

194

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch06.fm

The elements of the XML mapping file may have additional attributes to define specific characteristics of the columns it maps. Attributes like type and not-null can be used to specify the data type and the nullability of a column.

Hibernate configuration file

The Hibernate configuration file must reside in the root directory of the

CLASSPATH. It contains configuration values for the Hibernate service and connection details for the database server.

Example 6-8 shows the contents of the

hibernate.cfg.xml

file used in by our sample. The connection details correspond to the IBM Informix JDBC Driver.

Example 6-8 hibernate.cfg.xml

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE hibernate-configuration PUBLIC

"-//Hibernate/Hibernate Configuration DTD 3.0//EN"

"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

<session-factory name="Informix_Session">

<!-- properties -->

<property name="connection.driver_class">

com.informix.jdbc.IfxDriver

</property>

<property name="connection.url">

jdbc:informix-sqli://kodiak:9088/stores_demo:INFORMIXSERVER=demo_on;

</property>

<property name="hibernate.connection.username">

informix

</property>

<property name="hibernate.connection.password">

password

</property>

<property name="dialect">

org.hibernate.dialect.InformixDialect

</property>

<property name="hibernate.show_sql">false</property>

<property name="hbm2ddl.auto">update</property>

<!-- mapping files -->

<mapping resource="State.hbm.xml"/>

</session-factory>

Example 6-9 on page 196 shows the attributes required for an IBM Data Server

Driver for JDBC connection. The configuration file includes the XML mapping

State.hbm.xml

for the State object.

Chapter 6. IBM Informix with Hibernate

195

7884ch06.fm

Draft Document for Review August 23, 2010 10:53 am

Example 6-9 Data Server Driver hibernate.cfg.xml file

<property name="dialect">

org.hibernate.dialect.DB2Dialect

</property>

<property name="connection.driver_class">

com.ibm.db2.jcc.DB2Driver

</property>

<property name="connection.url">

jdbc:ids://kodiak:9089/stores_demo;

</property>

HibernateUtil helper class

The HibernateUtil class is used to interact with the Hibernate service. It performs the operations related to the Hibernate SessionFactory classes that provide an convenient way for the application to access the Hibernate session.

The Java file containing the HibernateUtil helper class is HibernateUtil.java

.

Example 6-10 shows a typical helper class.

Example 6-10 HiberanteUtil.java

import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; public class HibernateUtil {

private static final SessionFactory sessionFactory;

static {

try {

// Creates the SessionFactory from hibernate.cfg.xml

sessionFactory = new Configuration().configure().buildSessionFactory();

}

catch (Throwable ex) {

System.err.println("SessionFactory creation failed." + ex);

throw new ExceptionInInitializerError(ex);

}

}

public static SessionFactory getSessionFactory() {

return sessionFactory;

}

public static void shutdown() {

// Close caches and connection pools

getSessionFactory().close();

}

196

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

}

7884ch06.fm

This class creates a Hibernate session using the parameters specified in the

Hibernate configuration file. Create the class by compiling the

HibernateUtil.java

java file as follows: javac HibernateUtil.java

Java application

The only task required by a Java application to use the Hibernate persistence object is to create a Hibernate Session instance using the

HibernateUtil

helper class. After that, the application can create persistence objects in the same way as it does for any other Java object.

6.3.2 Working with a Hibernate object

Developers must follow an object-orientated methodology when writing applications using the Hibernate API. With Hibernate, the data is represented by the status and properties of an object, not by tables and rows in a relational database.

Storing

When a persistent object is created and saved or stored, an insert operation is performed on the database.

Example 6-11 shows a basic Java code that creates a new

State object using the parameters supplied in the command line. The example creates a Hibernate

Session object using the helper class, and then creates a new State object called myState . The myState.setcode() and myState.setsname() are used to stored the values passed from the command line.

Example 6-11 Create.java

import java.util.*; import org.hibernate.*; import javax.persistence.*; public class create {

public static void main(String[] args) {

Session Session = HibernateUtil.getSessionFactory().openSession();

Transaction Transaction = Session.beginTransaction();

State myState = new State();

myState.setcode(args[0]);

myState.setsname(args[1]);

Chapter 6. IBM Informix with Hibernate

197

7884ch06.fm

Draft Document for Review August 23, 2010 10:53 am

Long stateId = (Long) Session.save(myState);

System.out.println("Stated added: "+myState.getcode()+", "

+myState.getsname());

Transaction.commit();

Session.close();

// Shutting down the application

HibernateUtil.shutdown();

}

}

Example 6-12 shows how the compile line and the output of the

Create.java

sample.

Example 6-12 Create.java

C:\work>javac create.java

C:\work>java create AZ Arizona

Stated added: AZ, Arizona

C:\work>

The Hibernate property hbm2ddl.auto

is set to update

in the configuration file, which means that if the table does not exists in the database, it is automatically created using the table model defined in the XML mapping file.

Example 6-13 shows the schema of the created

States

table and the new row added to the table.

Example 6-13 States table schema

D:\Infx\ids1150>dbaccess stores_demo -

Database selected.

> INFO COLUMNS FOR states;

Column name Type Nulls id int8 no code varchar(255) yes sname varchar(255) yes

> SELECT * FROM states;

198

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

id 1 code AZ sname Arizona

1 row(s) retrieved.

>

7884ch06.fm

The Java object is made persistence, which means saving the state of the object in the database, using the Session.save() Hibernate method and committing the unit of work with Transaction.commit() .

Loading

To retrieve a persistence object from the database server, the application must create a Hibernate session and load the state of the object into the current session.

The process of loading a persistence object can be achieved using several methods:

򐂰 Use Session.load() and Session.get() to retrieve the state of an object from the database using the object identifier as reference. For example, to load the

State object with ID equal to 1, the following code is needed:

State mystateobj = (State) Session.load(State.class,1);

The only difference between the load()

and get()

methods is the returned value. If the object is not found, get()

returns a null

and load()

throws an exception.

򐂰 Use a SQL or HQL query. The Hibernate Query Language which is similar to

SQL but optimized for an object-orientated environment. Methods such as

Session.createQuery() and Session.createCiteria() can be used to load the state of one or multiple objects from the database server. The following command loads all State objects into a list.

List<State> states = session.createQuery("from state").list();

Example 6-14 demonstrates how to load a single object from the database using

the Session.load() method:

Example 6-14 Load.java

import java.util.List; import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.Transaction; import org.hibernate.criterion.*;

Chapter 6. IBM Informix with Hibernate

199

7884ch06.fm

Draft Document for Review August 23, 2010 10:53 am public class load {

public static void main(String[] args) {

Long stateId = null;

Session Session = HibernateUtil.getSessionFactory().openSession();

Transaction Transaction = Session.beginTransaction();

stateId=Long.parseLong(args[0]);

State mystate = (State) Session.load(State.class,stateId);

System.out.println(mystate.getcode() +", " +

mystate.getsname() );

Transaction.commit();

Session.close();

}

}

Example 6-15 shows how to compile and run the previous example. The

application loads the State object identified by the id value passed through the command line.

Example 6-15 Output of load.java

C:\work>javac load.java

C:\work>java load 1

AZ, Arizona

C:\work>java load 2

CA, California

C:\work>

The application can use a HQL query to load all the objects, or entities, of a particular type. All the

State

objects are kept in the

States

table. Example 6-16

shows how to retrieve a list of the

State

entities.

Example 6-16 List.java

C:\work>cat list.java

import java.util.*; import org.hibernate.*; import javax.persistence.*; public class list {

200

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch06.fm

public static void main(String[] args) {

Session newSession = HibernateUtil.getSessionFactory().openSession();

Transaction newTransaction = newSession.beginTransaction();

List states = newSession.createQuery("from State order by id asc").list();

for ( Iterator iter = states.iterator();

iter.hasNext(); ) {

State state = (State) iter.next();

System.out.println(state.getId() +", "+ state.getcode()

+", " + state.getsname() );

}

newTransaction.commit();

newSession.close();

HibernateUtil.shutdown();

}

}

C:\work>javac list.java

C:\work>java list

1, AZ, Arizona

2, CA, California

C:\work>

Updating

Updating an persistence object is the process of changing the state of the object.

There is no specific operation required for this task, the application must load the object, change the object properties, and save it.

Example 6-17 demonstrates how to update individual objects. It uses the

parameters from the command line to change the code

and sname

properties of a

State

object.

Example 6-17 Update.java

C:\work>cat update.java

import java.util.List; import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.Transaction; public class update {

public static void main(String[] args) {

Long stateId = null;

Chapter 6. IBM Informix with Hibernate

201

7884ch06.fm

Draft Document for Review August 23, 2010 10:53 am

Session Session = HibernateUtil.getSessionFactory().openSession();

Transaction Transaction = Session.beginTransaction();

stateId=Long.parseLong(args[0]);

State mystate = (State) Session.load(State.class,stateId);

mystate.setcode(args[1]);

mystate.setsname(args[2]);

Session.save(mystate);

System.out.println("new values: "+ mystate.getcode()+", "+

mystate.getsname() );

Transaction.commit();

Session.close();

}

}

C:\work>javac update.java

C:\work>java update 1 AZ ARIZONA

new values: AZ, ARIZONA

C:\work>

Criteria

Criteria queries are a feature of the Hibernate Query Language that allows to build complex queries using an object-orientated API.

Example 6-18 shows how to update a president object using a HQL criteria to

retrieve the object from the database. The HQL Criteria is created using the name of the class for the object we want to select,

State.class

. A HQL

Restriction,

Restriction.eq("code", args[0])

, is used to specify a filter for the criteria. This restriction specifies that the query should return the objects with a specific code value.

Example 6-18 Update2.java

import java.util.*; import org.hibernate.*; import javax.persistence.*; import org.hibernate.criterion.*; public class update2 {

public static void main(String[] args) {

202

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch06.fm

Session Session = HibernateUtil.getSessionFactory().openSession();

Transaction Transaction = Session.beginTransaction();

Criteria crit = Session.createCriteria(State.class);

crit.add( Restrictions.eq( "code", args[0]) );

List states = crit.list();

for ( Iterator iter = states.iterator(); iter.hasNext(); ) {

State mystate = (State) iter.next();

mystate.setsname(args[1]);

Session.flush();

Long msgId = (Long) Session.save(mystate);

System.out.println("new values: "+ mystate.getcode()+", "+

mystate.getsname() );

}

Transaction.commit();

Session.close();

HibernateUtil.shutdown();

}

}

Example 6-19 shows the output of the example.

Example 6-19 Update2.java output

C:\work>javac update2.java

C:\work>java update2 AZ Arizona

new values: AZ, Arizona

C:\work>

Delete

In the Hibernate framework, delete a persistence object means to make the object transient. A transient object is a typical Java object but the state of the object is not stored anywhere, which means that the object will only exists during the life of the application.

An object can be deleted using the Session.delete()

method. Example 6-20

demonstrates how to use the Session.delete() method:

Example 6-20 delete.java

C:\work>cat delete.java

import java.util.List; import org.hibernate.HibernateException;

Chapter 6. IBM Informix with Hibernate

203

7884ch06.fm

Draft Document for Review August 23, 2010 10:53 am import org.hibernate.Session; import org.hibernate.Transaction; public class delete {

public static void main(String[] args) {

Long stateId = null;

Session Session = HibernateUtil.getSessionFactory().openSession();

Transaction Transaction = Session.beginTransaction();

stateId=Long.parseLong(args[0]);

State mystate = (State) Session.load(State.class,stateId);

Session.delete(mystate);

System.out.println( "Object deleted");

Transaction.commit();

Session.close();

}

}

C:\work>javac delete.java

C:\work>java delete 2

Object deleted

C:\work>java list

1, AZ, Arizona

C:\work>

One of the main features of using Hibernate is that abstracts the JDBC layer from the application. This means that applications written using the Hibernate API are not tied to a specific JDBC driver or relational database server.

All the examples presented in this section can be run using any of the two

Informix JDBC drivers available, IBM Informix JDBC Driver or IBM Data Server

Driver for JDBC. Refer to the “Hibernate configuration file” on page 189 for information regarding how to switch between JDBC drivers.

For more information regarding how to develop using the Hibernate API, refer to the Hibernate Reference Documentation at: http://docs.jboss.org/hibernate/core/3.3/reference/en/html/objectstate.html

204

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch06.fm

6.3.3 Using annotations

Java annotations is a feature added into the Java 5 Software Development Kit

(SDK) that allows the inclusion of special annotations within the Java source code to express metadata relating to program objects.

Hibernate supports Java annotations through the use of the Hibernate

Annotations Extensions. These extensions allow to include the definition of specific Hibernate properties such as configuration properties or object mappings properties directly into the Java code.

With annotations, there is no need for a specific XML mapping file to link the Java objects with the database objects.

Example 6-21 shows the definition of the

State object using Hibernate annotations. Annotations such as @Entity , @Table or @Column define the mapping information needed to persist the Java objects into the database.

Example 6-21 State.java with annotations

import javax.persistence.*;

@Entity

@Table(name="States")

public class State {

private Long id;

private String code;

private String sname;

public State() {}

public State(String text, String text2) {

this.code = text;

this.sname = text2;

}

@Id

@GeneratedValue(strategy=GenerationType.IDENTITY )

@Column(name="id")

public Long getId() {

return id;

}

private void setId(Long id) {

this.id = id;

}

@Column(name="code", length=2, nullable=false)

public String getcode() {

return code;

}

public void setcode(String text) {

Chapter 6. IBM Informix with Hibernate

205

7884ch06.fm

Draft Document for Review August 23, 2010 10:53 am

this.code = text;

}

@Column(name="sname", length=15, nullable=false)

public String getsname() {

return sname;

}

public void setsname(String text) {

this.sname = text;

}

}

Because all the information required to map the objects is specify as annotations, there is no need to include a <mapping> section in the Hibernate configuration file, hibernate.cfg.xml

.

When using annotations, the HibernateUtil helper class,

HibernateUtil.java

, uses the

AnnotationConfiguration()

interface to retrieve the Hibernate

properties and the metadata definition from the object class. Example 6-22

shows the

HibernateUtil.java

file used to create a SessionFactory for the

State.class

object.

Example 6-22 HibernateUtil.java for annotations

import org.hibernate.SessionFactory;

import org.hibernate.cfg.AnnotationConfiguration;

public class HibernateUtil { private static final SessionFactory sessionFactory;

static {

try {

// Create the SessionFactory from hibernate.cfg.xml

sessionFactory = new AnnotationConfiguration()

.configure()

.addAnnotatedClass(State.class)

.buildSessionFactory();

} catch (Throwable ex) {

System.err.println("Initial SessionFactory creation failed." + ex);

throw new ExceptionInInitializerError(ex);

}

}

public static SessionFactory getSessionFactory() {

return sessionFactory;

}

public static void shutdown() {

206

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

getSessionFactory().close();

}

}

7884ch06.fm

There is no need to change the code for the Java applications that use the persistence object, the process for manipulate the objects is the same as when using the XML mapping files than when using Hibernate annotations.

A description of all the Hibernate annotation extensions can found in the

Hibernate Reference Documentation at http://docs.jboss.org/hibernate/stable/annotations/reference/en/html_single/#en tity-hibspec

Chapter 6. IBM Informix with Hibernate

207

7884ch06.fm

Draft Document for Review August 23, 2010 10:53 am

208

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch07.fm

7

Chapter 7.

Working with the IBM

Informix OLE DB Provider

This chapter describes the IBM Informix OLE DB provider. we discuss the following topics:

򐂰 Description of the Informix OLE DB provider

򐂰 Setup and Configuration

򐂰 Application development using the OLE DB provider

򐂰 Typical errors and how to enable tracing

© Copyright IBM Corp. 2010. All rights reserved.

209

7884ch07.fm

Draft Document for Review August 23, 2010 10:53 am

7.1 IBM Informix OLE DB Provider

Informix OLE DB Provider is a Universal Data Access component that enables

IBM Informix Server access from OLE DB consumers.

Microsoft OLE DB is a specification for a set of interfaces designed to expose data from a variety of sources (relational and non-relational). OLE DB uses the

Component Object Model (COM) to accomplish this.

You can use IBM Informix OLE DB Provider to enable client applications, such as

ActiveX Data Object (ADO) applications and Web pages, to access data on an

IBM Informix database server.

Table 7-1 shows the name and COM class ID of the IBM Informix OLE DB

Provider.

Table 7-1 COM class ID

Name DLL

ifxoledbc iifxoledbc.dll

CLSID

{A6D00422-FD6C-11D0-8043-00A0C90F1C59}

Table 7-2 lists the Informix database servers that support IBM Informix OLE DB

Provider.

Table 7-2 Supported databases

Database Server

IBM Informix

IBM Informix Extended Parallel Server

IBM Informix Online

Versions

10.0,11.10,11.50

8.50 and higher

5.20 and higher

7.2 Setup and configuration

In this section we discuss how to set up the OLE DB provider and how to perform basic connectivity tests.

7.2.1 Installation and setup

The IBM Informix OLE DB provider is only included in the Windows version of

IBM Informix Client SDK. The OLE DB provider is selected by default in the

210

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch07.fm

Client SDK installation. During the install process, the provider is automatically registered on the Windows registry as a command component.

The default install directory is C:\Program Files\IBM\Informix\Client-SDK.

The INFORMIXDIR environment variable should point to the directory where the product was installed. The provider shared library, ifxoledbc.dll, is located in

%INFORMIXDIR%\bin directory.

Because the OLE DB provide is registered, by default, during the Client SDK installation, manual registration is usually not required. However, in cased needed, you can manually register the OLE DB provider using the Microsoft regsvr32.exe

tool by running the following command in a command prompt: regsvr32.exe %INFORMIXDIR%\bin\ifxoledbc.dll

Note: On a Windows x64 (64-bit) there are two versions of the regsvr32.exe

tool:

򐂰 The 32-bit version is located in C:\WINDOWS\SysWOW64

򐂰 The 64-bit version is located in C:\WINDOWS\System

Use the correct version when registering the OLE DB provider, otherwise, the application would fail to load the shared library due to a mismatched version.

After installation, you must run the script coledbp.sql

on the database server against the sysmaster database as user

informix

to add the tables and functions required by the provider to work.

The script coledbp.sql

is located in the

%INFORMIXDIR%\etc

directory. If you want to remove the support functions and tables, use the doledbp.sql

script located in the same directory.

7.2.2 Verifying connectivity

Informix Client SDK does not contain any specific tool to test the OLE DB provider.

Internally, the IBM Informix OLE DB Provider uses the same Informix connection libraries as ESQL/C or ODBC. You can test the basic connection details for your database server using the

Ilogin

tool included in the

%INFORMIXDIR%\bin directory.

Chapter 7. Working with the IBM Informix OLE DB Provider

211

7884ch07.fm

Draft Document for Review August 23, 2010 10:53 am

Testing using VBScript

VBScript is a scripting language included as part of Windows operating system.

It provide access to ADO objects through COM and can be use to test if the IBM

Informix OLE DB provider is properly configured.

VBScripts are text files with a vbs extension which are automatically loaded and executed by the Visual Basic runtime.

Example 7-1 shows a simple VBS script which loads the Informix OLE DB

provider and selects a single row from the database.

Example 7-1 Connect.vbs

' ---- Test_Ifx.vbs ----

On Error Resume Next args = WScript.Arguments.Count

If args < 1 then

WScript.Echo "usage: connect.vbs Connection_string"

WScript.Echo " e.g.: connect.vbs ""Data Source=stores_demo@demo_on;User

ID=informix;Password=password;"""

WScript.Quit

end If set conn=createobject("ADODB.Connection")

conn.provider = "Ifxoledbc" conn.connectionstring = WScript.Arguments.Item(0)

conn.open

If Err then

WScript.Echo "Error!! "+conn.Errors(0).Description

Else

WScript.Echo "Connected"

conn.close

End If

' ---- Test_Ifx.vbs ----

Example 7-2 shows how run the

Connect.vbs

script with a data source string as the parameter to test the database connectivity.

Example 7-2 Output of Connect.vbs

c:\work>connect.vbs

usage: connect.vbs Connection_string

e.g.: connect.vbs "Data Source=stores_demo@demo_on;User

ID=informix;Password=password;" c:\work>connect.vbs "Data Source=stores_demo@demo_on;User

ID=informix;Password=password;"

212

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch07.fm

Connected c:\work>connect.vbs "Data Source=stores_demo@demo_on;User

ID=informix;Password=invalid;"

Error!! EIX000: (-951) Incorrect password or user informix@dubito is not known on the database server.

Rowset Viewer

Another way to test the Informix OLE DB provider is using the Rowset Viewer.

The Rowset Viewer is included with the Microsoft Data Access Components

(MDAC) 2.8 Software Development Kit (SDK) which can be download from the following location http://www.microsoft.com/downloads/details.aspx?FamilyID=6c050fe3-c795-4b7d-b03

7-185d0506396c

To test the OLE DB provider using the Rowset tool, perform the following steps:

򐂰 Run the Rowset tool .

򐂰

Select File

Full Connect.

򐂰 In the Provider field choose Ifxoledbc.

򐂰

In the DataSource field, enter the database as server name you want to connect to, for example, stores_demo@demo_on.

򐂰 Press the OK.

Figure 7-1 shows the Full Connect dialog box.

Figure 7-1 Rowset Full Connect dialog

Chapter 7. Working with the IBM Informix OLE DB Provider

213

7884ch07.fm

Draft Document for Review August 23, 2010 10:53 am

You also can use Rowset Viewer to run SQL statements against the database server. To execute a SQL statement, write the SQL text in the Rowset pane and click .

Figure 7-2 shows the Rowset Viewer running the SQL statement s

elect * from state .

Figure 7-2 Rowset Viewer SQL Statement

7.3 Developing an OLE DB application

This section describes the interfaces implemented in the Informix OLE DB

Provider and demonstrates how to perform basic database operations.

In this section we discuss:

򐂰 Supported interfaces in the Informix OLE DB Provider

򐂰 Parameters used in the connection string

򐂰 Data type mapping

򐂰 Typical database operations

214

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch07.fm

7.3.1 Supported interfaces

A OLE DB application creates objects based on ADO interfaces to perform

operations against a database server. Table 7-3 lists a few ADO interfaces

implemented in the IBM Informix OLE DB Provider as examples. For a complete list, refer to http://publib.boulder.ibm.com/infocenter/idshelp/v115/topic/com.ibm.oledb.doc/s ii-xa-21954.htm#sii-xa-21954

Table 7-3 OLE DB supported interfaces

Interface Description

IAccessor Provides methods for accessor management

IColumnsInfo

ICommand

IDBCreateCommand

IDBCreateSession

Information about columns of a rowset or prepared command

Execute commands

Obtain a new command.

Obtain a new session.

IDBDataSourceAdmin Create, destroy, and modify a data source objects

IDBProperties Gets and sets the values of properties on the data source object or enumerator and to get information about all properties supported by the provider.

IErrorLookup Used by OLE DB error objects to determine the values of the error message, source, Help file path, and context ID based on the return code and a provider-specific error number.

Obtaining an interface pointer to the data source object.

IGetDataSource

IRowsetIdentity

ISessionProperties

Indicates row instance identity is implemented on the rowset and enables testing for row identity.

Returns information about the properties a session supports and the current settings of those properties.

ITransaction Used to commit, abort, and obtain status information about transactions.

7.3.2 Connecting to database

In this section we describe the connection string options with the IBM Informix

OLE DB Provider.

Chapter 7. Working with the IBM Informix OLE DB Provider

215

7884ch07.fm

Draft Document for Review August 23, 2010 10:53 am

The connection details for the database server are passed to the OLE DB provider using a connection string. If the

Provider

attribute of the Connection object is not set, you must include the

provider

keyword as part of the connection string to specify the name of the Informix OLE DB provide,

ifxoledbc.

For example: connStr="Provider=Ifxoledbc;Data Source=stores_demo@demo_on"

Table 7-4 describes the specific connection string attributes for the Informix OLE

DB Provider.

Table 7-4 Connection String attributes

Keyword Description

Data Source

User ID

Database and Informix server to connect to.

The syntax for the Data Source parameter is database@server

If

@server

is not specified, the default database server is used (corresponding to the value specified by the client’s INFORMIXSERVER registry entry or environment variable).

The user ID used to connect to the Informix server

Password

Persist Security Info

Client_locale

Db_locale

UNICODE decasr8

RSASWS or

REPORTSTRINGASWSTRING

FBS or FETCHBUFFERSIZE

The password for the user ID

Specifies whether the data source can keep authentication information such as the password

The client locale for the application which correspond to the locale used by the Windows OS

The database locale. Locale used when the database was created

Indicates whether to use IBM Informix GLS Unicode

Controls how the codeset conversion to Unicode is done

If set, floating point numbers with a scale greater than 30 are returned as DBTYPE_R8

Enables you to control the data mapping for wide strings

The size in bytes of the buffer size used to send data to or from the database. Minimum value is 4096,

Maximum 32767. Default is 4096

A typical connection string for the IBM Informix OLE DB Provider looks like:

216

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch07.fm

Data Source=stores_demo@demo_on; User ID=informix; Password=password; Persist

Security Info=True; CLIENT_LOCALE=en_US.CP1252; DB_LOCALE=en_US.819

The connection details about the Informix server must be stored in the registry using the Setnet32 tool included in Informix Client SDK.

7.3.3 Type mapping

The Informix OLE DB provider supports all the Informix data types, both build-in and extended.

Table 7-5 lists the mappings between the standards OLE DB data types and

specific Informix OLE DB types.

Table 7-5 Informix specific type mapping table

Informix SQL Informix OLE DB Provider

BIGINT

BIGSERIAL

DBTYPE_I8

DBTYPE_I8

BLOB

BOOLEAN

BYTE

CLOB

DATETIME

DBTYPE_BYTES

DBTYPE_BOOL

DBTYPE_BYTES

DBTYPE_STR

DBTYPE_DBDATE, DBTYPE_DBTIME,

DBTYPE_DBTIMESTAMP

DECIMAL

DISTINCT

FLOAT

INT8

INTERVAL

LIST

LVARCHAR

MONEY (p<=19 s<=4

MONEY (p>19 s<>4)

DBTYPE_NUMERIC

Same as underlying type

DBTYPE_R8

DBTYPE_I8

DBTYPE_STR if mapped as a string

DBTYPE_Ix (8,4,2 or 1) if mapped as a numeric

DBTYPE_VARIANT

DBTYPE_STR

DBTYPE_CY

DBTYPE_NUMERIC

Chapter 7. Working with the IBM Informix OLE DB Provider

217

7884ch07.fm

Draft Document for Review August 23, 2010 10:53 am

Informix SQL

MULTISET

Named ROW

NCHAR

OPAQUE

SERIAL

SERIAL8

SET

TEXT

Unnamed ROW

Informix OLE DB Provider

DBTYPE_VARIANT

DBTYPE_VARIANT

DBTYPE_STR

DBTYPE_BYTES

DBTYPE_I4

DBTYPE_I8

DBTYPE_VARIANT

DBTYPE_STR

DBTYPE_VARIANT

There are three OLE DB Provider date and time data types that map to one

DATETIME Informix SQL data type. Which one to use depends on the precision

of the data type desired. See Table 7-6 for a summary.

Table 7-6 DATETIME OLE DB mapping table

Informix OLE DB Provider Date and time precision

DBTYPE_DBDATE

DBTYPE_DBTIME

Day to day, month to day, month to month, year to day, year to month, and year to year

Hour to hour, hour to minute, hour to second, minute to minute, minute to second, and second to second

DBTYPE_DBTIMESTAMP Day to fraction, day to hour, day to minute, and day to second

Fraction to fraction, hour to fraction, and minute to fraction

Month to fraction, month to hour, month to minute, and month to second

Second to fraction

Year to fraction, year to hour, year to minute, and year to second

For a complete list of all the data type mapping, refer to the Data Type Mappings section of the IBM Informix OLE DB Guide at http://publib.boulder.ibm.com/infocenter/idshelp/v115/topic/com.ibm.oledb.doc/u sing990839.htm#using990839

218

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch07.fm

7.3.4 Cursors

An ADO application uses cursors to move among the data returned by a recordset. ADO defines four types of cursors:

򐂰

Forward-Only ( adOpenForwardOnly

):

Provides a copy of the records at the time the Recordset was created. This is the default cursor type of ADO.

򐂰

Static ( adOpenStatic

):

Provides a static copy of the records.

򐂰

Dynamic ( adOpenDynamic

):

Provides a real-time copy of the records, new and altered records by other users are also included.

򐂰

Keyset ( adOpenKeyset

):

Provides a updateable copy of the records at the time the Recordset was created. Only existing records are included.

The IBM Informix OLE DB Provider supports all these cursor types with some limitations regarding the use of extended data types and location of the cursor

(Client or Server side). For example:

򐂰

Updates of tables with extended data types are not allowed with Client-side scrollable cursors.

򐂰 Server-side scrollable cursors are not supported with simple large objects

(BYTE and TEXT) or collections.

򐂰

ROWIDs (internal columns added by the Informix server on non fragmented tables) are required on tables bookmarks and updates.

Refer to the IBM Informix OLE DB Provider Programmer's Guide for a complete list of these caveats: http://publib.boulder.ibm.com/infocenter/idshelp/v115/topic/com.ibm.oledb.doc/s ii-using-29878.htm#sii-using-29878

7.3.5 Typical database operations

In this section we provide examples of how to use the IBM Informix OLE DB

Provider to perform typical database operations against an Informix database.

We cover operations such as executing SQL statements, selecting data, or how to handle errors coming from the OLE DB provider.

for the general information about OLE DB architecture and programming, refer to the Microsoft’s OLE DB Programer's Guide at

Chapter 7. Working with the IBM Informix OLE DB Provider

219

7884ch07.fm

Draft Document for Review August 23, 2010 10:53 am http://msdn.microsoft.com/en-us/library/ms713643%28v=VS.85%29.aspx

Command

The execution of the SQL commands using an OLE DB provider is accomplished through the ICommand interface.

The application has to perform the following steps in order to execute a SQL statement:

1. Call

QueryInterface

for

IDBCreateCommand

to check if commands are supported in the session.

2. Call IDBCreateCommand::CreateCommand to create the command.

3. Call

ICommandText::SetCommandText

to specify the SQL statement for the command.

4. Call ICommand::Execute to execute the SQL statement.

Example 7-3 on page 221 demonstrates how to connect to the database and

execute an UPDATE statement. In this example, we use the following operations and interfaces:

򐂰

Connect to the database a. Initialize common property options (prompt, DSN, user, and password).

b. Get an Interface for properties:

InterfacepIDBInitialize->QueryInterface(IID_IDBProperties) pIDBProperties->SetProperties() c. Get an Interface for creating session object: pIDBInitialize->QueryInterface(IID_IDBCreateSession) d. Create a session object: pCreateSession->CreateSession()

򐂰

Create a command object: e. Get an Interface for creating command object: pSession->QueryInterface(IID_IDBCreateCommand) f. Create command object and get ICommandText

Interface: pCreateCommand->CreateCommand()

򐂰 Set the CommandText for the command object: pCommandText->SetCommandText()

򐂰

Execute the command: pCommandText->Execute()

򐂰 Clean up.

220

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch07.fm

Example 7-3 Command.cpp

#define UNICODE

#define _UNICODE

#include <oledb.h>

#include <oledberr.h>

#include <msdaguid.h>

#include <msdadc.h>

#include <comdef.h>

#include <windows.h>

#include <stdio.h>

// CLSID For IBM-Informix Client Side OLE DB Provider const GUID CLSID_IFXOLEDBC= {0xa6d00422, 0xfd6c, 0x11d0,

{0x80, 0x43, 0x0, 0xa0, 0xc9, 0xf, 0x1c, 0x59}};

#define CHECK(hr) if (((HRESULT)(hr)) < 0) {printf( "Error"); return(hr);} int main()

{

HRESULT hr = S_OK;

IDBInitialize *pIDBInitialize;

IDBCreateSession *pCreateSession;

IDBCreateCommand *pCreateCommand;

IUnknown *pSession;

ICommandText *pCommandText;

IDBProperties *pIDBProperties;

DBPROP InitProperties[4];

DBPROPSET rgInitPropSet;

_bstr_t bstrDsnName = "stores_demo@demo_on";

_bstr_t bstrUserName = "informix";

_bstr_t bstrPassWord = "password";

_bstr_t bstrCommand = (WCHAR *) L"UPDATE state SET sname = 'California'

WHERE code = 'CA'";

CoInitialize( NULL );

// Instantiate a data source object

CHECK( hr = CoCreateInstance((REFCLSID) CLSID_IFXOLEDBC, NULL,

CLSCTX_INPROC_SERVER, IID_IDBInitialize, (void **) &pIDBInitialize))

// Set all Properties, Prompt, DSN, User and Password

// Initialize common property options.

for (ULONG i = 0; i < 4; i++ )

{

VariantInit(&InitProperties[i].vValue);

InitProperties[i].dwOptions = DBPROPOPTIONS_REQUIRED;

InitProperties[i].colid = DB_NULLID;

InitProperties[1].vValue.vt = VT_BSTR;

}

InitProperties[0].dwPropertyID = DBPROP_INIT_PROMPT;

Chapter 7. Working with the IBM Informix OLE DB Provider

221

7884ch07.fm

Draft Document for Review August 23, 2010 10:53 am

InitProperties[0].vValue.vt = VT_I2;

InitProperties[0].vValue.iVal = DBPROMPT_NOPROMPT;

InitProperties[1].dwPropertyID = DBPROP_INIT_DATASOURCE;

InitProperties[1].vValue.bstrVal = bstrDsnName;

InitProperties[2].dwPropertyID = DBPROP_AUTH_USERID;

InitProperties[2].vValue.bstrVal = bstrUserName;

InitProperties[3].dwPropertyID = DBPROP_AUTH_PASSWORD;

InitProperties[3].vValue.bstrVal = bstrPassWord;

rgInitPropSet.guidPropertySet = DBPROPSET_DBINIT;

rgInitPropSet.cProperties = 4;

rgInitPropSet.rgProperties = InitProperties;

// Get initialization properties.Interface

CHECK (hr = pIDBInitialize->QueryInterface(IID_IDBProperties,

(void**) &pIDBProperties))

CHECK(hr = pIDBProperties->SetProperties( 1, &rgInitPropSet))

CHECK( hr = pIDBProperties->Release())

// Connect to the Database Server

CHECK(hr = pIDBInitialize->Initialize())

// Get an Interface for creating Session Object

CHECK( hr = pIDBInitialize->QueryInterface(IID_IDBCreateSession,

(void **) &pCreateSession))

// Create a Session Object

CHECK( hr = pCreateSession->CreateSession(NULL, IID_IUnknown,

(IUnknown **) &pSession))

CHECK( hr = pCreateSession->Release())

// Create Command Object

// Get an Interface for creating Command Object

CHECK( hr = pSession->QueryInterface( IID_IDBCreateCommand,

(void **) &pCreateCommand))

// Create Command Object and get ICommandText Interface

CHECK( hr = pCreateCommand->CreateCommand(NULL, IID_ICommandText,

(IUnknown **) &pCommandText ))

CHECK( hr = pCreateCommand->Release())

// Set the CommandText

CHECK( hr = pCommandText->SetCommandText(DBGUID_DBSQL, bstrCommand))

// Executing the Command

CHECK( hr = pCommandText->Execute( NULL, IID_NULL, NULL, NULL, NULL))

printf( "Row Updated");

// Cleanup

pCommandText->Release();

pCommandText = NULL;

pSession->Release();

pSession = NULL;

pIDBInitialize -> Uninitialize();

pIDBInitialize -> Release();

pIDBInitialize = NULL;

222

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch07.fm

CoUninitialize();

return(0);

}

Example 7-4 describes how to compile and run Example 7-3 on page 221. The

connection string is constructed inside the program, so there are not passing any command line parameters.

Example 7-4 Output of Command.cpp

C:\work>cl /EHsc /nologo command.cpp command.cpp

C:\work>command

Row Updated

C:\work>

Rowset

A Rowset is a set of rows and each row has a number of columns of data.

Rowsets are the main OLE DB objects used to exposes data from a data source.

You can create rowsets object with the following methods:

򐂰

Explicitly create a rowset by calling

IOpenRowset::OpenRowset()

.

򐂰 Execute an SQL statement such as SELECT that returns rows with a

ICommand:Execute method.

򐂰

Execute any method that returns a rowset or a schema rowset, for example,

ColumnsRowset::GetColumnsRowset

or

IDBSchemaRowset::GetRowset.

Example 7-5 on page 224 demonstrates how to create a rowset object and

retrieve metadata information. The operations and interfaces to initialize the session and connect to the database are always the same in a OLE DB application. This example also does the following operations:

򐂰 Connect to the database

򐂰

Create a Command Object

򐂰 Create a OpenRowSet Object pCreateCommand->QueryInterface(IID_IOpenRowset) pIOpenRowset->OpenRowset()

򐂰 Obtain access to the IColumnsInfo interface, from the rowset object pRowset->QueryInterface(IID_IColumnsInfo)

򐂰

Retrieve the Column Information

Chapter 7. Working with the IBM Informix OLE DB Provider

223

7884ch07.fm

Draft Document for Review August 23, 2010 10:53 am pColumnsInfo->GetColumnInfo()

򐂰 Cleanup

Example 7-5 Rowset.cpp

#define UNICODE

#define _UNICODE

#include <oledb.h>

#include <oledberr.h>

#include <msdaguid.h>

#include <msdadc.h>

#include <comdef.h>

#include <windows.h>

#include <stdio.h>

// CLSID For IBM-Informix Client Side OLE DB Provider const GUID CLSID_IFXOLEDBC= {0xa6d00422, 0xfd6c, 0x11d0,

{0x80, 0x43, 0x0, 0xa0, 0xc9, 0xf, 0x1c, 0x59}};

#define CHECK(hr) if (((HRESULT)(hr)) < 0) {printf( "Error"); return(hr);} int main()

{

HRESULT hr = S_OK;

IDBInitialize *pIDBInitialize;

IUnknown *pSession;

ITransactionJoin *pITransactionJoin;

ICommandText *pCommandText;

IOpenRowset *pIOpenRowset;

IColumnsInfo *pColumnsInfo;

IDBProperties* pIDBProperties;

DBPROP InitProperties[4];

DBPROPSET rgInitPropSet;

IDBCreateSession *pCreateSession = NULL;

IDBCreateCommand *pCreateCommand = NULL;

IRowset *pRowset = NULL;

DBID TableID;

DBPROPSET rgPropSets[1];

DBCOLUMNINFO *pDBColumnInfo;

WCHAR *pStringsBuffer;

ULONG lNumCols; int i=0;

_bstr_t bstrDsnName = "stores_demo@demo_on";

_bstr_t bstrUserName = "informix";

_bstr_t bstrPassWord = "password";

_bstr_t TableName = L"customer";

CoInitialize( NULL );

// Instantiate a data source object

224

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch07.fm

CHECK( hr = CoCreateInstance((REFCLSID) CLSID_IFXOLEDBC, NULL,

CLSCTX_INPROC_SERVER, IID_IDBInitialize, (void **) &pIDBInitialize))

// Set all Properties, Prompt, DSN, User and Password

// Initialize common property options.

for (ULONG i = 0; i < 4; i++ )

{

VariantInit(&InitProperties[i].vValue);

InitProperties[i].dwOptions = DBPROPOPTIONS_REQUIRED;

InitProperties[i].colid = DB_NULLID;

InitProperties[1].vValue.vt = VT_BSTR;

}

InitProperties[0].dwPropertyID = DBPROP_INIT_PROMPT;

InitProperties[0].vValue.vt = VT_I2;

InitProperties[0].vValue.iVal = DBPROMPT_NOPROMPT;

InitProperties[1].dwPropertyID = DBPROP_INIT_DATASOURCE;

InitProperties[1].vValue.bstrVal = bstrDsnName;

InitProperties[2].dwPropertyID = DBPROP_AUTH_USERID;

InitProperties[2].vValue.bstrVal = bstrUserName;

InitProperties[3].dwPropertyID = DBPROP_AUTH_PASSWORD;

InitProperties[3].vValue.bstrVal = bstrPassWord;

rgInitPropSet.guidPropertySet = DBPROPSET_DBINIT;

rgInitPropSet.cProperties = 4;

rgInitPropSet.rgProperties = InitProperties;

// Get initialization properties.Interface

CHECK (hr = pIDBInitialize->QueryInterface(IID_IDBProperties,

(void**) &pIDBProperties))

CHECK(hr = pIDBProperties->SetProperties( 1, &rgInitPropSet))

CHECK( hr = pIDBProperties->Release())

// Connect to the Database Server

CHECK(hr = pIDBInitialize->Initialize())

// Get an Interface for creating Session Object

CHECK( hr = pIDBInitialize->QueryInterface(IID_IDBCreateSession,

(void **) &pCreateSession))

// Create a Session Object

CHECK( hr = pCreateSession->CreateSession(NULL, IID_IUnknown,

(IUnknown **) &pSession))

CHECK( hr = pCreateSession->Release())

// Create Command Object

// Get an Interface for creating Command Object

CHECK( hr = pSession->QueryInterface( IID_IDBCreateCommand,

(void **) &pCreateCommand))

// Create Command Object and get ICommandText Interface

CHECK( hr = pCreateCommand->CreateCommand(NULL, IID_ICommandText,

(IUnknown **) &pCommandText ))

CHECK( hr = pCreateCommand->Release())

// Create a OpenRowSet

CHECK( hr = pCreateCommand->QueryInterface( IID_IOpenRowset,

Chapter 7. Working with the IBM Informix OLE DB Provider

225

7884ch07.fm

Draft Document for Review August 23, 2010 10:53 am

(void **)&pIOpenRowset ))

TableID.eKind = DBKIND_NAME;

TableID.uName.pwszName = TableName;

CHECK( hr = pIOpenRowset->OpenRowset( NULL, &TableID, NULL, IID_IRowset,

0, rgPropSets, (IUnknown **)&pRowset

))

// Obtain access to the IColumnsInfo inteface, from the Rowset object

CHECK( hr = pRowset->QueryInterface(IID_IColumnsInfo, (void ** )

&pColumnsInfo))

// Retrieve the Column Information

CHECK( hr = pColumnsInfo->GetColumnInfo( &lNumCols, &pDBColumnInfo,

&pStringsBuffer))

wprintf( L"\nTable : %s\nColumns :%d\nName\t\tType\tLength",

TableID.uName.pwszName, lNumCols); for ( i=0; i<(int)lNumCols; ++i)

{

wprintf( L"\n%s\t%d\t%ld", (pDBColumnInfo+i)->pwszName,

(pDBColumnInfo+i)->wType, (pDBColumnInfo+i)->ulColumnSize);

}

// Free the Column Information Interface

CHECK( (hr = pColumnsInfo->Release()))

// Cleanup

pCommandText->Release();

pCommandText = NULL;

pSession->Release();

pSession = NULL;

pIDBInitialize -> Uninitialize();

pIDBInitialize -> Release();

pIDBInitialize = NULL;

CoUninitialize();

return(0);

}

Example 7-6 shows the name, type, and length columns of the customer table.

Example 7-6 Output of Rowset.cpp

C:\work>cl /EHsc /nologo rowset.cpp

rowset.cpp

C:\work>rowset

Table : customer

Columns :7

Name Type Length

226

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am customer_num 3 4 customer_type 129 1 customer_name 129 32767 customer_loc 3 4 contact_dates 129 32767 cust_discount 131 19 credit_status 129 1

C:\work>

7884ch07.fm

Large objects

Large object (simple and smart) do not require any special handling when using the Informix OLE DB provider.

Smart Large Objects (BLOB and TEXT) support the ADO GetChunk() and

AppendChunk() methods.

Example 7-7 demonstrates how to retrieve a CLOB column using

GetChunk() from the ADO library in C++. This example fetches the first three rows of the

catalog table from the sample stores_demo database and displays the data for the catalog_number and advert_descr columns.

Example 7-7 Select.cpp

#include <stdio.h>

#include <afxdisp.h>

#import "c:\program files\common files\system\ado\msado15.dll" rename

("EOF","adoEOF") no_namespace

#define CREATEiNSTANCE(sp,riid) { HRESULT _hr =sp .CreateInstance( __uuidof( riid

) ); \

if (FAILED(_hr)) _com_issue_error(_hr); }

#define RsITEM(rs,x) rs->Fields->Item[_variant_t(x)]->Value

#define UC (char *) struct InitOle {

InitOle() { ::CoInitialize(NULL); }

~InitOle() { ::CoUninitialize(); }

} _init_InitOle_; void main(){

_RecordsetPtr spRS;

_ConnectionPtr spCON;

_variant_t varBLOB;

long lDataLength = 0;

int nrows=3;

Chapter 7. Working with the IBM Informix OLE DB Provider

227

7884ch07.fm

Draft Document for Review August 23, 2010 10:53 am

try{

CREATEiNSTANCE(spCON,Connection);

spCON->Provider="ifxoledbc";

spCON->ConnectionString = L"Data Source=stores_demo@demo_on;"

L"User ID=informix; Password=password;";

// Connect to the database

spCON->Open( "", "", "", -1 );

CREATEiNSTANCE(spRS,Recordset)

spRS->PutRefActiveConnection( spCON );

spRS->Open(_bstr_t("catalog"),vtMissing, adOpenForwardOnly,

adLockOptimistic,adCmdTable);

while( (spRS->adoEOF == false) && nrows>0 ){

nrows--;

printf("catalog_num = %s\n", UC _bstr_t(RsITEM(spRS,"catalog_num")));

// Get the size of the large object

lDataLength = spRS->Fields->Item["advert_descr"]->ActualSize;

if(lDataLength > 0) {

// Call GetChunk to retrieve the Blob data

VariantInit(&varBLOB);

varBLOB = spRS->Fields->Item["advert_descr"]->GetChunk(lDataLength);

printf("advert_descr = %s\n", UC _bstr_t(varBLOB));

}

// Move the cursor to the next row

spRS->MoveNext();

}

spRS->Close();

spCON->Close();

}

catch( _com_error &e){

_bstr_t bstrSource(e.Source());

_bstr_t bs = _bstr_t(" Error: ") + _bstr_t(e.Error()) +

_bstr_t(" Msg: ") + _bstr_t(e.ErrorMessage()) +

_bstr_t(" Description: ") + _bstr_t(e.Description());

printf("Error %s\n", bs);

}

}

#undef UC

Example 7-8 shows the content of the output.

Example 7-8 Output of Select.cpp

C:\work>cl /EHsc /nologo select.cpp /DWINVER=0x0600 select.cpp

C:\work>select

catalog_num = 10001

228

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch07.fm

advert_descr = Brown leather. Specify first baseman's or infield/outfield style. Specify right- or left-handed.

catalog_num = 10002 catalog_num = 10003

C:\work>

Errors

The Informix OLE DB Provider supports the

ISupportErrorInfo

interface.

Applications can retrieve information about an OLE DB error using this interface.

Methods like IErrorRecords->GetErrorInfo() , IErrorInfo->GetDescription() and IErrorInfo->GetSource() are fully supported by the Informix OLE DB provider.

Example 7-9 Illustrates how to use these methods. This example retrieves the

error information directly after the IDBInitialize->Initialize() function call.

Because error handling should be done after every use of an interface function, it is a good practice to create an error handle routine to avoid code redundancy.

Example 7-9 Errorinfo.cpp

#define UNICODE

#define _UNICODE

#include <oledb.h>

#include <oledberr.h>

#include <msdaguid.h>

#include <msdadc.h>

#include <comdef.h>

#include <windows.h>

#include <stdio.h>

// CLSID For IBM-Informix Client Side OLE DB Provider const GUID CLSID_IFXOLEDBC= {0xa6d00422, 0xfd6c, 0x11d0,

{0x80, 0x43, 0x0, 0xa0, 0xc9, 0xf, 0x1c, 0x59}};

#define CHECK(hr) if (((HRESULT)(hr)) < 0) {printf( "Error"); return(hr);}

HRESULT GetDetailedErrorInfo(

HRESULThresult,

IUnknown *pBadObject,

GUID IID_BadIntereface); int main()

{

HRESULT hr = S_OK;

IDBInitialize *pIDBInitialize;

Chapter 7. Working with the IBM Informix OLE DB Provider

229

7884ch07.fm

Draft Document for Review August 23, 2010 10:53 am

IUnknown *pSession;

IDBProperties* pIDBProperties;

DBPROP InitProperties[4];

DBPROPSET rgInitPropSet;

IDBCreateSession *pCreateSession = NULL;

IErrorInfo *pErrorInfo = NULL;

IErrorInfo *pErrorInfoRec = NULL;

IErrorRecords *pErrorRecords = NULL;

ISupportErrorInfo *pSupportErrorInfo = NULL;

ULONG i,ulNumErrorRecs;

BSTR bstrDescriptionOfError = NULL;

BSTR bstrSourceOfError = NULL;

_bstr_t bstrDsnName = "wrong_db@demo_on"; // WRONG DATABASE

_bstr_t bstrUserName = "informix";

_bstr_t bstrPassWord = "password";

CoInitialize( NULL );

// Instantiate a data source object

CHECK( hr = CoCreateInstance((REFCLSID) CLSID_IFXOLEDBC, NULL,

CLSCTX_INPROC_SERVER, IID_IDBInitialize, (void **) &pIDBInitialize))

// Set all Properties, Prompt, DSN, User and Password

// Initialize common property options.

for (ULONG i = 0; i < 4; i++ )

{

VariantInit(&InitProperties[i].vValue);

InitProperties[i].dwOptions = DBPROPOPTIONS_REQUIRED;

InitProperties[i].colid = DB_NULLID;

InitProperties[1].vValue.vt = VT_BSTR;

}

InitProperties[0].dwPropertyID = DBPROP_INIT_PROMPT;

InitProperties[0].vValue.vt = VT_I2;

InitProperties[0].vValue.iVal = DBPROMPT_NOPROMPT;

InitProperties[1].dwPropertyID = DBPROP_INIT_DATASOURCE;

InitProperties[1].vValue.bstrVal = bstrDsnName;

InitProperties[2].dwPropertyID = DBPROP_AUTH_USERID;

InitProperties[2].vValue.bstrVal = bstrUserName;

InitProperties[3].dwPropertyID = DBPROP_AUTH_PASSWORD;

InitProperties[3].vValue.bstrVal = bstrPassWord;

rgInitPropSet.guidPropertySet = DBPROPSET_DBINIT;

rgInitPropSet.cProperties = 4;

rgInitPropSet.rgProperties = InitProperties;

// Get initialization properties.Interface

CHECK (hr = pIDBInitialize->QueryInterface(IID_IDBProperties,

(void**) &pIDBProperties))

CHECK(hr = pIDBProperties->SetProperties( 1, &rgInitPropSet))

CHECK( hr = pIDBProperties->Release())

230

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch07.fm

// Connect to the Database Server

hr = pIDBInitialize->Initialize();

if (hr < 0) {

pIDBInitialize->QueryInterface(IID_ISupportErrorInfo,

(LPVOID FAR*)&pSupportErrorInfo);

pSupportErrorInfo->InterfaceSupportsErrorInfo(__uuidof(pIDBInitialize));

GetErrorInfo(0,&pErrorInfo);

//Get the IErrorRecord interface and get the count of error recs.

pErrorInfo->QueryInterface(IID_IErrorRecords,(LPVOID FAR*)&pErrorRecords);

pErrorRecords->GetRecordCount(&ulNumErrorRecs);

//Get the error record, (we only get the first one)

pErrorRecords->GetErrorInfo(0, GetUserDefaultLCID(), &pErrorInfoRec);

pErrorInfoRec->GetDescription(&bstrDescriptionOfError);

pErrorInfoRec->GetSource(&bstrSourceOfError);

printf("ERROR!\nResult of 0x%0x (%ld) returned\n",(long)hr,(long)hr);

printf("Error Source: %S\n",bstrSourceOfError);

printf("Error Description: %S\n", bstrDescriptionOfError);

pErrorInfo->Release();

pErrorRecords->Release();

pSupportErrorInfo->Release();

pErrorInfoRec->Release();

SysFreeString(bstrSourceOfError);

SysFreeString(bstrDescriptionOfError);

} // if

/* ... some useful code here .... */

pIDBInitialize -> Uninitialize();

pIDBInitialize -> Release();

pIDBInitialize = NULL;

CoUninitialize();

return(0);

}

Example 7-10 shows the output of the Example 7-9 on page 229. We use a non

existent database for the connection, so an error is expected during initialization.

Example 7-10 Output of Errorinfo.cpp

C:\work>cl /EHsc /nologo errorinfo.cpp

errorinfo.cpp

C:\work>errorinfo

ERROR!

Result of 0x80004005 (-2147467259) returned

Chapter 7. Working with the IBM Informix OLE DB Provider

231

7884ch07.fm

Draft Document for Review August 23, 2010 10:53 am

Error Source: Ifxoledbc

Error Description: EIX000: (-329) Database not found or no system permission.

C:\work>

7.4 Visual Basic, ADO.NET, and SQL Server

ActiveX and COM objects are a core component of any Windows operating system. For this reason, OLE DB providers are extensively used by many

Windows applications. In this section we describe how to use the IBM Informix

OLE DB Provider with some of the Microsoft technologies and applications such as ADO.NET or Microsoft SQL Server.

7.4.1 OLE DB with Visual Basic

Visual Basic (VB) is a programming language developed by Microsoft focused on the use of the COM objects. Visual Basic is design to be easy to learn and use allowing the development of database applications with far less effort than C or

C++ languages. ADO and the Informix OLE DB provider is widely used with

Visual Basic.

In this section we demonstrate how to use the OLE DB provider to access an

Informix database using VBScript that is based on Visual Basic.

Select data

Example 7-11 shows how to query the state table using a recordset with a

VBScript file. We open the recordset using a static server cursor ( adUseServer=2 and adOpenStatic=3

).

Example 7-11 Select.vbs

' Create the ADO objects

set cx=createobject("ADODB.Connection")

set cr=createobject("ADODB.Recordset")

' Set the connection string

cx.provider="Ifxoledbc"

cx.connectionstring="Data Source=stores_demo@demo_on;"

' Open the Connection

cx.open

set cr.activeconnection=cx

cr.cursorlocation=2

' Open the Recordset

cr.open "SELECT * FROM state WHERE code='CA'", cx, 2, 3

232

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

WScript.Echo cr.fields("sname")

Example 7-12 shows the output of the this script.

Example 7-12 Output of Select.vbs

c:\work>select.vbs

California c:\work>

7884ch07.fm

Comparing this example with Example 7-5 on page 224 written on C++ you can

clearly see how easy it is to use OLE DB with Visual Basic.

Example 7-13 demonstrates how to scroll through a recordset.

Example 7-13 Scroll.vbs

' Create the ADO objects

set cx=createobject("ADODB.Connection")

set cr=createobject("ADODB.Recordset")

set cm=createobject("ADODB.Command")

' Set the connection string

cx.provider = "Ifxoledbc.2"

cx.Open "Data Source=stores_demo@demo_on"

' Set the Command SQL text

cm.ActiveConnection = cx

cm.CommandText = "SELECT * FROM state"

' Open the cursor

cr.CursorLocation = 3 ‘ adUseClient

cr.Open cm

WScript.Echo "First row: " & cr.fields("sname")

' Scroll to the last element in the recordset

cr.MoveLast

WScript.Echo "Last row : " & cr.fields("sname")

We use the

MoveLast()

method to position the cursor in the last record, see the

output in Example 7-14.

Example 7-14 Output of Scroll.vbs

c:\work>scroll.vbs

First row: Alaska

Last row : Puerto Rico c:\work>

Chapter 7. Working with the IBM Informix OLE DB Provider

233

7884ch07.fm

Draft Document for Review August 23, 2010 10:53 am

Add new data

In Example 7-15 we demonstrate how to add a new record to a table using the

AddNew() method. After adding a new record to the table, the code opens a cursor and position at the end of the recordset to retrieve the last inserted row.

Example 7-15 Addnew.vbs

' Create the ADO objects

set cx = CreateObject("ADODB.Connection")

set cr = CreateObject("ADODB.Recordset")

' Set the connection string

cx.provider = "Ifxoledbc"

cx.connectionstring = "Data Source=stores_demo@demo_on;"

cx.Open

Set cr.activeconnection = cx

' Open the recordset

cr.Open "SELECT * FROM state", cx, 3, 2

' Add a new record to the recordset

cr.AddNew

cr.fields("code") = "UN"

cr.fields("sname") = "Unkown"

cr.fields("sales_tax") = "0.0"

' Update the database table

cr.Update

cr.Close

' Retrieve the new inserterd row

cr.open "SELECT * FROM state", cx, 3, 3

cr.MoveLast

WScript.Echo cr.fields("sname")

Example 7-16 shows the value of the sname column after the update operation

Example 7-16 Output of Addnew.vbs

c:\work>addnew.vbs

Unkown

c:\work>

7.4.2 ADO.NET and the OLEDB bridge

In addition to ADO, developers can also use the IBM Informix OLE DB Provider with ADO.NET. Similar to ADO but within the .NET Framework, ADO.NET is a set of .NET components used to retrieve, manipulate, and update data from a data source.

234

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch07.fm

One of the .NET data providers included with ADO.NET is the Microsoft OLE DB

Provider for .NET. This .NET provider acts as bridge between the .NET framework and standard OLE DB providers so developers can use the .NET technology with a database server even if there is no specific .NET data provider for that particular database.

IBM has specific .NET providers to access an Informix database: IBM Informix

.NET Provider and IBM Data Server Provider for .NET. However, the developers can use the Informix OLE DB Provider through the Microsoft OLE DB .NET

Provider.

Example 7-17 demonstrates how to use the Informix OLE DB with a .NET

application. The connection string for the Informix OLE DB provider is the same,

refer 7.3.2, “Connecting to database” on page 215 for the complete syntax.

Example 7-17 Getoledb.cs

using System; using System.Data; using System.Data.OleDb; class sample {

static void Main(string[] args) {

OleDbConnection con = new OleDbConnection();

con.ConnectionString = "Provider=Ifxoledbc;"

+" Data Source=stores_demo@demo_on; User ID=informix;"

+" Password=password";

DataSet ds = new DataSet();

string sql = "SELECT first 3 * FROM STATE";

OleDbDataAdapter da = new OleDbDataAdapter(sql,con);

da.Fill(ds,"state");

foreach(DataRow dr in ds.Tables[0].Rows) {

Console.WriteLine(dr["code"]);

Console.WriteLine(dr["sname"]);

Console.WriteLine(dr["sales_tax"]);

}

con.Close();

con.Dispose();

}

}

Example 7-18 on page 236 demonstrates how to compile and run this .NET

example.

Chapter 7. Working with the IBM Informix OLE DB Provider

235

7884ch07.fm

Draft Document for Review August 23, 2010 10:53 am

Example 7-18 Output of Getoledb.cs

c:\work>csc.exe /nologo getoledb.cs c:\work>getoledb

AK

Alaska

0.00000

HI

Hawaii

0.04000

CA

California

0.08250

c:\work>

7.4.3 SQL Server

Using the IBM Informix OLE DB Provider you can select data from an Informix database directly from Microsoft SQL Server.

SQL Server uses OLE DB to create Linked Servers, and retrieve data from any

OLE DB data source.

There are no specific steps to configure or to use the Informix OLE DB Provider with SQL Server as a linked server. If the Informix OLE DB Provider is correctly installed and configured, SQL Server can use it to connect to an IBM Informix database server.

We describe how to setup a Linked Server using the Informix provider here.

Figure 7-3 on page 237 shows the New Linked Server dialog box where the

connection details for the OLE DB provider must be set.

236

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch07.fm

Figure 7-3 New Linked Server Dialog

The following fields must be set

򐂰 Linked Server: Specify the name for the SQL Server to link.

򐂰

Provider: Choose IBM Informix OLE DB Provider from the dropdown list.

򐂰 Product name: Specify the name of the Informix provider which is ifxoledbc .

򐂰

Data source: Specify the name of the datasource as database@server.

򐂰 Provider string: Specify any additional Connection String parameters used by the provider.

The user id for the Informix database server may differ from the one used with

SQL Server. If this is the case, a remote user mapping must be set. Figure 7-4 on page 238 shows a user mapping between the sa and informix users.

Chapter 7. Working with the IBM Informix OLE DB Provider

237

7884ch07.fm

Draft Document for Review August 23, 2010 10:53 am

Figure 7-4 Linked Server Security options

You can also create linked servers using only SQL statements. In Example 7-19

we illustrate how to create a linked server to connect to the demo_on

Informix

instance. We use the same connection details shown in Figure 7-3 on page 237.

Example 7-19 Linked Server SQL script

EXEC master.dbo.sp_addlinkedserver

@server = N'demo_on',

@srvproduct=N'ifxoledbc',

@provider=N'ifxoledbc',

@datasrc=N'stores7@demo_on',

@provstr=N''

EXEC sp_addlinkedsrvlogin 'demo_on',false,'sa','informix','password'

SELECT * FROM demo_on.stores7.informix.customer

238

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

Figure 7-5 shows the output for the previous SQL script.

7884ch07.fm

Figure 7-5 Linked Servers Select output

The last SQL statement in the script uses the linked server to retrieve the data from the customer table

SELECT * FROM demo_on.stores7.informix.customer

For more information about Linked Servers, refer to the Microsoft documentation at http://msdn.microsoft.com/en-us/library/ms188279.aspx

7.5 Troubleshooting and tracing

In this section we discuss typical errors seen when using the IBM Informix .NET

Provider and how to enable the tracing facility to collect diagnostic information.

Chapter 7. Working with the IBM Informix OLE DB Provider

239

7884ch07.fm

Draft Document for Review August 23, 2010 10:53 am

7.5.1 Typical errors

Most of the errors encountered when using the Informix OLE DB provider are due to an incorrect setup or a invalid connection string been passed to the provider.

The Informix OLE DB provider uses the same connectivity libraries as other components of the Client SDK package. It also uses the information stored in the registry through the Setnet32 tool for the database server connection.

It is always a good practise to test this basic connectivity using the Ilogin tool included in the Client SDK directory.

Provider not found

Here we explain the reason and the solution for the “provider not found” error.

Reason

This error appears if Windows fails to locate the OLE DB provider class specified by the application.

Solution

During the installation of Client SDK, the OLE DB provider is automatically registered within the Windows registry. You can manually register the Informix

OLE DB using the regsvr32

tool as follows: regsvr32.exe %INFORMIXDIR%\bin\ifxoledbc.dll

If you are running a 64-bit version of Windows, make sure that you register the provider using the correct version of the regsvr32

binary. Otherwise, it may happen that the 32-bit provider is registered as a 64-bit one (or vice versa) and

Windows would fail to find and load the provider.

You can check if the provider library is correctly registered by examining the

Windows registry. Example 7-20 shows the registry entry 32-bit and 64-bit

Informix OLE DB providers. Remember that the name of the Informix provider is ifxoledbc

.

Example 7-20 Informix OLE DB registry keys

C:\work>c:\windows\syswow64\reg query

"HKEY_CLASSES_ROOT\CLSID\{A6D00422-FD6C-11D0-8043-00A0C90F1C59}\InprocServer32"

HKEY_CLASSES_ROOT\CLSID\{A6D00422-FD6C-11D0-8043-00A0C90F1C59}\InprocServer32

(Default) REG_SZ C:\Program Files

(x86)\IBM\Informix\Client-SDK\bin\ifxoledbc.dll

ThreadingModel REG_SZ Both

240

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch07.fm

C:\work>c:\windows\system32\reg query

"HKEY_CLASSES_ROOT\CLSID\{A6D00422-FD6C-11D0-8043-00A0C90F1C59}\InprocServer32"

HKEY_CLASSES_ROOT\CLSID\{A6D00422-FD6C-11D0-8043-00A0C90F1C59}\InprocServer32

(Default) REG_SZ C:\Program

Files\IBM\Informix\Client-SDK\bin\ifxoledbc.dll

ThreadingModel REG_SZ Both

C:\work>

Failed to load the Ifxoledbc.dll

Here we explain the reason and the solution for the “Failed to load the

Ifxoledbc.dll” error.

Reason

The application fails to load the Informix OLE DB provider or one of its libraries.

Solution

The value of INFORMIXDIR (as a environment variable or in the registry) should be the directory where Informix Client SDK was installed. Make sure the environment variable PATH contains the

%INFORMIXDIR%\bin

directory. For example:

PATH=C:\Program Files\IBM\Informix\Client-SDK\bin;%PATH%

When an application loads the Informix OLE DB provider, the Client SDK libraries that the provider needs for communication and registry access are loaded from the directory used in the registration process.

On 64-bit version of Windows, make sure PATH and INFORMIXDIR variables are correctly set for all users. Some applications such as SQL Server are executed under different credentials as the logged user, and may have different settings for this variables.

Failed to connect to the database

Here we explain the reason and the solution for the “Failed to connect to the database” error.

Reason

Most common reason for these errors is due to the invalid parameters in the connection string or the invalid connectivity information.

Chapter 7. Working with the IBM Informix OLE DB Provider

241

7884ch07.fm

Draft Document for Review August 23, 2010 10:53 am

Solution

If the application is getting an Informix OLE DB error, it means it has managed to load the Informix OLE DB provider, but it is failing during connection.

For any connection error, always check if the basic connectivity works. Test if the client machine has access to the database using Ilogin would help to narrow down the problem.

If

Ilogin

fails, verify the connection parameters for the database (server name,

port number, host name, and so on) are correct. Use setnet32 to check if the information stored in the registry is valid.

The user credentials (user and password) can also be set in the registry using setnet32. Verify both of them are valid.

The majority of the connection string parameters must be included exactly as

they appear in Table 7-4 on page 216. Invalid parameters are ignored and may

cause an error connection. See Table 7-7 for same examples.

Table 7-7 Valid parameters

Valid Invalid

Data Source DataSource, DSN

User ID

Password

UserID, UID

PWD

If you are using GLS variables (

Client_Locale

or

Db_locale

), make sure they are correctly set. If UNICODE is not used, The codeset part of

Client_Locale

should be the same as your operating system.

Db_Locale

should be your database locale.

Failure when handling database data

Here we explain the reason and the solution for the “Failed when handling database data” error.

Reason

These types of errors are caused by using the wrong data type when accessing

Informix tables.

Solution

The Informix OLE DB Provider requires additional functions and tables in the

sysmaster database to correctly handle Informix data types. These objects are created when running the coledbp.sql

SQL script.

242

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch07.fm

This script is located in the %INFORMIXDIR%\etc directory and must be executed against the sysmaster database as the informix user.

If you are upgrading from an old version of Informix Client SDK, remove these objects by running the doledbp.sql

script from the old client before using the new coledbp.sql

.

7.5.2 Tracing

Tracing is useful when diagnosing application problems such as SQL errors or unexpected behaviors and can even be used for performance analysis.

Tracing

There are two types of tracing that a developer can set when using the Informix

OLE DB Provider:

򐂰 Informix OLE DB Trace

򐂰 SQLIDEBUG

Informix OLE DB Trace

Informix OLE DB Trace is specific to the Informix OLE DB Provider. You can set the IFXOLEDBCTRACE

environment variable to point to the location of the trace file,

for example:

IFXOLEDBCTRACE=oledbtrace.txt

The trace file generated contains the calls to all the OLE DB interfaces used by the provider.

Example 7-21shows a typical Informix OLE DB trace file

Example 7-21 OLE DB trace

Wed Jun 30 13:59:01 2010

A44: 53C Enter Clsfact::QueryInterface

Object Address: 0x032C2CB8

A44: 53C Enter Clsfact::AddRef

Object Address: 0x032C2CB8

A44: 53C Exit Object Address: 0x032C2CB8 hr=2 qi: 032C2CB8 (pif 032C2CB8)

A44: 53C Enter Clsfact::Release

Object Address: 0x032C2CB8

A44: 53C Exit Object Address: 0x032C2CB8 hr=1

A44: 53C Enter Clsfact::AddRef

Object Address: 0x032C2CB8

Chapter 7. Working with the IBM Informix OLE DB Provider

243

7884ch07.fm

Draft Document for Review August 23, 2010 10:53 am

A44: 53C Exit Object Address: 0x032C2CB8 hr=2

A44: 53C Enter Clsfact::Release

Object Address: 0x032C2CB8

A44: 53C Exit Object Address: 0x032C2CB8 hr=1

A44: 53C Enter Clsfact::QueryInterface

Object Address: 0x032C2CB8

A44: 53C Enter Clsfact::AddRef

Object Address: 0x032C2CB8

A44: 53C Exit Object Address: 0x032C2CB8 hr=2

...

In addition to the OLE DB interfaces, the trace facility collects the return value for

any method used during the OLE DB session. Example 7-22 illustrates this.

Example 7-22 Entry and Exit points OLE DB trace

A44: 53C Enter Datasrc::QueryInterface

A44: 53C Enter Datasrc::QueryInterface

A44: 53C Enter Datasrc::AddRef

A44: 53C Exit Object Address: 0x032CC370 hr=2

A44: 53C Enter Datasrc::Release

A44: 53C Exit Object Address: 0x032CC370 hr=1

A44: 53C Enter Datasrc::QueryInterface

A44: 53C Enter Datasrc::XIDBProperties::SetProperties

A44: 53C Exit Object Address: 0x032CC38C hr=0

A44: 53C Enter Datasrc::QueryInterface

A44: 53C Enter Datasrc::XIDBProperties::SetProperties

A44: 53C Exit Object Address: 0x032CC38C hr=0

A44: 53C Enter Datasrc::QueryInterface

A44: 53C Enter Datasrc::XIDBInitialize::Initialize

A44: 53C Exit Object Address: 0x032CC384 hr=0

A44: 53C Enter Datasrc::QueryInterface

A44: 53C Enter Datasrc::XIDBProperties::GetProperties

A44: 53C Exit Object Address: 0x032CC38C hr=0

A44: 53C Enter Datasrc::QueryInterface

A44: 53C Enter Datasrc::XIDBCreateSession::CreateSession

SQLIDEBUG

SQLI is the communication protocol used by Informix Client SDK. SQLIDEBUG is a trace facility of all the messages between an Informix client and a Informix database server. This trace is common to all the Informix Client SDK components (ESQL/C, ODBC, OLE DB, and so on).

244

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch07.fm

You can find a description and how to enable SQLIDEBUG in 3.3.6,

“Troubleshooting” on page 113.

When diagnosing a performance problem, sometimes, it is useful to collect a

SQLIDEBUG trace to have an idea of where the delay occurs. Using the summary option when processing the sqlidebug file with sqliprint

that produces a detail

description of all the message between client and server. See Example 7-23.

Example 7-23 Sqliprint Summary Output

>>>>>>>>>>>>>>>>>> SUMMARY INFORMATION <<<<<<<<<<<<<<<<<

>>>>>>>>>>TOTAL ELAPSED CLOCK TIME (sec): 0.047000

>>>>>>>>>>CLIENT ELAPSED CLOCK TIME (sec): 0.047000

>>>>>>>>>>SERVER+NETWORK CLOCK TIME (sec): 0.000000

FROM C->S

Msg occured Total Avg Min Max

------------------------------------------------------------------

SQ_PREPARE 1 0.000000 0.000000 0.000000 0.000000

SQ_ID 4

SQ_CLOSE 1

SQ_RELEASE 2

SQ_EOT 7

SQ_NDESCRIBE 1

SQ_SFETCH 1 0.000000 0.000000 0.000000 0.000000

SQ_WANTDONE 1

SQ_EXIT 1

SQ_INFO 1

SQ_RET_TYPE 1

SQ_INTERNALVER 1

SQ_PROTOCOLS 1

------------------------------------------------------------------

FROM S->C

Msg occured Total Avg Min Max

------------------------------------------------------------------

UNKNOWN 1

SQ_DESCRIBE 1 0.000000 0.000000 0.000000 0.000000

SQ_EOT 6

SQ_TUPLE 1

SQ_TUPID 1

SQ_PROTOCOLS 1

------------------------------------------------------------------

=======================================================================

COMMAND TEXT INFORMATION (first 99 are listed) a( b) CMD[##]= ' first 60 bytes of cmd text ' where a = 'P'repare, or 'N'ot prepared, and b = length of command string

-----------------------------------------------------------------------

P( 28) CMD[ 0]='SELECT rowid, * FROM state;'

Chapter 7. Working with the IBM Informix OLE DB Provider

245

7884ch07.fm

Draft Document for Review August 23, 2010 10:53 am

-----------------------------------------------------------------------

=======================================================================

Fetch Array feature not used

OPTOFC feture not used

Number of open/reoptimzation encountered = 0

Number of C->S message send = 22

Number of S->C message send = 21

Number of prepare statements encountered = 1

Number of execute statements encountered = 0

Number of singleton select encountered = 0

Number of open cursor encountered = 0

Number of close cursor encountered = 1

Number of non-blob put = 0, averge size of each put is 0.000000

Number of non-blob fetch = 1, averge size of each fetch is 25.000000

Number of blob put = 0, averge size of each put is 0.000000

Number of blob fetch = 0, averge size of each fetch is 0.000000

>>>>>>>>>>>>>>> END SUMMARY INFORMATION <<<<<<<<<<<<<<<

246

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch08.fm

8

Chapter 8.

Working with the .NET Data

Providers

This chapter describes the different .NET Providers available for working with an

Informix database server.

We cover the following topics:

򐂰 .NET data Provider setup and configuration

򐂰 Basic connectivity

򐂰 Simple operations with the database

򐂰 Using the .NET extensions for special data types

򐂰 Problem diagnosis

򐂰 Tracing

© Copyright IBM Corp. 2010. All rights reserved.

247

7884ch08.fm

Draft Document for Review August 23, 2010 10:53 am

8.1 Informix and .NET data providers

A .NET data provider is a .NET assembly that lets the .NET applications access and manipulate data in a database. It does this by implementing several interfaces that follow the Microsoft ADO.NET architecture. A .NET data provider can be used by any application that can be executed by the Microsoft .NET

Framework.

IBM provides two .NET data providers to work with an IBM Informix database:

򐂰 IBM Infomix .NET Provider

򐂰 IBM Data Server Provider for .NET

Both providers, Informix .NET and Data Server, rely on internal calls to the

ODBC and CLI drivers, so they are not 100% managed-code providers.

8.2 Setup and configuration

This chapter describes the .NET providers available to connect to an IBM

Informix database. We explain how to configure and test the connectivity with both IBM Infomix .NET Provider and IBM Data Server Provider for .NET.

8.2.1 IBM Informix .Net Provider

The Informix .NET Provider is part of the IBM Informix Client SDK. IBM Informix

.NET Provider has been certified to work on both 32-bit and 64-bit editions of

Windows XP, Windows Vista, Windows Server 2003, Windows Server 2008 and

Windows 7.

The provider requires that Microsoft .NET Framework SDK 1.1 or higher are already installed on the computer. The provider is installed by default when performing a complete install of the Informix Client SDK package.

Informix .NET Data Provider supports the following Informix database servers:

򐂰 IBM Informix 10.00, 11.10, and 11.50

򐂰 IBM Informix Extended Parallel Server 8.50 and later

The assembly name of the Informix .NET provider is

IBM.Data.Informix.

The assembly files are located in the Client SDK directory. The provider for a

.NET 1.1 application is in %INFORMIXDIR%\netf11 . For a .NET 2.0 and above, use the provider located in %INFORMIXDIR\netf20 .

248

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch08.fm

The installation process registers two strong-named assemblies in the global assembly cache (GAC).

Table 8-1 shows the Informix .NET Provide assembly versions.

Table 8-1 Informix.NET Provider assembly versions

.NET framework Assembly version

1.1

2.0 and above

2.81.0.0

3.0.0.2

The assemblies are registered in the common section of the GAC (GAC_MSIL).

Because of this, only one version of the provider (32-bit or 64-bit) can be stored in the GAC at one time.

Note: There is no 64-bit version of the .NET 1.1 Framework, so the .NET 1.1

provider is not installed on a Windows 64-bit platform.

8.2.2 IBM Data Server Provider for .NET

The IBM Data Server Provider for .NET is included in the IBM Data Server

Package. The Provides support multiple IBM data servers including IBM Informix

(11.x) and DB2.

Same as the Informix .NET provider, the Data Server Provider is not 100% managed code, this means that it requires the DB2 CLI component for the communication with the database.

There are two Data Server providers for an Informix database:

򐂰

IBM.Data.DB2: This is the preferred .NET provider when developing new applications.

򐂰 IBM.Data.Informix: This .NET Provider assembly is normally used to migrate an application developed using the IBM Informix .NET Provider.

The assembly files are located in the netf20 subdirectory under the Data Server

Client directory, by default is C:\Program Files\IBM\IBM DATA SERVER

DRIVER\netf20.

Note: The 64-bit version of the Data Server Client Package also includes the

32-bit drivers.

Chapter 8. Working with the .NET Data Providers

249

7884ch08.fm

Draft Document for Review August 23, 2010 10:53 am

Both providers had the same assembly version, 9.0.0.2. Table 8-2 shows the

Data Server Client .NET Provider assembly version.

Table 8-2 Data Server Client Assembly versions

.NET Provider Assembly version

IBM.Data.DB2

IBM.Data.Informix

9.0.0.2

9.0.0.2

8.2.3 Verifying connectivity

The Informix .NET provider uses communication libraries Internally as the other drivers included in the Informix Client SDK, this means that it uses the same connectivity information normally stored in the registry through the use of

Setnet32.

When there is no specific tool to verify the connectivity with the Informix .NET provider, you can use a simple .NET application to test it.

The Microsoft .NET Framework SDK is required to use the .NET Provider that contains a .NET language compiler.

Example 8-1 shows a simple C# code to verify the connection with the database

server. This example takes the connection string as first argument and uses it to connect to the database.

Example 8-1 Connect.cs

using System; using System.Data; using IBM.Data.Informix; class Connect

{

static void Main(string[] args)

{

IfxConnection conn;

if (args.Length>0) {

try {

conn = new IfxConnection(args[0]);

conn.Open();

Console.WriteLine("Connected");

Console.WriteLine(String.Format("Server Type: {0}, Server

Version: {1}", conn.ServerType, conn.ServerVersion));

250

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch08.fm

Console.WriteLine(String.Format("Database: {0}", conn.Database));

}

catch (Exception e) {

Console.WriteLine(e.Message);

}

}

else

Console.WriteLine("Need a connection string as argument\n e.g:

\"Host=kodiak;Service=9088;Server=demo_on;Database=stores_demo;User

ID=informix;password=;\"\n");

}

}

Example 8-2 shows how to compile and run Example 8-1 on page 250.

Example 8-2 Output of Connect.cs

C:\work>csc.exe /R:%INFORMIXDIR%\bin\netf20\IBM.Data.informix.dll /nologo connect.cs

C:\work>connect "Server=demo_on;Database=stores_demo"

Connected

Server Type: Informix, Server Version: 11.50.0000 FC6

Database: stores_demo

C:\work>

If the connection information for the Informix server is stored in the registry, the only parameter required in the connection string is the name of the database server, everything else such as Host or Service is taken from the registry.

At compile time, you must pass the assembly as a reference to the csc.exe compiler using the /R parameter. For example:

/R:%INFORMIXDIR%\bin\netf20\IBM.Data.Informix.dll

If you want to use the Data Server provider, the reference path should be

/R:”C:\Program Files (x86)\IBM\IBM DATA SERVER DRIVER\bin\netf20\IBM.Data.Informix.dll”

Example 8-3 shows how to compile and execute the sample with the Data Server

.NET provider.

Example 8-3 Data Server Connect.cs sample

C:\work>csc.exe /R:"C:\Program Files (x86)\IBM\IBM DATA SERVER

DRIVER\bin\netf20\IBM.Data.Informix.dll" /nologo connect.cs

Chapter 8. Working with the .NET Data Providers

251

7884ch08.fm

Draft Document for Review August 23, 2010 10:53 am

C:\work>connect "Server=kodiak:9089;Database=stores_demo;User

ID=informix;password=password;"

Connected

Server Type: IDS/NT64, Server Version: 11.50.0000

Database: STORES_DEMO

C:\work>

The Data Server provider includes a connection tool called

testconn20.exe

which

can be used to test the connection with the database. Example 8-4 shows a

typical output of the testconn tool.

Example 8-4 Output of testconn20.exe

C:\work>testconn20.exe "server=kodiak:9089; database=stores_demo; uid=informix; pwd=password;"

Step 1: Printing version info

.NET Framework version: 2.0.50727.3603

DB2 .NET provider version: 9.0.0.2

DB2 .NET file version: 9.7.2.2

Capability bits: ALLDEFINED

Build: 20100514

Factory for invariant name IBM.Data.DB2 verified

VSAI assembly version: 9.1.0.0

VSAI file version: 9.7.1.53

Elapsed: 1.015625

Step 2: Validating db2dsdriver.cfg against db2dsdriver.xsd schema file

C:\PROGRA~1\IBM\IBMDAT~2\cfg\db2dsdriver.cfg against C:\Program

Files\IBM\IBM DATA SERVER DRIVER\cfg\db2dsdriver.xsd

Elapsed: 0.015625

Step 3: Connecting using "server=kodiak:9089; database=stores_demo; uid=informix; pwd=password;"

Server type and version: IDS 11.50.0000

Elapsed: 0.46875

Step 4: Selecting rows from informix.systables to validate existance of packages

SELECT * FROM informix.systables

Elapsed: 0.171875

Step 5: Calling GetSchema for tables to validate existance of schema functions

Elapsed: 0.21875

Test passed.

252

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

C:\work>

7884ch08.fm

8.3 Developing a .NET application

This section describes the connection string attributes for two Informix .NET providers and provides samples of basic database operations.

8.3.1 Connecting to database

In this section we describe the connection string attributes for the IBM Informix

.NET Provider and the Data Server Provider for .NET

Informix .NET connection attributes

Table 8-3 lists the connection attributes that the Informix .NET provider supports.

Table 8-3 Informix .NET connection string attributes.

Attribute Description

Locale used on the application Client Locale,

Client_Locale

Connection Lifetime

Database, DB

Time in seconds that a connection is allowed in the pool

Database to connect to

Locale of the database Database Locale,

DB_LOCALE

DELIMIDENT If set, any string within double quotes (") is treated as an identifier, and any string within single quotes (’) is treated as a string literal

Enlist

Exclusive, XCL

Host

Default

en_us.1252

0 en_US.819

y

Enables or disables automatic enlistment in a distributed transaction true

No if set the database is open in exclusive mode

Name or IP address of the machine on which the Informix server is running localhost

Max Pool Size Maximum number of connections allowed in the pool

100

Chapter 8. Working with the .NET Data Providers

253

7884ch08.fm

Draft Document for Review August 23, 2010 10:53 am

Attribute

Min Pool Size

Optimize OpenFetchClose,

OPTOFC

Packet Size, Fetch Buffer

Size, FBS

Password, PWD

Persist Security Info

Pooling

Protocol, PRO

Server

Service

Skip Parsing

UserDefinedTypeFormat

Leave Trailing Spaces

User ID, UID

Description

Minimum number of connections allowed in the pool

Reduces the number of client-server messages when using cursors

Size in bytes of the buffers used to send data to or from the server

Password associated with the User ID

Default

0

0

32767

If set the security-sensitive information, such as the password, is returned as part of the connection string

Enable Connection Pooling false true

Communication protocol

Name or alias of the Informix server

Service name or port number used by the server for incoming connection if set, there is no internal SQL parsing it increases performance but the SQL must be valid

Changes the mapping of UDTs to either

DbType.String or DbType.Binary

If set disable the automatic trailing of spaces done in a varchar column

Login account.

false false

Data Server Client for .NET connection attributes

Table 8-4 lists the most common connection attributes that the IBM Data Server

.NET Provider uses.

Table 8-4 IBM Data Server connection string attributes

Attribute Description

ConnectTimeout,

Connect Timeout

Connection Lifetime

The time (in seconds) to wait for the database connection to be established.

Time in seconds that a connection is allowed in the pool.

Default Value

0

60

254

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch08.fm

Attribute

Database, DB

Enlist

Max Pool Size

Min Pool Size

Password, PWD

Persist Security Info

Pooling

Query Timeout

Server

User ID, UID

Description

Database to connect to.

Enables or disables automatic enlistment in a distributed transaction.

Maximum number of connections allowed in the pool.

Minimum number of connections allowed in the pool.

Password associated with the User ID

If set the security-sensitive information, such as the password, is returned as part of the connection string.

Enable Connection Pooling within the

.NET Provider

Time to wait for a SQL query response

Name or alias of the Informix server followed by service name or the port number

Login account

Default Value

true

0

0 false true

5

The configuration parameters for Data Server .NET provider and most of the components in the Data Server Client are stored in the db2sdriver.cfg

file. Refer to the following website for a complete list of configuration parameters: http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.swg.im.dbcli

ent.config.doc/doc/c0054698.html

If the connection string does not contain all the required information, the provider takes the missing arguments from the db2sdriver.cfg

configuration file.

The majority of the connection string attributes of Data Server Provider for .NET have the similar meaning and format with the Informix .NET Provider except the the Server attribute.

For the Informix .NET Provider the keyword Server contains the name (or alias) of the Informix server which normally is the same as the value of the

INFORMIXSERVER variable.

For the Data Server .NET Provider, Server contains the host name where the

Informix server is running, and the service name or port number used to listen for

DRDA client connections.

Chapter 8. Working with the .NET Data Providers

255

7884ch08.fm

Draft Document for Review August 23, 2010 10:53 am

Example 8-5 shows the Server attribute format. In this example, we connect to

an Informix database server running in a machine named kodiak.ibm.com

. The

Informix server DRDA alias is using the port number 9089

.

Example 8-5 Server attribute for the Data Server provider

C:\work>connect

"Server=kodiak.ibm.com:9089;Database=stores_demo;UID=informix;password=password

;"

Connected

Server Type: IDS/NT64, Server Version: 11.50.0000

Database: STORES_DEMO

C:\work>

8.3.2 Data type mapping

The data types used by the .NET Framework differ from the data type used by the IBM Informix database. In this section we describe the optimal data types to use when accessing data in an Informix database. The optimal data type depends on .NET method used to access the data.

You can use types other than those shown, for example, you can use the

IfxDataReader.GetString method to obtain any Informix data type. The types mentioned here are the most efficient and least likely to change in value in data conversion.

Informix .NET type mapping

Table 8-5 shows the mapping for the specific IBM Informix data types.

Table 8-5 Type mapping for Informix specific data

Informix data type For DataReader

BIGINT Int64

BIGSERIAL

BLOB

BOOLEAN

BYTE

CLOB

COMPLEX (ROW, LIST)

Int64

IfxBlob

Boolean

Byte[]

IfxClob

String

For DataSet

Int64

Int64

Byte[]

Boolean

Byte[]

Byte[]

String

256

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch08.fm

Informix data type

DECIMAL(p<=28) fixed scale

For DataReader

IfxDecimal

DECIMAL(p<=28) floating point IfxDecimal

DECIMAL (p>28) IfxDecimal

IDSSECURITYLABEL

INT8

Int64[]

Int64

INTERVAL, year-month

INTERVAL, day-fraction

LVARCHAR

MONEY

NCHAR

SERIAL

SERIAL8

TEXT

IfxMonthSpan

IfxTimeSpan

String

IfxDecimal

String nt32

Int64

String

For DataSet

Decimal

Double

String

Int64[]

Int64

String

TimeSpan

String

Decimal with same precision

String

Int32

Int64

String

Data Server Client type mapping

Table 8-6 shows the type mapping with the Data Server provider when using

specific Informix data types.

Table 8-6 Type mapping for Informix specific data

Informix Data Type Optimal for DataReader Optimal for DataSet

LVARCHAR IfxString String

BLOB, BYTE

CLOB, TEXT

BOOLEAN, SMALLINT

BIGINT, BIGSERIAL, INT8,

SERIAL8

DECIMAL(p<=28) fixed scale

IfxBlob

IfxClob

IfxInt16

IfxInt64

IfxDecimal

DECIMAL(p<=28) floating point IfxDouble

DECIMAL (p>28) IfxDouble

Byte[]

String

Int16

Int64

Decimal

Double

Double

Chapter 8. Working with the .NET Data Providers

257

7884ch08.fm

Informix Data Type

MONEY

Draft Document for Review August 23, 2010 10:53 am

Optimal for DataReader Optimal for DataSet

IfxDecimal Decimal

8.3.3 Performing database operations

This section describes the main classes in the .NET Provider and demonstrate how to use them with basic examples.

IfxConnection

This object represents a unique connection with the database server. You can specify the connectivity details about the database when creating the connection object or by setting the ConnectionString property later on.

Because the .NET Provider uses native resources (not managed by the .NET

CLR), you should always close or dispose any open IfxConnection object when it is not longer needed.

Table 8-7 lists the public method of the

IfxConnection class.

Table 8-7 IfxConnection public methods

Method Description

void Open() void Close()

Opens a database connection

Closes the connection to the database void ChangeDatabase(String) void EnlistTransaction()

Changes the current database

Enlist the connection in a DTC transaction

IfxTransaction

BeginTransaction()

BeginTransaction(IsolationLevel)

Begins a database transaction

IfxCommand CreateCommand() Creates an instance of a IfxCommand object associated with this IfxConnection

IfxBlob GetIfxBlob() Creates an instance of a IfxBlob object associated with this connection

IfxClob GetIfxClob() Creates an instance of a IfxClob object associated with this connection

We described the connection string attributes in 8.3.1, “Connecting to database” on page 253.

258

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch08.fm

Example 8-6 demonstrates how to connect to the database

Example 8-6 connect_sample.cs

using System; using System.Data; using IBM.Data.Informix; class sample {

static void Main(string[] args) {

IfxConnection conn;

try {

conn = new IfxConnection("Server=demo_on;database=stores_demo");

conn.Open();

Console.WriteLine("Connected to "+conn.Database);

conn.Close();

}

catch (Exception e) {

Console.WriteLine(e.Message);

}

}

}

Example 8-7 shows the output of Example 8-6.

Example 8-7 Output of Connect_sample.cs

C:\work>csc.exe /R:%INFORMIXDIR%\bin\netf20\IBM.Data.Informix.dll /nologo connect_sample.cs

C:\work>connect_sample

Connected to stores_demo

C:\work>

IfxCommand

IfxCommand represents a SQL statement or stored procedure to execute against a database server.

Table 8-8 on page 260 shows methods that the

IfxCommand class provides for executing a SQL statement.

Chapter 8. Working with the .NET Data Providers

259

7884ch08.fm

Draft Document for Review August 23, 2010 10:53 am

Table 8-8 IfxCommand public methods

Method

Int32 ExecuteNonQuery()

IfxDataReader ExecuteReader()

ExecuteReader(DataCommandBehavior behavior)

Object ExecuteScalar() void Cancel()

IfxParameter CreateParameter() void Prepare()

Description

Executes an SQL statement against the

IfxConnection object.

Executes the command in the

CommandText property against the

IfxConnection object and builds an

IfxDataReader object.

Executes the query, and returns the first column of the first row.

Attempts to cancel the execution of a command.

Creates a new instance of an

IfxParameter object.

Creates a prepared (or compiled) version of the command against the database.

Example 8-8 demonstrates how to run a simple DELETE SQL statement.

Example 8-8 Command_sample.cs

using System; using System.Data; using IBM.Data.Informix; class sample {

static void Main(string[] args) {

IfxConnection conn;

int drows=0;

try {

conn = new IfxConnection("Server=demo_on;database=stores_demo");

conn.Open();

IfxCommand cmmd = conn.CreateCommand();

cmmd.CommandText = "DELETE FROM customer WHERE customer_num = 103";

drows = cmmd.ExecuteNonQuery();

Console.WriteLine("Deleted rows: "+drows.ToString());

conn.Close();

}

catch (Exception e) {

Console.WriteLine(e.Message);

}

260

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

}

}

7884ch08.fm

Example 8-9 shows the output of Example 8-8 on page 260.

Example 8-9 Output of command_sample.cs

C:\work>csc.exe /R:%INFORMIXDIR%\bin\netf20\IBM.Data.Informix.dll /nologo command_sample.cs

C:\work>command_sample

Deleted rows: 1

C:\work>

IfxDataAdapter

The IfxDataAdapter class represents a set of data commands that are used to communicate between a DataSet and the database. A DataSet is a copy of the database data stored in memory.

Table 8-9 lists the methods that

IfxDataAdapter provides for accessing the data.

Table 8-9 IfxDataAdapter public methods

Method Description

Int32 Fill(DataSet)

DataTable FillSchema(DataSet,

SchemaType)

Adds or refreshes rows in the DataSet.

Adds a DataTable to the DataSet and configures the schema to match that in the database based on the specified SchemaType.

IDataParameter GetFillParameters() Returns the parameters set by the user when executing a SELECT statement

Int32 Update(DataSet) Execute the SQL statement associated with the InsertCommand, UpdateCommand or

DeleteCommand for each inserted, updated, or deleted row in the specified DataSet

Example 8-10 demonstrates how to retrieve data from the database using the

IfxDataAdapter class. In this example, we retrieve the data rows directly from the

DataSet.

Example 8-10 Dataadapter_sample.cs

using System;

Chapter 8. Working with the .NET Data Providers

261

7884ch08.fm

Draft Document for Review August 23, 2010 10:53 am using System.Data; using IBM.Data.Informix; class sample {

static void Main(string[] args) {

IfxConnection conn;

conn = new IfxConnection("Server=demo_on;database=stores_demo");

conn.Open();

IfxCommand cmmd = conn.CreateCommand();

cmmd.CommandText = "SELECT * FROM state WHERE code='CA'";

IfxDataAdapter dadap = new IfxDataAdapter();

DataSet dset = new DataSet();

dadap.SelectCommand = cmmd;

dadap.Fill(dset);

foreach(DataRow dr in dset.Tables[0].Rows) {

Console.WriteLine(String.Format("\tCode\tState\n"));

Console.WriteLine(String.Format("\t{0}\t{1}", dr["code"], dr["sname"]));

}

conn.Close();

}

}

Example 8-11 shows the data returned by the DataSet object.

Example 8-11 Output of Dataadapter_sample.cs

C:\work>csc.exe /R:%INFORMIXDIR%\bin\netf20\IBM.Data.Informix.dll /nologo dataadapter_sample.cs

C:\work>dataadapter_sample.exe

Code State

CA California

C:\work>

IfxDataReader

The

IfxDataReader

class provides fast read-only, forward-only access to a set of rows, similar to SQL cursors data. To create an

IfxDataReader

object the application calls the

ExecuteReader()

method of the

IfxCommand

object.

262

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch08.fm

IfxDataReader inheres from the System.Data.Common.DbDataReader

. It provides all common DbDataReader methods as well as additional methods to handle

Informix specific data types.

Table 8-10 contains the additional public methods of the IfxDataReader class.

Table 8-10 Additional methods of IfxDataReader

Method Description

Boolean GetBoolean()

TimeSpan GetTimeSpan()

Gets the value of the specified column as a Boolean.

Gets the time span value of the specified field.

IfxBlob GetIfxBlob()

IfxClob GetIfxClob()

IfxDateTime GetIfxDateTime()

IfxDecimal GetIfxDecimal

IfxMonthSpan

GetIfxMonthSpan

IfxTimeSpan GetIfxTimeSpan

Gets the IfxBlob value of the specific field.

Gets the IfxClob value of the specific field.

Gets the IfxDateTime value of the specific field.

Gets the GetIfxDecimal value of the specific field.

Gets the IfxMonthSpan value of the specific field.

Gets the IfxTimeSpan value of the specific field.

Refer to the IBM Informix .NET Provider Guide for a complete list of all the

IfxDataReader public methods at http://publib.boulder.ibm.com/infocenter/idshelp/v115/topic/com.ibm.netpr.doc/n etpr031023156.htm#netpr031023156

Note: Even if the

IfxDataReader.Read()

method returns only one row each time it is called, the provider may retrieve more than one row from the database. The .NET provider does this to increase performance. The application can set the number of rows the provider fetches from the database using the

IfxCommand

property

RowFetchCount

.

Example 8-12 demonstrates how to use a

IfxDataReader to access a database table.

Example 8-12 Datareader_sample.cs

using System; using System.Data; using IBM.Data.Informix; class sample {

static void Main(string[] args) {

Chapter 8. Working with the .NET Data Providers

263

7884ch08.fm

Draft Document for Review August 23, 2010 10:53 am

IfxConnection conn;

conn = new IfxConnection("Server=demo_on;database=stores_demo");

conn.Open();

IfxCommand cmmd = conn.CreateCommand();

cmmd.CommandText = "SELECT * FROM state WHERE code='CA'";

IfxDataReader drdr;

drdr = cmmd.ExecuteReader();

while (drdr.Read()) {

Console.WriteLine(String.Format("\tCode\tState\n"));

Console.Write(String.Format("\t{0}", drdr.GetString(0)));

Console.WriteLine(String.Format("\t{0}", drdr.GetString(1)));

}

drdr.Close();

conn.Close();

}

}

Example 8-13 shows the output of Example 8-12 on page 263.

Example 8-13 Output of Datareader_sample.cs

C:\work>csc.exe /R:%INFORMIXDIR%\bin\netf20\IBM.Data.Informix.dll /nologo datareader_sample.cs

C:\work>datareader_sample.exe

Code State

CA California

C:\work>

IfxError

The

IfxError

class collects information relevant to a warning or error returned by the database. You can use IfxError and

IfxErrorCollection

to retrieve additional information when an error occurs.

An application can access this information using the properties of the

IfxError

object listed in Table 8-11 on page 264.

Table 8-11 IfxError properties

Property Type

Message String

Description

Text message

264

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch08.fm

Property

NativeError

SQLState

Type

Int32

String

Description

IBM Informix error code

ANSI SQL error code

Example 8-14 desmonstrates a typical use of the

IfxError class. The

IfxException class contains one or more IfxError objects.

Example 8-14 Error_sample.cs

using System; using System.Data; using IBM.Data.Informix; class Connect {

static void Main(string[] args) {

IfxConnection conn;

int drows=0;

try {

conn = new IfxConnection("Server=demo_on;database=wrong_db");

conn.Open();

Console.WriteLine("Connected");

conn.Close();

}

catch (IfxException e) {

Console.WriteLine("----------------------------");

if (e.Errors.Count > 0) {

IfxError ifxErr = e.Errors[0];

Console.WriteLine("Message :" + ifxErr.Message);

Console.WriteLine("Native error :" + ifxErr.NativeError);

Console.WriteLine("SQL state :" + ifxErr.SQLState );

}

Console.WriteLine(e.StackTrace);

Console.WriteLine("----------------------------");

}

}

}

IfxParameter

The IfxParameter class is used to pass parameters to the IfxCommand method.

IfxParameters are stored as a collection in a IfxParameterCollection object.

Chapter 8. Working with the .NET Data Providers

265

7884ch08.fm

Draft Document for Review August 23, 2010 10:53 am

Table 8-12 contains the public attributes of a IfxParameter object.

Table 8-12 IfxParameter attributes

Property Type

DbType

Direction

DbType

ParameterDirection

IfxType

IsNullable

ParameterName

SourceColumn

SourceVersion

Value

IfxType

Boolean

String

String

DataRowVersion

Object

Description

Defines the DbType of the parameter.

Defines the direction of the parameter

(Input, Output or both).

Defines the IfxType of the parameter.

Specifies whether the parameter is allowed to be null.

Name of the parameter. Unique reference in the parameter collection.

Specifies the column that is mapped to the DataSet.

Defines the DataRowVersion to use when you load Value.

value of the parameter.

Example 8-15 shows how to use

IfxParameter

to perform an UPDATE operation.

Example 8-15 Parameter_sample.cs

using System; using System.Data; using IBM.Data.Informix; class sample {

static void Main(string[] args) {

IfxConnection conn;

int urows=0;

try {

conn = new IfxConnection("Server=demo_on;database=stores_demo");

conn.Open();

IfxCommand cmmd = conn.CreateCommand();

cmmd.CommandText = "UPDATE state SET sname = ? where code = ?";

IfxParameter pcode = new IfxParameter(“code”, DbType.String);

IfxParameter psname = new IfxParameter(“sname”, DbType.String);

pcode.Value="CA";

psname.Value="CALIFORNIA";

266

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

cmmd.Parameters.Add(psname);

cmmd.Parameters.Add(pcode);

urows = cmmd.ExecuteNonQuery();

Console.WriteLine("Updated rows: "+urows.ToString());

conn.Close();

}

catch (Exception e) {

Console.WriteLine(e.Message);

}

}

}

7884ch08.fm

You can see the output in Example 8-16

Example 8-16 Output of Parameter_sample.cs

C:\work>csc.exe /R:%INFORMIXDIR%\bin\netf20\IBM.Data.Informix.dll /nologo parameter_sample.cs

C:\work>parameter_sample.exe

Updated rows: 1

C:\work>

IfxTransaction

The IfxTransaction class represents an SQL transaction to be made at a database. The application creates an transaction by calling the

BeginTransaction method of the IfxConnection object.

IfxConnection.BeginTransaction() returns a IfxTransaction object. When the application decides how to resolve the transaction, it uses the Commit and

Rollback methods of the IfxTransaction object.

Any IfxCommand involved in a transaction must have the transaction property set to the IfxTransaction object.

Example 8-17 on page 267 demonstrates how to create a transaction.

Example 8-17 Creating a transaction using lfxTransaction

using System; using System.Data; using IBM.Data.Informix; class sample {

Chapter 8. Working with the .NET Data Providers

267

7884ch08.fm

Draft Document for Review August 23, 2010 10:53 am

static void Main(string[] args) {

IfxConnection conn;

int drows=0;

try {

conn = new IfxConnection("Server=demo_on;database=stores_demo");

conn.Open();

IfxTransaction trans = conn.BeginTransaction();

IfxCommand cmmd = conn.CreateCommand();

cmmd.Transaction = trans;

cmmd.CommandText = "DROP TABLE state";

drows = cmmd.ExecuteNonQuery();

trans.Rollback();

conn.Close();

}

catch (Exception e) {

Console.WriteLine(e.Message);

}

}

}

You can specify the following Isolation levels with the

BeginTransaction() method:

򐂰 ReadUncommitted

򐂰 ReadCommitted

򐂰 RepeatableRead

򐂰 Serializable

The default Isolation level is ReadCommited.

Example 8-18 demonstrates how to run a distributed transaction.

Example 8-18 Transact_cts.cs

using System; using System.Data; using IBM.Data.Informix; using System.Transactions; class sample {

static void Main(string[] args) {

IfxConnection conn;

268

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch08.fm

try {

conn = new IfxConnection("Server=demo_on;database=stores_demo");

// Transaction options

TransactionOptions tsopt = new TransactionOptions();

tsopt.IsolationLevel =

System.Transactions.IsolationLevel.RepeatableRead;

tsopt.Timeout = new TimeSpan(0, 60, 0);

using (TransactionScope tscope = new TransactionScope(

TransactionScopeOption.RequiresNew, tsopt,

EnterpriseServicesInteropOption.Full))

{

conn.Open();

IfxCommand cmmd = conn.CreateCommand();

cmmd.CommandText = "DROP TABLE state";

cmmd.ExecuteNonQuery();

// Rollback the distributed transaction not calling Complete()

// tscope.Complete();

}

}

catch (Exception e) {

Console.WriteLine(e.Message);

}

}

}

8.3.4 Handling Informix specific data types

In this section we cover how to work with IBM Informix specific data types such as Smart Large Objects or Decimal using the .NET Provider.

IfxBlob and IfxClob

CLOB and BLOB are Informix data types used to stored large amount of character or binary data.The application can handle these Smart Large Objects using the

IfxClob

and

IfxBlob

classes.

The method implemented on these classes allows random access of its contents.

The application can read or write to certain positions in the large object without reading or writing through all of the data up to that position.

BLOBs and CLOBs are both smart large object type. Both types share many of the same methods. BLOBs differ from CLOBs in that the data in a CLOB is

Chapter 8. Working with the .NET Data Providers

269

7884ch08.fm

Draft Document for Review August 23, 2010 10:53 am treated as text characters but the data in a BLOB is not. The data in a BLOB is considered to be binary data and no translation or conversion of any kind is performed on it when it is moved to or from the database server.

Properties and methods

Table 8-13 lists the

IfxBlob and IfxClob public properties.

Table 8-13 Properties of lfxBlob and lfxClob

Property Type Description

EstimatedSize

ExtentSize

Int64

Int32

Estimated final size of the large object

Next extent size for this large object (disk space)

Flags

IsNull

IsOpen

LastAccessTime

Int32

Boolean

Boolean

Int32

Flags for this large object

Checks if the large object is NULL

Checks if the large object is open

Last time the large object was accessed.

LastChangeTime Int32

LastModificationTime Int32

MaxBytes

Position

ReferenceCount

Int64

Int64

Int32

SBSpace

Size

String

Int64

Last time the status was changed

Last time the large object was modified

Maximum size for the large object.

Current position on the large object.

Number of records in the database that currently contain a reference to this large object.

Sbspace in which the large object is stored.

Size of the large object in byte.

Table 8-14 lists the available public methods from

IfxClob and IfxBlob classes.

Table 8-14 Public methods of lfxClob and lfxBlob

Method Description

void Open(mode)

IfxSmartLOBLocator GetLocator()

Int64 Read(buff), Read(buff, buffOffset, numBytesToRead, sLOBOffset, whence )

Opens a large object in a specific mode

Returns the IfxSmartLOBLocator associated with this instance.

Reads the complete data or a portion of a large object as a Byte[] or Char[]

270

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch08.fm

Method

Int64 Write(buff), Write( buff, buffOffset, numBytesToWrite, sLOBOffset, whence) void Truncate(offset)

Int64 Seek(offset, whence)

Description

Writes the complete buffer or a portion into a large object.

Truncates everything in the large object past the position offset.

Changes the current position within the large object.

void FromFile(filename, appendTosLOB, fileLocation)

Reads a operating system file and write the complete content into the large object.

String ToFile(filename, mode, fileLocation) Writes the contents of the large object to an operating system file.

void Lock(sLOBOffset, whence, range, lockMode)

Locks the complete large object or only a portion.

void Unlock(sLOBOffset, whence, range) Unlock a large object.

void Release() void Close()

Frees database server resources

Closes the large object

Creating a Smart Large Object

You can use the GetIfxClob() and GetIfxBlob() method of the

IfxConnection() object to create a large object. Perform the following steps to create a large object:

1. Create an instance of a the large object,

IfxClob

or

IfxBlob

.

2. Open the large object.

3. Write data into the large object.

4. Execute the SQL Statement using the IfxClob or IfxBlob as a parameter for the statement.

5. Close the large object.

Example 8-19 on page 271 demonstrate how to update a CLOB column. The

code reads a text file sample_blob.cs

and use the contents for the CLOB data

Example 8-19 Lo_create.cs

using System; using System.IO; using System.Data; using IBM.Data.Informix; class sample {

Chapter 8. Working with the .NET Data Providers

271

7884ch08.fm

Draft Document for Review August 23, 2010 10:53 am

static void Main(string[] args) {

IfxConnection conn;

int urows=0;

IfxClob vclob;

char[] vclobBuff;

try {

conn = new IfxConnection("Server=demo_on;Database=stores_demo");

conn.Open();

// Create and Open the Clob

vclob = conn.GetIfxClob();

vclob.Open(IfxSmartLOBOpenMode.ReadWrite);

// Read a text file and insert into the clob

vclobBuff = File.ReadAllText("lo_create.cs").ToCharArray();

vclob.Write(vclobBuff);

// Create the UPDATE Ifxcommand

IfxCommand cmmd = conn.CreateCommand();

cmmd.CommandText = "UPDATE catalog set advert_descr = ? WHERE" +

" catalog_num = ?;";

// Bind the IfxClob value and execute the UPDATE statement

IfxParameter padvt_desc = new IfxParameter(null, vclob);

IfxParameter pcatalog_n = new IfxParameter(null, "10072");

cmmd.Parameters.Add(padvt_desc);

cmmd.Parameters.Add(pcatalog_n);

urows = cmmd.ExecuteNonQuery();

Console.WriteLine("Updated rows: "+urows.ToString());

// Close the IfxClob object

vclob.Close();

conn.Close();

}

catch (Exception e) {

Console.WriteLine(e.Message);

}

}

}

If the application requires more control over the smart large object, it can use the specific properties of the ifxClob

and

IfxBlob

classes to set up values such as in which smart BLOB space the large object should be created, or the maximum size.

Example 8-20 Illustrates how to use the properties of the

IfxBlob

classes.

272

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch08.fm

Example 8-20 Large Object Extended properties

...

// Create and Open the Clob

vclob = conn.GetIfxClob();

vclob.EstimatedSize = 5000;

vclob.ExtentSize = 1000;

vclob.Flags = (int) IfxSmartLOBCreateTimeFlags.DontKeepAccessTime |

(int) IfxSmartLOBCreateTimeFlags.NoLog;

vclob.MaxBytes = 10000;

vclob.SBSpace = "sbspace";

vclob.Open(IfxSmartLOBOpenMode.ReadWrite);

...

Selecting a Smart Large Object

Reading a large object using the Large Object extensions require the following steps:

1. Execute the SQL Statement and retrieve the large object column.

2. Open the large object.

3. Read from the large object into an application buffer.

4. Close the large object.

Example 8-21 shows how to read a large object column from a database table.

Example 8-21 Lo_select.cs

using System; using System.Data; using IBM.Data.Informix; class sample {

static void Main(string[] args) {

IfxConnection conn;

IfxClob vclob;

int maxSize = 2000;

char[] vclobBuff = new char[maxSize];

try {

conn = new IfxConnection("Server=demo_on;Database=stores_demo");

conn.Open();

// Select the large object from the database

IfxCommand cmmd = conn.CreateCommand();

cmmd.CommandText = "SELECT * FROM catalog WHERE catalog_num = 10072";

IfxDataReader drdr;

drdr = cmmd.ExecuteReader();

Chapter 8. Working with the .NET Data Providers

273

7884ch08.fm

Draft Document for Review August 23, 2010 10:53 am

while (drdr.Read()) {

// Get the large object. The clob is the 6th column

vclob = drdr.GetIfxClob(5);

// Open the large object

vclob.Open(IfxSmartLOBOpenMode.ReadOnly);

vclob.Read(vclobBuff, 0, maxSize, 0, IfxSmartLOBWhence.Current);

Console.WriteLine(vclobBuff);

// Close the large object

vclob.Close();

}

conn.Close();

}

catch (Exception e) {

Console.WriteLine(e.Message);

}

}

}

Random access

One of the benefits of the Smart Large Objects against a normal large object is the option of reading partial data.

The

Read(buff, buffOffset, BytesToRead, loOffset, whence)

method allows you to position the data pointer anywhere in the large object data and read from there.

The code in Example 8-22 shows how to read the last 10 bytes of a large object.

Example 8-22 Partial large object Read

...

// Read only the last 10 bytes of large object

int bytesToRead = 10;

vclob.Read(vclobBuff, 0, bytesToRead, (-1) * bytesToRead,

IfxSmartLOBWhence.End);

...

Smart Large Objects support random IO access. Using the

Seek(offset, whence)

method you can position anywhere in the large object and perform IO operations with the data.

Example 8-23 demonstrates how to update only a portion of a large object using

the

Seek()

method.

274

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

Example 8-23 Lo_seek.cs

using System; using System.Data; using IBM.Data.Informix;

7884ch08.fm

class sample {

static void Main(string[] args) {

IfxConnection conn;

IfxClob vclob;

int urows=0;

int maxSize = 100;

char[] vclobBuff = new char[maxSize];

try {

conn = new IfxConnection("Server=demo_on;Database=stores_demo");

conn.Open();

// Select the large object from the database

IfxCommand cmmd = conn.CreateCommand();

cmmd.CommandText = "SELECT * FROM catalog WHERE catalog_num = 10072";

IfxDataReader drdr;

drdr = cmmd.ExecuteReader();

drdr.Read();

// Get the large object. The clob is the 6th column

vclob = drdr.GetIfxClob(5);

// Open the large object

vclob.Open(IfxSmartLOBOpenMode.ReadWrite);

// Move the pointer 15 bytes from the beginning of the large object.

vclob.Seek(15,IfxSmartLOBWhence.Begin);

// Update the large object.

vclobBuff="//------------//".ToCharArray();

vclob.Write(vclobBuff);

drdr.Close();

// Update the column in the table

cmmd.CommandText = "UPDATE catalog set advert_descr = ? WHERE" +

" catalog_num = ?;";

// Bind the IfxClob value and execute the UPDATE statement

IfxParameter padvt_desc = new IfxParameter(null, vclob);

IfxParameter pcatalog_num = new IfxParameter(null, "10072");

cmmd.Parameters.Add(padvt_desc);

cmmd.Parameters.Add(pcatalog_num);

urows = cmmd.ExecuteNonQuery();

Console.WriteLine("Updated rows: "+urows.ToString());

Chapter 8. Working with the .NET Data Providers

275

7884ch08.fm

Draft Document for Review August 23, 2010 10:53 am

// Close the large object

vclob.Close();

conn.Close();

}

catch (Exception e) {

Console.WriteLine(e.Message);

}

}

}

Note: The IBM Data Server Provider for .NET does not support random I/O

access.

IfxDateTime

The IfxDateTime class represents the Informix DATETIME data type. The

IfxDateTime class provides support for all the precisions allowed in an Informix

DATETIME.

The Informix DATETIME data type is made of these time units:

򐂰

Year

򐂰

Month

򐂰

Day

򐂰

Hour

򐂰

Minute

򐂰

Second

򐂰

Fractions of a second

In an Informix database, the maximum precision for a DATETIME column is

YEAR

TO FRACTION(5)

. A DATETIME column can be defined with any precision from a year to fraction of a second allowing any subset of these units.

Table 8-15 lists the public properties of the IfxDataTime class.

Table 8-15 Public properties of IfxDataTime

Property Type Description

Date IfxDateTime A Year to Day IfxDateTime instance

Day

EndTimeUnit

Hour

MaxValue

Int32

IfxTimeUnit

Int32

IfxDateTime

The day portion of the value

The end time unit of the instance

The hour portion of the value

Maximum value allowed for this IfxDateTime

276

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch08.fm

Property

Millisecond

MinValue

Minute

Month

Now

Type

Int32

Int32

Description

Millisecond unit in this IfxDateTime

IfxDateTime Smalles value allowed for this IfxDateTime

Int32 Minute unit in this IfxDateTime

Month unit in this ifxDateTime

IfxDateTime Current date with a range of Year to Fraction (5)

Second Int32 Second unit of this IfxDateTime.

StartTimeUnit IfxTimeUnit Start time unit of this IfxDateTime

Ticks

Today

Year

Int64

IfxDateTime

Int32

Ticks from midnight on 1 Jan 0001

Current time with a range of Year to Day

Year unit of the value

Table 8-16 lists the the public methods of the

IfxDateTime

class.

Table 8-16 Public methods of IfxDateTime

Method Description

Add(IfxTimeSpan or IfxMonthSpan) Current value plus by object passed

AddDays(days)

AddMilliseconds(milliseconds)

AddMinutes(minutes)

AddMonths(months)

Current value plus days passed

Current value plus milliseconds passed

Current value plus minutes passed

Current value plus months passed

AddSeconds(seconds)

AddYears(years)

Compare(ifxDT1, ifxDT1)

CompareTo(obj)

Current value plus seconds passed

Current value plus years passed

Compare two IfxDataTime instances

Compare two IfxDataTime instances

DaysInMonth(year, month)

Equals(ifxDT1, ifxDT2)

Number of days in the month of the year

True if ifxDT1 is equal to ifxDT2

GreaterThan(ifxDT1, ifxDT2) True if ifxDT1 is later than ifxDT2

GreaterThanOrEqual(ifxDT1, ifxDT2) True if ifxDT1 is later or equal than ifxDT2

LessThan(ifxDT1, ifxDT2) True if ifxDT1 is earlier than ifxDT2

Chapter 8. Working with the .NET Data Providers

277

7884ch08.fm

Draft Document for Review August 23, 2010 10:53 am

Method

LessThanOrEqual(ifxDT1, ifxDT2)

NotEquals(ifxDT1, ifxDT2)

Parse(dateTimeStr)

Parse(dateTimeStr, start, end)

Parse(dateTimeStr, format, start, end)

ToString(), ToString (format)

Description

True if ifxDT1 is earlier or equal than ifxDT2

True if ifxDT1 is different than ifxDT2

New IfxDateTime with a value based on dateTimeStr

Calue of the instance as a string

To access a DATETIME column in the database, the application uses the

IfxGetDateTime()

method from the

IfxDataReader()

object.

Example 8-24 demostrate how to select a DATETIME data type from a table.

Example 8-24 Datetime.cs

using System; using System.Data; using IBM.Data.Informix; class sample {

static void Main(string[] args) {

IfxConnection conn;

IfxDateTime vdtime;

try {

conn = new IfxConnection("Server=demo_on;Database=stores_demo");

conn.Open();

// Select the datetime from the database

IfxCommand cmmd = conn.CreateCommand();

cmmd.CommandText = "SELECT * FROM cust_calls WHERE "

+ "customer_num = 106";

IfxDataReader drdr;

drdr = cmmd.ExecuteReader();

drdr.Read();

// Get the IfxDateTime from the recordset, 2nd columnd

vdtime = drdr.GetIfxDateTime(1);

Console.WriteLine("Call:\t"+vdtime);

Console.WriteLine("Hour :\t "+vdtime.Hour);

Console.WriteLine("Minute:\t"+vdtime.Minute);

conn.Close();

}

catch (Exception e) {

278

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

Console.WriteLine(e.Message);

}

}

}

7884ch08.fm

In Example 8-25 you can see the Hour and Minute units extracted from the

IfxDateTime object.

Example 8-25 Output of Datetime.cs

C:\work>csc.exe /R:%INFORMIXDIR%\bin\netf20\IBM.Data.Informix.dll /nologo datetime.cs

C:\work>datetime

Call: 2008-06-12 08:20

Hour : 8

Minute: 20

C:\work>c

Arithmetic operations between two IfxDateTime objects may return a lfxDateSpan() object or a IfxMonthSpan() object depending on the precision used by the IfxDateTime objects.

Example 8-26 shows the usage of the IfxDateSpan() class.

Example 8-26 Datetime2.cs

using System; using System.Data; using IBM.Data.Informix; class sample {

static void Main(string[] args) {

IfxConnection conn;

IfxDateTime vdtime,vrestime;

IfxTimeSpan vtimetaken;

try {

conn = new IfxConnection("Server=demo_on;Database=stores_demo");

conn.Open();

// Select the datetime from the database

IfxCommand cmmd = conn.CreateCommand();

cmmd.CommandText = "SELECT * FROM cust_calls WHERE "

+ "customer_num = 106";

IfxDataReader drdr;

drdr = cmmd.ExecuteReader();

Chapter 8. Working with the .NET Data Providers

279

7884ch08.fm

Draft Document for Review August 23, 2010 10:53 am

drdr.Read();

// Get the IfxDateTime from the recordset

vdtime = drdr.GetIfxDateTime(1);

vrestime = drdr.GetIfxDateTime(5);

// Stores the difference in an IfxTimeSpan object.

vtimetaken=vrestime-vdtime;

Console.WriteLine("Initiated at:\t"+vdtime);

Console.WriteLine("Resolved at:\t"+vrestime);

Console.WriteLine("Minutes taken:\t"+vtimetaken.Minutes);

conn.Close();

}

catch (Exception e) {

Console.WriteLine(e.Message);

}

}

}

IfxDecimal

An IfxDecimal object represents the Informix decimal data type. The DECIMAL data type on an Informix database can take two forms: DECIMAL(p) floating point and DECIMAL(p,s) fixed point. The Informix .NET IfxDecimal supports both versions.

Table 8-17 contains the description of the public properties of a

IfxDecimal object.

Table 8-17 Public properties of IfxDecimal

Property Type Description

E

IsFloating

IfxDecimal

Boolean

Irrational number e.

Whether is a floating number.

IsNull

IsPositive

MaxPrecision

MaxValue

Boolean

Boolean

Byte

IfxDecimal

Whether is NULL.

Whether is positive

Maximum precision supported (32).

Largest value allowed.

MinusOne

MinValue

Null

One

IfxDecimal

IfxDecimal

IfxDecimal

IfxDecimal

-1.

Smallest value allowed.

Null.

1.

280

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch08.fm

Property

Pi

Zero

Type

IfxDecimal

IfxDecimal

Description

Irrational number pi.

0.

Table 8-18 contains the description for the

IfxDecimal

public methods.

Table 8-18 Public methods of IfxDecimal

Method Description

Abs(IfxDec) Absolute value of IfxDec

Add(IfxDec1, IfxDec2)

Ceiling(IfxDec)

Clone()

Compare(IfxDec1, IfxDec2)

Sum of IfxDec1 and IfxDec2

Smallest integer that is not less than IfxDec

Creates a duplicate of this instance

Compares two IfxDecimal values

CompareTo(obj)

Divide(Dividend, Divisor)

Compares current instace with obj

Dividing result for Dividend by Divisor

Equals(obj) Equal

Equals(IfxDec1, IfxDec2) True if IfxDec1 is the same as IfxDec2

Floor(IfxDec)

GreaterThan(IfxDec1, IfxDec2)

GreaterThanOrEqual(IfxDec1,IfxDec

2)

Largest integer not larger than IfxDec

True if IfxDec1 > IfxDec2

True if IfxDec1 >= IfxDec2

LessThan(IfxDec1, IfxDec2) True if IfxDec1 < IfxDec2

LessThanOrEqual(IfxDec1, IfxDec2) True if IfxDec1 <= IfxDec2

Max(IfxDec1, IfxDec2)

Min(IfxDec1, IfxDec2)

Returns whichever is larger, IfxDec1 or IfxDec2

Whichever is smaller, IfxDec1 or IfxDec2

Modulo(a, b)

Multiply(IfxDec1, IfxDec2)

Negate(IfxDec)

NotEquals(IfxDec1, IfxDec2)

Parse(DecString)

Returns the remainder

Returns IfxDec1 times IfxDec2

Current value negated

True if IfxDec1<>IfxDec2

Returns a new IfxDecimal based on DecString

Chapter 8. Working with the .NET Data Providers

281

7884ch08.fm

Draft Document for Review August 23, 2010 10:53 am

Method

Remainder(a, b)

Round(IfxDec1, FractionDigits)

Subtract(IfxDec1, IfxDec2)

ToString(), ToString (format)

Truncate(IfxDec1, FractionDigits)

Description

Remainder of the integer division of a by b

Value of IfxDec1 rounded to FractionDigits

Returns IfxDec1 minus IfxDec2

Returns the current value as a string

Round() with truncation

An application uses the GetIfxDecimal() method from the IfxDataReader() class to access a DECIMAL column from the database.

Example 8-27 demonstrates how to retrieve a DECIMAL column

Example 8-27 Decimal.cs

using System; using System.Data; using IBM.Data.Informix; class sample {

static void Main(string[] args) {

IfxConnection conn;

IfxDecimal vtax;

try {

conn = new IfxConnection("Server=demo_on;Database=stores_demo");

conn.Open();

// Select the datetime from the database

IfxCommand cmmd = conn.CreateCommand();

cmmd.CommandText = "SELECT * FROM state WHERE "

+ "code = 'CA'";

IfxDataReader drdr;

drdr = cmmd.ExecuteReader();

drdr.Read();

// Get the IfxDecimal from the recordset

vtax = drdr.GetIfxDecimal(2);

Console.WriteLine("Value Sales Tax :\t "+vtax);

Console.WriteLine("Ceiling Sales Tax :\t " + IfxDecimal.Ceiling(vtax));

Console.WriteLine("Negative Sales Tax :\t " + IfxDecimal.Negate(vtax));

conn.Close();

}

catch (Exception e) {

Console.WriteLine(e.Message);

282

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

}

}

}

7884ch08.fm

Example 8-28 shows the output of the previous example.

Example 8-28 Decimal.cs output

C:\work>csc.exe /R:%INFORMIXDIR%\bin\netf20\IBM.Data.Informix.dll /platform:x86 decimal.cs

C:\work>decimal

Value Sales Tax : 0.0825

Ceiling Sales Tax : 1.0

Negative Sales Tax : -0.0825

C:\work>

8.3.5 Troubleshooting

In this section we discuss typical errors seen when using the .NET Provider and how to enable the tracing facility to collect diagnostic information.

Typical errors

If the application is failing to connect to the Informix database server, check if connection string details are correct for the server and version of the .NET provider that you are using.

Both .NET providers use the ODBC or CLI layer to communicate with the database server. You can test the connection with these components before using the .NET provider.

When using the Informix .NET provider, always test the connectivity first using the

Ilogin

tool included in the Informix Client SDK package.

The Data Server Driver for .NET package includes the

Testconn11.exe

and

Testconn20.exe

executables which can be used to diagnose connectivity and setup problems when using the Data Server provider.

Table 8-19 contains some typical errors and how to resolved them.

Chapter 8. Working with the .NET Data Providers

283

7884ch08.fm

Draft Document for Review August 23, 2010 10:53 am

Table 8-19 Typical errors

Error

ERROR [IM009] [Informix

.NET provider]

Unable to load translation shared library (DLL)

Reason

The Informix .NET provider failed to load the ODBC shared library.

Solution

Check the values for the

INFORMIXDIR environment variable and PATH are correct.

INFORMIXDIR should point to your Client SDK install directory, PATH should contain the

%INFORMIXDIR%\bin directory.

Register the proper version of the .NET assembly into the

GAC using the gacutil.exe tool

System.BadImageFormat

Exception: An attempt was made to load a program with an incorrect format

Unhandled Exception:

System.EntryPointNotFou

ndException: Unable to find an entry point named

'InterlockedIncrement' in

DLL 'kernel32.dll'.

Unhandled Exception:

System.DllNotFoundExce

ption: Unable to load DLL

'IfxDotNetIntrinsicModule.

dll': The specified module could not be found.

A 32-bit application loading a 64-bit

IBM.Data.Informix assembly.

A 64-bit application loading a 32-bit

IBM.Data.Inforimx.dll assembly.

Failed to load

IfxDotNetIntrinsicModu le assembly required by the 64-bit version of the

Informix .NET provider

Register the proper version of the .NET assembly into the

GAC using the gacutil.exe tool

When using the 64-bit version of the .NET provider, the environment variable PATH should contains the

%INFORMIXDIR%\bin and

%INFORMIXDIR%\bin\netf20 directories

Tracing

Your application can set two types of tracing when using the Informix .NET provider:

򐂰

Informix .NET Trace

򐂰

SQLIDEBUG

Informix .NET trace

This trace is specific to the Informix .NET provider. To use this feature the application must use the Trace version of the IBM.Data.Informix assembly located in the

%INFORMIXDIR%\netf20

directory. The name of shared library is

IBM.Data.Trace.dll.

Register the assembly in the GAC and enable the trace by setting the environment variables

IFXDOTNETTRACE

and

IFXDOTNETTRACEFILE

.

284

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch08.fm

Example 8-29 demonstrates how to register the trace library and generate a

.NET trace file.

Example 8-29 Trace setup

C:\work>gacutil /i %INFORMIXDIR%\bin\netf20\IBM.Data.IfxTrace.dll /nologo

Assembly successfully added to the cache

C:\work>set IFXDOTNETTRACE=2

C:\work>set IFXDOTNETTRACE=trace.txt

C:\work>decimal

Value Sales Tax : 0.0825

Ceiling Sales Tax : 1.0

Negative Sales Tax : -0.0825

C:\work>dir trace.txt

Volume in drive C is W2003

Volume Serial Number is 50DA-70D7

Directory of C:\work

25/06/2010 13:52 13,172 trace.txt

1 File(s) 13,172 bytes

0 Dir(s) 76,259,311,616 bytes free

C:\work>

The .NET trace file contains information about all the .NET classes used and

their return values. Example 8-30 shows some of the entries in the .NET trace

file.

Example 8-30 .NET Trace file.

...

3532:1 Entry: IfxDecimal.ToString()

3532:1 Exit: IfxDecimal.ToString

IfxDecimal 0.0825

3532:1 Entry: IfxDecimal.ToString()

532:1 Exit: IfxDecimal.ToString

IfxDecimal -1.0

)

3532:1 Entry: IfxDecimal.get_IsNull()

3532:1 Exit: IfxDecimal.get_IsNull

532:1 Exit: IfxDecimal.Multiply

3532:1 Exit: IfxDecimal.Negate

3532:1 Entry: IfxConnection.Close()

3532:1 Entry: IfxConnection.GetLatch

Chapter 8. Working with the .NET Data Providers

285

7884ch08.fm

Draft Document for Review August 23, 2010 10:53 am

(

String IfxConnection.Close

)

...

The level of tracing is determine by the value of

IFXDOTNETTRACE

variable

򐂰 0, No tracing

򐂰

1, Tracing of API entry and exit, with return code

򐂰 2, Tracing of API entry and exit, with return code, plus tracing of parameters to the API

Levels 3 and 4 are for internal use only.

SQLIDEBUG and DRDADEBUG

Refer to the SQLIDEBUG section in 3.3.6, “Troubleshooting” on page 113

for the description and use of the SQLIDEBUG.

8.4 Visual Studio Add-In for Visual Studio

This section gives an overview of the Visual Studio Add-in. The IBM Database

Add-Ins for Visual Studio are a collection of features that integrate into Microsoft

Visual Studio development environment so that you can work with IBM Data servers.

Visual Studio Add-in Version 9.5 is compatible with Visual Studio 2005 and it uses the IBM Informix .NET Provider to connect to the database server.

Version 9.7 is compatible with Visual Studio 2005 and Visual Studio 2008 and uses the IBM Data Server for .NET.

Although it is not included in the Client SDK bundle, the VS Add-ins is available as a separate product: https://www.software.ibm.com/webapp/iwm/web/reg/download.do?source=swg-vsai

The Visual Studio Add-In provides tools and wizards that simplify the .NET development for common tasks such as:

򐂰

Explore catalog information of your database server.

򐂰 Generate DDL for your database objects.

򐂰

Drag and drop your server objects onto your .NET applications components to automatically generate the required ADO.NET code.

286

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch08.fm

The first step to use the Visual Studio Add-In is to define the IBM Informix server

into the Data Connections group of your Visual Studio environment. Figure 8-1

shows the Add Connection selection for adding a new server definition.

Figure 8-1 Server Explorer Add Connection

Figure 8-2 shows the Connection details dialog for a new server

Figure 8-2 Connection Dialog

Figure 8-3 shows two of the stores7 database tables dragged into a .NET

DataSet component.

Chapter 8. Working with the .NET Data Providers

287

7884ch08.fm

Draft Document for Review August 23, 2010 10:53 am

Figure 8-3 Visual Studio Add-in

For more details about using the IBM Database Add-Ins and the Data Server

Provider for .NET for application development, refer to the IBM Information

Management and Visual Studio .NET zone at http://www.ibm.com/developerworks/data/zones/vstudio

288

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch09.fm

9

Chapter 9.

Working with PHP

PHP is a widely-used general-purpose scripting language that is especially suited for web development and can be embedded into HTML. This chapter discusses the use of PHP with Informix as the database server. We discuss various PHP database extension which you can use to connect to informix.

Following that is the discussion about other components such as Apache Web server and OAT (OpenAdmin Tool) and how to bring these together. At the end we describes, in detail, the usage of programming interfaces provided by the selected PHP database extensions through the use of various examples.

We discuss the following SQL and database concepts:

򐂰 Database connections

򐂰 Basic database operations like Insert, Delete, Update.

򐂰 Handling special data types (BLOB, CLOB, TEXT and BYTE)

򐂰 Exception handling

򐂰 Troubleshooting

© Copyright IBM Corp. 2010. All rights reserved.

289

7884ch09.fm

Draft Document for Review August 23, 2010 10:53 am

9.1 Informix and PHP extensions

The PHP Data Objects (PDO) extension defines a lightweight, consistent interface for accessing databases in PHP. Each database driver that implements the PDO interface can expose database-specific features as regular extension functions.

Informix database can be accessed by PHP using two PDO drivers:

򐂰 PDO_INFORMIX

This is also called PHP Driver for IBM Informix.

To compile and use the driver, you must install the Informix Client Software Development Kit. You can download this driver from http://pecl.php.net/package/PDO_INFORMIX

򐂰 PDO_IBM

This driver is also know as PHP Driver for Data Server clients. The PHP

Driver for Data Server clients requires the IBM Data Server Driver for ODBC and CLI to be installed on the same computer. This driver can be accessed from the site http://pecl.php.net/package/PDO_IBM

In addition to these two drivers, there are two PHP extensions which allows you to access an IBM Informix database:

򐂰 PHP_INFORMIX

This extension only provides support for standard Informix data types. This extension is developed by the open source community and is available at http://cvs.php.net/viewvc.cgi/pecl/informix/

򐂰 IBM_DB2

This extension is available under the IBM Data Server Driver Package, and is written, maintained, and supported by IBM. It supports the Informix and DB2 databases.

Choosing the driver

Your application development environment, including hardware and software, should determine which PHP drivers and extensions to use. If the platform of your choice is not supported by IBM Data Server Driver or if you are using some of the data types not supported by IBM Data Server Driver then go for the

Informix driver. The Data Server Driver for ODBC and CLI requires an Informix database of Version v11.x or later. If your database server is exclusively Informix,

290

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch09.fm

then there is no problem using the Informix driver. You can also use both drivers simultaneously if such need arises.

9.2 Setup and configuration

To develop an PHP application for Informix, your application development system should have the following software:

򐂰

PHP drivers and extensions:

Choose one of the PHP driver or extension supported by Informix. The PHP

Driver for IBM Informix requires the Informix Client SDK and the PHP Driver for Data Server clients requires the IBM Data Server Driver for ODBC and

CLI. Refer to 2.2, “Client setup” on page 31 for the details.

򐂰

Web Server

You can either install Apache Web server or use OpenAdmin Tool (OAT) which is a PHP-based Web browser administration tool. Installing OAT is an easier option because it contains everything that is required for PHP connectivity. At the time of writing this book, OAT version 2.2.7 has:

– Apache 2.2.4

– PHP 5.2.4

– PDO_INFORMIX 1.2.6

In this section we discuss OAT installation and driver configuration. For installing the latest Apache Web server, refer to the website http://httpd.apache.org/

9.2.1 Installation of OAT

The OAT product is available for Windows, Linux, and Macintosh OS X (64-bit only) at the OpenAdmin Tool website at http://www.openadmintool.org

This will lead to the IBM site that requires you to register and login.

Once you have completed the download, the installation procedure is as follows:

1. Start the installation with one of the following methods:

– GUI Mode: Launch the installation executable:

• On Windows: Run install.exe

.

• On Linux: Run install.bin

.

• MAC OS X: Unzip the install.zip

file, and run install.app.

Chapter 9. Working with PHP

291

7884ch09.fm

Draft Document for Review August 23, 2010 10:53 am

– Console Mode: Enter the following commands:

• Windows: install.exe -i console

• Linux: install.bin -i console

2. Accept the license agreement to continue.

3. Select the installation directory. The default is:

– For Windows: C:\Program Files\OpenAdmin

– For Linux: /opt/OpenAdmin

– For MAC OS X: /Applications/OpenAdmin/

4. Choose an available port number for the Web server.

5. For Windows users, provide an Apache service name.

6. Specify the host name which is the name of the computer where the database server is located.

7. In the Security Features panel, to enable password-protection for the

OpenAdmin Tool administration pages, select the check box.

8. In the OAT Administrator login setup panel, enter a user name and password.

9. In the Plug-in page, ensure that the plug-ins that you want to install are selected. Accept the license agreement.

10.In the Pre- Installation Summary panel, review your selections and proceed the installation. When the installation is complete, the following message is displayed

OpenAdmin Tool has been installed successfully. Please visit http://servername:portnumber/openadmin/ to use the OpenAdmin Tool

Where:

– servername is the name of the machine where the Web server is running.

This can be localhost on Windows.

– portnumber

is the port number that you provided in step 4.

11.Click Done.

– For Linux and MAC OS X: The OpenAdmin Tool configuration page opens in your default Web browser.

– For Windows: Your machine needs reboot. You can access OAT from the

Start

All Programs

OpenAdmin Tool for IDS.

For an insight into OpenAdmin Tool, read the release notes and the README file which comes bundled with the product.

292

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch09.fm

9.2.2 PDO_INFORMIX

We discuss the installation of the PDO_INFORMIX driver in 2.2.3, “Setting up

IBM Data Server drivers” on page 40. PDO_INFORMIX driver is also installed

automatically when you install OAT.

We use the PDO_INFORMIX driver and the Apache web server that is installed with OAT in a Windows system for the examples in this chapter.

On successful installation of OAT, the shared library php_pdo_informix.ddl

(.so in Linux) is placed in the PHP extension directory. For example, if your installation directory is C:\Program FIles\OpenAdmin , the shared library is in the directory

C:\Program Files\OpenAdmin\PHP_5.2.4\ext .

To verify if the PHP extensions are working, in a web browser give the following

URL: http://localhost:8080/phpinfo.php

This should give a web page similar to the one in Figure 9-1. The picture shown

here is only the initial part of the entire html page.

Figure 9-1 partial picture of output from phpinfo() script

Chapter 9. Working with PHP

293

7884ch09.fm

Draft Document for Review August 23, 2010 10:53 am

9.2.3 PDO_IBM

The installation of PDO_IBM driver is discussed in 2.2.3, “Setting up IBM Data

Server drivers” on page 40. Depending on your platform copy, add the .dll or .so

to the OpenAdmin extension directory and change the php.ini

to include the extension php_pdo_ibm.dll

or php_pdo_ibm.so

.

9.2.4 Verifying the PDO setup

You can see which PDO driver has been loaded by the Apache web server by typing the URL http://localhost:8080/phpinfo.php

in your browser. Figure 9-2

shows that the PDO_INFORMIX and PDO_SQLITE driver are available to use.

Figure 9-2 output from phpinfo() function

9.2.5 Verifying connectivity

You can use a simple PHP program to verify the connectivity to the Informix server using the installed Informix PHP drivers or extensions.

Example 9-1 on page 295 shows a simple PHP script which connects to the

database server using the PDO_INFORMIX driver. In the conn_string variable, set the proper host name, user name, and password, and the respective locales.

The first keyword in the connection string identify which PDO driver is been used.

The PDO_INFORMIX driver uses informix and the PDO_IBM driver uses ibm.

294

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch09.fm

Example 9-1 connect.php

<?php

$informixdir = getenv("INFORMIXDIR");

$uname = "informix"; $password= "123456";

$conn_string = "informix: host=9.12.4.65; service=9088; database=stores_demo; server=ol_svr_custom; protocol=onsoctcp; CLIENT_LOCALE=EN_US.CP1252 ;

$sql = "SELECT dbinfo('version', 'major') version FROM systables WHERE tabid=1";

try {

print "<li>informixdir = $informixdir</li>\n";

$conn = new PDO($conn_string, $uname, $password);

$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

print "<li>Got a connection</li>\n";

$stmt = $conn->query($sql);

if ( ! $stmt ) {

print "Error in execute: stmt->execute()\n";

print "errInfo[0]=>$err[0]\nerrInfo[1]=>$err[1]\nerrInfo[2]=>$err [2]\n";

}

$row = $stmt->fetch();

print "<li>IDS version " . $row['VERSION'] . "</li>\n";

}

catch (Exception $e) {

print "Exception messsage:{$e->getMessage()}\n";

exit(0);}

?>

If you run the script from a browser, you should see an output like below: informixdir = C:\Program Files\IBM\Informix\

Got a connection

IDS version 11

You can use the same script to test the connectivity using the PDO_IBM driver,

by just changing the connection string. Example 9-2 shows a typical connection

string using the PD_IBM driver.

Example 9-2 PDO_IBM connection string.

$conn_string = "ibm: DRIVER={IBM DB2 ODBC

DRIVER};DATABASE=stores_demo;HOSTNAME=kodiak;PORT=9089;PROTOCOL=TCPIP;";

At this point, you know that your environment is set properly and you are ready to start using PHP with Informix.

Chapter 9. Working with PHP

295

7884ch09.fm

Draft Document for Review August 23, 2010 10:53 am

9.3 Developing a PHP application

PHP is a powerful server-side scripting language that was invented and designed for creating dynamic Web applications with non-static content. The PHP code can be a standalone program as well as an insert inside HTML (Hypertext

Markup Language) or XHTML (Extensible Hypertext Markup Language). The

PHP syntax is based mostly on and similar to C, Java, and Perl. You can use

PHP with an open-source license. You can run the PHP program directly from command line. The following are reasons for using PHP for our applications:

򐂰

Easy to use:

PHP is a scripting language included directly in HTML. This means that getting started is easy. There is no need to compile PHP programs or spend time learning tools to create PHP. You can simply insert statements and get quick turnaround as you make changes.

򐂰

Fully functional:

The PHP language has built-in functions to access your favorite database.

With PHP, your HTML pages can reflect current information from databases.

You can use information of the user viewing your HTML Web page to customize the page specifically for that user. You can create classes for object-oriented programming, or use flat file or Lightweight Directory Access

Protocol (LDAP) databases. It also includes a spell checker, XML functions, image generation functions, and more.

򐂰

Compatible and quick:

PHP is compatible with all Web browsers, because PHP generates plain

HTML.

򐂰

Secure:

Although PHP is open source, it is a secure environment. One of its advantages is that the Web clients can only see the pure HTML code. The logic of the PHP program is never exposed to the client, therefore, reducing security exposures.

򐂰

Open source:

PHP is an open-source programming language. It is easy to get started and find examples from websites, such as http://www.sourceforge.net

9.3.1 Connecting to database

Regardless of which PHP driver is used, PDO_INFORMIX or PDO_IBM, you must decide what type of connection to use for any database connection and what user type to use for authentication.

296

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch09.fm

Connection type

The connection type behavior is controlled by the Web server. There are two connection types:

򐂰 Persistence connection:

For the Persistent connection, the Web server will leave the connection to the database open after the PHP script finishes its work. The next attempt to connect to the database with the same parameters will reuse the connection.

򐂰 Standard connection:

For the Standard connection, the database connection will be closed when the script finishes its execution.

Here are some considerations for persistent connection:

򐂰 When using the persistent connection, the same connection will be used for the next request with the same connection parameters. This could cause some kind of connection pooling depending on the implementation and how you decide if the connection will be reused or not. Unintentional connection pooling is most likely a source of serious problems, even if you use transactions.

򐂰

Opening up a persistent connection only makes sense in a Web server environment if the connection will not be closed in the same script with a connection close call. Calling the PHP command line processor on the shell will close the connection to Informix database server at the end of the execution of the script.

򐂰 The Web server spawns more than one process to handle the incoming Web requests, so reusing the existing persistent connection is only valid for a specific Web server process. So it easily results in the database server having more connections open than actual running Web server processes.

򐂰

Restarting the database server without cleaning up the remaining persistent connections in the Web server environment will produce no errors at connection time when the connection is reused, but will fail at the first database statement. This type of error is hard to diagnose.

The user type

The user type is controlled by the database and has to do with authentication at the database server. You can choose an authentication with user ID and password in the connection string, or a trusted user connect where the database server does not apply an authentication. This will be controlled by settings on operating system resources, such as .rhosts or /etc/hosts.equiv

files. Since you have to specify user names and passwords in the PHP scripts, pay higher attention to these files in regard to security. Use encapsulation for files containing

Chapter 9. Working with PHP

297

7884ch09.fm

Draft Document for Review August 23, 2010 10:53 am the passwords and put these files in directories secured with the .htaccess

or httpd.conf

mechanism of the Apache Web server.

Informix PDO requires, at connection time, a defined set of parameters: database name and database server name. We suggest you use a user ID and password for untrusted user sessions. There are some optional parameters that can influence the cursor behavior. In this section, we focus on the required connection parameters.

Example 9-3 gives you a detailed overview about the various parameter settings

in an attempt to connect to the Informix database server. The examples shown are for PDO_INFORMIX. Choose one of the connection statements which meets your requirements.

Example 9-3 PDO_INFORMIX connection strings

/*--- standard connect ---*/

$dbc = new PDO("informix:; database=sysmaster; server=ol_svr_custom;","informix", "123456");

/*--- standard connect trusted user ---*/

$dbc = new PDO("informix:; database=sysmaster; server=ol_svr_custom;");

/*--- persistent connect untrusted user ---*/

$dbc = new PDO("informix:; database=sysmaster; server=ol_svr_custom;","informix","123456",array(PDO::ATTR_PERSISTENT=> true));

/*--- persistent connect trusted user ---*/

$dbc = new PDO("informix:; database=sysmaster; server=ol_svr_custom;",NULL,NULL,array(PDO::ATTR_PERSISTENT=> true));

PDO_IBM is based on the Data Server Driver CLI driver, this means it uses the same connectivity information as the ODBC and CLI driver. You can store this information as well as user credentials in the db2cli.ini

file located in the user

profile directory. Example 9-4 shows an example

db2cli.ini

file.

Example 9-4 db2cli.ini file

[dsc_dsn]

Protocol=TCPIP

Port=9089

Hostname=kodiak

Database=stores_demo

PWD=password

UID=password

298

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch09.fm

Having the details inside the db2cli.ini

file makes it easier to managed the information needed for the connection. You can use either of the connection

strings mentioned in the Example 9-5. The second

conn_string is using the file dbscli.ini

mentioned in Example 9-4 on page 298.

Example 9-5 PDO_IBM connection strings

$conn_string = "ibm: DRIVER={IBM DB2 ODBC DRIVER};DATABASE=stores_demo;

HOSTNAME=kodiak;PORT=9089;PROTOCOL=TCPIP;";

$conn_string = "ibm: DSN=dsc_dsn";

9.3.2 Performing database operations

Informix supports both static and dynamic SQL statements for the client applications such as PHP programs. In this section we provide an in-depth discussion about the abilities of handling dynamic and static SQL of PDO

Informix. We focus on the INSERT statement, but also give short examples for

DELETE and UPDATE statements.

Example 9-6 shows various ways of executing a static INSERT with Informix

PDO.

Example 9-6 INSERT, UPDATE and DELETE using PDO_INFORMIX

<?php

$informixdir = getenv("INFORMIXDIR");

$dbc = new PDO("informix:; database=stores_demo;

server=ol_svr_custom;","informix", "123456");

$sql = "INSERT INTO customer VALUES(0,'Carla','Gomes','All kitchen supplies',

'2440 Cavaleras blvd', '', 'San Jose','CA','93086', '408-777-8075');";

$dbc->exec($sql);

$error=$dbc->errorInfo(); if ( $error["1"]) { printf(" execute insert failed with %s <br>",$error["1"]); exit(1);

}

/*--- Using PDO::query for the insert ---*/

$dbc->query($sql);

$error=$dbc->errorInfo(); if ( $error["1"]) { printf(" execute insert failed with %s <br>",$error["1"]); exit(1);

}

/*--- Using PDO::prepare and PDO::sql::execute for the insert ---*/

Chapter 9. Working with PHP

299

7884ch09.fm

Draft Document for Review August 23, 2010 10:53 am

$stmt=$dbc->prepare($sql);

$error=$dbc->errorInfo(); if ( $error["1"]) { printf(" prepare insert failed with %s <br>",$error["1"]); exit(1);

}

$stmt->execute();

$error=$dbc->errorInfo(); if ( $error["1"]) { printf(" execute insert failed with %s <br>",$error["1"]); exit(1);

} printf("RowCount: %d <br>",$stmt->rowCount());

$stmt=$dbc->query("SELECT COUNT(*) FROM customer ");

$row=$stmt->fetch(PDO::FETCH_NUM); printf("<br>Total Rows in Table %d <br>", $row[0]);

?>

In a Web application, most of the time the input data comes from a HTML form

entered by a web user. Example 9-7 shows, based on a very simple HTML form,

how the data flows from the HTML over the PHP script into the database table.

Example 9-7 HTML sample basic html format

<?php

printf("<form method=\"post\" action=\"<your file name>.php\" >"); printf("fname <input name=\"fname\" /><br />"); printf("lname <input name=\"lname\" /><br />"); printf("company <input name=\"company\" /><br />"); printf("address1 <input name=\"address1\" /><br />"); printf("address2 <input name=\"address2\" /><br />"); printf("city <input name=\"city\" /><br />"); printf("state <input name=\"state\" /><br />"); printf("zipcode <input name=\"zipcode\" /><br />"); printf("phone <input name=\"phone\" /><br />"); printf("<input type=\"submit\" value=\"Confirm\" name=\"Button\"/>"); printf("<input type=\"submit\" value=\"Abort\" name=\"Cancel\"/>"); printf("</form>");

?>

Example 9-8 shows the PHP script which handles the HTML form. The array

$_POST contains all the settings for the buttons and the values for the text fields from the HTML.

Example 9-8 PHP Script handling the insert

<?php

300

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch09.fm

$dbc = new PDO("informix:host=9.14.23.34; database=stores_demo; server=ol_svr_custom; protocol=onsoctcp ", "informix", "123456"); if (!dbc) { exit();

}

/* --data from the Input Format

0|Carla|Gomes|Red Socks|217 Milpitas|Alum Rock|San Jose|CA|408-988-9887|

---*/

$statement="INSERT INTO customer VALUES (0,".

"'" . $_POST["fname"] . "'," .

"'" . $_POST["lname"] . "'," .

"'" . $_POST["company"] . "'," .

"'" . $_POST["address1"] . "'," .

"'" . $_POST["address2"] . "'," .

"'" . $_POST["city"] . "'," .

"'" . $_POST["state"] . "'," .

"'" . $_POST["zipcode"] . "'," .

"'" . $_POST["phone"] . "');"; printf ("STATEMENT = %s", $statement);

$dbc->query($statement);

$error=$dbc->errorInfo(); if ( $error["1"]) { printf(" prepare insert failed with %s \n",$error["1"]); exit(1);

}

?>

In Example 9-9, we show how to perform an update and a delete using the PDO

Informix extension.

Example 9-9 Update PHP script

<?php

$dbc = new PDO("informix:host=9.14.23.34; database=stores_demo; server=ol_svr_custom; protocol=onsoctcp ", "informix", "123456"); if (!dbc) { exit();

}

/*--- Static update that changes Redwood city to Fremont ---*/

$statement="UPDATE customer SET city='Fremont' where city='Redwood City'";

$stmt=$dbc->query($statement);

$error=$dbc->errorInfo(); if ( $error["1"]) { printf(" update failed with %s <br>",$error["1"]);

} printf("#Records updated: %d <br>",$stmt->rowCount());

/*--- Delete all records beloning to the company Sportstown; ---*/

$dbc->beginTransaction();

Chapter 9. Working with PHP

301

7884ch09.fm

Draft Document for Review August 23, 2010 10:53 am

$statement="DELETE FROM customer WHERE company='Sportstown'";

$stmt=$dbc->prepare($statement);

$stmt->execute();

printf("#Records deleted: %d <br>",$stmt->rowCount()); if ($stmt->rowCount()>10000)

{

$dbc->rollback();

} else {

$dbc->commit();

}

?>

Dynamic SQL and Informix PDO

Dynamic SQL allows an IBM Informix client side programs to build an SQL statement at runtime, so that the contents of the statement can be determined by user input. Informix PDO provides several ways to use dynamic SQL. You have to use placeholders, such as “?” or “:parameter”, to prepare a statement for dynamic usage. These placeholders will later be substituted with the actual values. The prepare once execute multiple times capability of dynamic statements allows you to specify different values at every execution time. To find out which statements and clauses allow placeholders, refer to http://publib.boulder.ibm.com/infocenter/idshelp/v115/topic/com.ibm.sqls.doc/sq ls.htm

.

This document also is a comprehensive reference of Informix SQL statements.

In Example 9-10, we show different INSERT statements using Informix PDO. To

learn more about using placeholders (“?”) and bind parameters, refer to PHP manual at http://php.net/manual/en/pdostatement.bindparam.php

Example 9-10 Parametrized insert

<?php

$dbc = new PDO("informix:host=9.14.23.34; database=stores_demo; server=ol_svr_custom; protocol=onsoctcp ", "informix", "123456"); if (!dbc) { exit();

}

/*--- dynamic inserts with "?" and bindParam ---*/

$stmt=

$dbc->prepare("INSERT INTO customer VALUES (0,?,?,?,?,?,?,?,?,?)");

$error=$dbc->errorInfo(); if ( $error["1"]) { printf(" prepare insert1 failed with %s \n",$error["1"]); exit(1);

302

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch09.fm

}

$stmt->bindParam(1, $_POST["fname"]);

$stmt->bindParam(2, $_POST["lname"]);

$stmt->bindParam(3, $_POST["company"]);

$stmt->bindParam(4, $_POST["address1"]);

$stmt->bindParam(5, $_POST["address2"]);

$stmt->bindParam(6, $_POST["city"]);

$stmt->bindParam(7, $_POST["state"]);

$stmt->bindParam(8, $_POST["zipcode"]);

$stmt->bindParam(9, $_POST["phone"]);

$stmt->execute();

$error=$dbc->errorInfo(); if ( $error["1"]) { printf(" prepare insert2 failed with %s \n",$error["1"]); exit(1);

}

/*--- dynamic inserts with :<> placeholders and bindParam ---*/

$stmt=

$dbc->prepare("INSERT INTO customer VALUES (0,:p1,:p2,:p3,:p4,:p5,:p6,:p7,:p8,:p9)");

$stmt->bindParam(':p1', $_POST["fname"]);

$stmt->bindParam(':p2', $_POST["lname"]);

$stmt->bindParam(':p3', $_POST["company"]);

$stmt->bindParam(':p4', $_POST["address1"]);

$stmt->bindParam(':p5', $_POST["address2"]);

$stmt->bindParam(':p6', $_POST["city"]);

$stmt->bindParam(':p7', $_POST["state"]);

$stmt->bindParam(':p8', $_POST["zipcode"]);

$stmt->bindParam(':p9', $_POST["phone"]);

$stmt->execute();

$error=$dbc->errorInfo(); if ( $error["1"]) { printf(" prepare insert2 failed with %s \n",$error["1"]); exit(1);

}

/*--- dynamic inserts with "?" placeholders and bindValue ---*/

$stmt=

$dbc->prepare("INSERT INTO customer VALUES (99,?,?,?,?,?,?,?,?,?)");

$stmt->bindValue(1, $_POST["fname"],PDO::PARAM_STR);

$stmt->bindValue(2, $_POST["lname"],PDO::PARAM_STR);

$stmt->bindValue(3, $_POST["company"],PDO::PARAM_STR);

$stmt->bindValue(4, $_POST["address1"],PDO::PARAM_STR);

$stmt->bindValue(5, $_POST["address2"],PDO::PARAM_STR);

$stmt->bindValue(6, $_POST["city"],PDO::PARAM_STR);

$stmt->bindValue(7, $_POST["state"],PDO::PARAM_STR);

$stmt->bindValue(8, $_POST["zipcode"],PDO::PARAM_STR);

$stmt->bindValue(9, $_POST["phone"],PDO::PARAM_STR);

$stmt->execute();

$error=$dbc->errorInfo(); if ( $error["1"]) { printf(" prepare insert3 failed with %s \n",$error["1"]); exit(1);

}

Chapter 9. Working with PHP

303

7884ch09.fm

Draft Document for Review August 23, 2010 10:53 am

/*--- dynamic inserts with :<> placeholders and bindValue ---*/

$stmt=

$dbc->prepare("INSERT INTO customer VALUES

(199,:p1,:p2,:p3,:p4,:p5,:p6,:p7,:p8,:p9)");

$stmt->bindValue(':p1', $_POST["fname"],PDO::PARAM_STR);

$stmt->bindValue(':p2', $_POST["lname"],PDO::PARAM_STR);

$stmt->bindValue(':p3', $_POST["company"],PDO::PARAM_STR);

$stmt->bindValue(':p4', $_POST["address1"],PDO::PARAM_STR);

$stmt->bindValue(':p5', $_POST["address2"],PDO::PARAM_STR);

$stmt->bindValue(':p6', $_POST["city"],PDO::PARAM_STR);

$stmt->bindValue(':p7', $_POST["state"],PDO::PARAM_STR);

$stmt->bindValue(':p8', $_POST["zipcode"],PDO::PARAM_STR);

$stmt->bindValue(':p9', $_POST["phone"],PDO::PARAM_STR);

$stmt->execute();

$error=$dbc->errorInfo(); if ( $error["1"]) { printf(" prepare4 insert failed with %s \n",$error["1"]); exit(1);

}

?>l

9.3.3 Handling complex data types

In this section, we discuss how to use complex data types in a PHP program. We cover row types, collection types such as SET, LIST and MULTISET, as well as the BLOB and SBLOB data types. We explain how to work with the complex data types using examples with Informix PDO.

Named row types

Example 9-11 shows the DDL to create a ROW type and the table that uses the

ROW type.

Example 9-11 DDL for creating ROW type and table

/*Create a row type and a table by name customer_rtype as below

CREATE ROW TYPE address_rtype ( street_num int, street_name char(20), city char(20), state char(20), zipcode char(10)

);

CREATE TABLE customer_rtype ( customer_num serial, lname char(15), fname char(15), company char(20),

304

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am address address_rtype, phone char(18)

);

7884ch09.fm

The PHP script in Example 9-12 shows SQL statements using ROW type. This

script inserts two rows, then selects the data from the database with and without a filter on the row type. It then updates one of the rows and delete the rows from the table.

Example 9-12 Insert complex types sample

<?php

$dbc = new PDO("informix:host=9.14.23.34; database=stores_demo; server=ol_svr_custom; protocol=onsoctcp ", "informix", "123456"); if (!dbc) { exit();

} printf(" <br>[ INSERT ] <br><br>");

/*--- Insert a row with a rowtype -- add a row to the newly created table ---*/

$dbc->query(' INSERT INTO customer_rtype VALUES (

0,"Carla","Gomes","All Sports",row(12345,"Broadway","San

Fransisco","CA","12345")::address_rtype, "408-908-8887")');

$dbc->query(' INSERT INTO customer_rtype VALUES (

0,"Smith","jones","Collin sports",row(1222,"Almeda blvd","Fremont","CA","12345")::address_rtype,"345-908-8887")'); printf(" <br>[ SELECT without filter] <br><br>");

/*--- Select the customer row without any filters ---*/

$stmt1=$dbc->query(" SELECT customer_num,fname,address.city,address.state,phone from customer_rtype");

$row=$stmt1->fetch(PDO::FETCH_ASSOC); while($row) { print_r($row); printf("<br>");

$row=$stmt1->fetch(PDO::FETCH_ASSOC);

} printf(" <br>[ SELECT with row_type filter ] <br><br>");

/*--- Select the row with a row_type filter ( a given address ) ---*/

$stmt1=$dbc->query(' SELECT customer_num , address.state, phone FROM customer_rtype

WHERE row(1222,"Almeda blvd","Fremont","CA","12345")::address_rtype = address');

$row=$stmt1->fetch(PDO::FETCH_ASSOC); while($row) { print_r($row); printf("<br>");

$row=$stmt1->fetch(PDO::FETCH_ASSOC);

} printf(" <br>[ UPDATE ] <br><br>");

/*--- update customer address ---*/

Chapter 9. Working with PHP

305

7884ch09.fm

Draft Document for Review August 23, 2010 10:53 am

$stmt1=$dbc->query(' UPDATE customer_rtype SET address=row(1234,"Almeda blvd","Fremont","CA","12345")::address_rtype WHERE row(1222,"Almeda blvd","Fremont","CA","12345")::address_rtype = address'); printf(" <br>[ SELECT ] <br><br>");

/*--- Verification ---*/

$stmt1=$dbc->query(' SELECT customer_num,fname, address::lvarchar FROM customer_rtype

WHERE address = row(1234,"Almeda blvd","Fremont","CA","12345")::address_rtype');

$row=$stmt1->fetch(PDO::FETCH_ASSOC); while($row) { print_r($row); printf("<br>");

$row=$stmt1->fetch(PDO::FETCH_ASSOC);

} printf(" <br>[ DELETE ] <br><br>");

/*--- close the buisness ---*/

$dbc->query(' DELETE FROM address_rowtype ');

$dbc->query(' DELETE FROM customer_rtype ');

?>

Example 9-13 shows the output from the SELECT statements to give you an idea

about how the array with row types looks in PHP.

Example 9-13 Output of ROW type example

[ INSERT ]

[ SELECT without row_type filter ]

Array ( [CUSTOMER_NUM] => 1 [FNAME] => Gomes [CITY] => San Fransisco [STATE] => CA

[PHONE] => 408-908-8887 )

Array ( [CUSTOMER_NUM] => 2 [FNAME] => jones [CITY] => Fremont [STATE] => CA [PHONE] =>

345-908-8887 )

[ SELECT with filter ]

Array ( [CUSTOMER_NUM] => 2 [STATE] => CA [PHONE] => 345-908-8887 )

[ UPDATE ]

[ SELECT ]

Array ( [CUSTOMER_NUM] => 2 [FNAME] => jones [] => ROW(1234 ,'Almeda blvd ','Fremont

','CA ','12345 ') )

[ DELETE ]

306

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch09.fm

Collection data types

The collection data types are another set of complex data types provided by the

Informix. Collection data types include SET, LIST, and MULTISET. In this section, we cover these collection data types by showing an example that inserts into and selects from a table containing collection data types.

Example 9-14 Using collection data types in PHP

<?php

/*create the tables containing collection data types

CREATE TABLE t_collections

(

seq serial not null,

l1 list (integer not null),

s1 set (integer not null),

m1 multiset(integer not null)

);

*/

$dbc = new PDO("informix:host=9.14.23.34; database=stores_demo; server=ol_svr_custom; protocol=onsoctcp ", "informix", "123456", array(PDO::ATTR_PERSISTENT=> true)); if (!dbc) { exit();

}

/*--- Insert a row ---*/ printf(" <br>[ Insert ] <br><br>");

$dbc->query(" INSERT INTO t_collections VALUES ( 0,

'LIST{-1,0,-2,3,0,0,32767,249}', 'SET{-1,0,-2,3}', 'MULTISET{-1,0,0,-2,3,0}')

");

$dbc->query(" INSERT INTO t_collections VALUES ( 0,

'LIST{-1,0,-2,3,0,0,55555,249}', 'SET{-11,0,-2,3}',

'MULTISET{-1,0,0,-2,3,0,9,10}') ");

/*--- select the row without any filters ---*/ printf(" <br>[ SELECT without filter] <br><br>");

$stmt1=$dbc->query(" SELECT l1::lvarchar LIST, s1::lvarchar SET, m1::lvarchar

MULTISET FROM t_collections");

$row=$stmt1->fetch(PDO::FETCH_ASSOC); while($row) { print_r($row); printf("<br>");

$row=$stmt1->fetch(PDO::FETCH_ASSOC);

}

/*--- select the row with a set filter for the color of the car ---*/ printf("<br> [ SELECT with filter] <br><br>");

$stmt1=$dbc->query(" SELECT l1::lvarchar LIST, s1::lvarchar SET, m1::lvarchar

MULTISET FROM t_collections WHERE 32767 IN l1");

Chapter 9. Working with PHP

307

7884ch09.fm

Draft Document for Review August 23, 2010 10:53 am

$row=$stmt1->fetch(PDO::FETCH_ASSOC); while($row) { print_r($row); printf("<br>");

$row=$stmt1->fetch(PDO::FETCH_ASSOC);

}

?>

Example 9-15 shows the output of Example 9-14 on page 307.

Example 9-15 The output of collection data type

[ Insert ]

[ SELECT without filter]

Array ( [LIST] => LIST{-1 ,0 ,-2 ,3 ,0 ,0 ,32767 ,249 } [SET] => SET{-1 ,0 ,-2

,3 } [MULTISET] => MULTISET{-1 ,0 ,0 ,-2 ,3 ,0 } )

Array ( [LIST] => LIST{-1 ,0 ,-2 ,3 ,0 ,0 ,55555 ,249 } [SET] => SET{-11 ,0 ,-2

,3 } [MULTISET] => MULTISET{-1 ,0 ,0 ,-2 ,3 ,0 ,9 ,10 } )

[ SELECT with filter]

Array ( [LIST] => LIST{-1 ,0 ,-2 ,3 ,0 ,0 ,32767 ,249 } [SET] => SET{-1 ,0 ,-2

,3 } [MULTISET] => MULTISET{-1 ,0 ,0 ,-2 ,3 ,0 } )

BLOB and SBLOB data types

With BLOB and SBLOB data types, Informix IDS can handle large objects as binary data in a BYTE data type and text objects in a TEXT data type. The BYTE and TEXT data types, commonly knows as BLOB data types or Simple Large

Objects, provides you the capability to store images and entire documents in the database. BLOB data types can be stored within all the other data in the table space, or in a separate specified BLOB space.

BLOB data types can be used in several operational areas. Commonly document retrieval systems and geographic information systems are based on this data type. The retrieval of BLOB data with SQL needs the define of keywords, which are stored together with the BLOB in the data row. The benefit of storing large data in the database is, beside an easy search via keywords and a combination of data stored in different rows but belonging together, also the opportunity of backup and restore and the apply of delete and update for specific data. Storing the data in a file in the operating system would cause much more maintenance effort.

308

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch09.fm

More advanced than the BLOB data types, Smart Large Objects (commonly know as SBLOB), provide more flexibility for searching in the data such as random I/O access to the data, which was impossible with Simple Large

Objects).

There are two types of SBLOBs, BLOB and CLOB. the BLOB data type is used to stored binary data when the CLOB data type is used only for character data.

There types require an additional set of functions defined in the server that provides an API for access. They are stored in an SBLOB space (smart BLOB space) in the database server.

You must create a sbspace to store the BLOB types in the server. You can create them with following command: onspaces -c -S sbspace -p <PATH> -o 0 -s 4000

We change the catalog table in stores database to use BLOB and CLOB instead of BYTE and TEXT using the following command:.

ALTER TABLE catalog MODIFY (cat_descr TEXT, cat_descr CLOB, cat_picture BYTE, cat_picture BLOB)

In the Example 9-16 we show how to insert and retrieve from data with SBLOB

data types, that is, BLOB and CLOB. The example shows how to insert the large data from files into a table and select the same data back into files in a local file system.

Example 9-16 Smart Large Object sample

<<?php

$dbc = new PDO("informix:host=9.14.23.34; database=stores_demo; server=ol_svr_custom; protocol=onsoctcp ", "informix", "123456"); if (!dbc) { exit(); }

/*--- try to insert the BLOB ---*/

$stmt= $dbc->prepare("INSERT INTO catalog VALUES (0,302,'KAR',?,?,'All sports

Goods')");

$file = fopen ("picture.jpg","r");

$image = fread ( $file, 100000) ; fclose ( $file);

$file = fopen ("README.txt","r");

$text = fread ( $file, 100000) ; fclose ( $file);

$stmt->bindParam(1, $text );

$stmt->bindParam(2, $image);

$stmt->execute();

$error=$dbc->errorInfo(); if ( $error["1"]) { printf(" execute insert blobs failed with %s \n",$error["1"]);

Chapter 9. Working with PHP

309

7884ch09.fm

Draft Document for Review August 23, 2010 10:53 am exit(1);

}

/*--- Get the BLOB from the database back ---*/

$query=$dbc->query("SELECT * FROM catalog where stock_num=302 and manu_code='KAR' ");

$error=$dbc->errorInfo(); if ( $error["1"]) { printf(" select blobs failed with %s \n",$error["1"]); exit(1);

}

$count=1;

$row=$query->fetch(PDO::FETCH_ASSOC); while ( $row ) {

$file = fopen ("README.$count.txt","w");

$test=fread($row["CAT_DESCR"],100000);

while($test) { fwrite ( $file, $test) ;

$test=fread($row["CAT_DESCR"],100000);

} fclose ( $file);

$file = fopen ("PICTURE.$count.jpg","w");

$test1=fread($row["CAT_PICTURE"],100000);

while($test1) { fwrite ( $file, $test1) ;

$test1=fread($row["CAT_PICTURE"],100000);

} fclose ( $file);

$count++;

$row=$query->fetch(PDO::FETCH_ASSOC);

}

?>

Using TEXT and BYTE (BLOB data types) is similar to SBLOB types. Users may

try Example 9-16 on page 309 and Example 9-17 using TEXT and BYTE instead

of CLOB and BLOB respectively.

The BLOB data to be inserted can be read from the file without placing it in a variable first. This simplifies the code

as can be seen in Example 9-17.

Example 9-17 Insert BLOB with file

<?php

$dbc = new PDO("informix:host=9.14.23.34; database=stores_demo; server=ol_svr_custom; protocol=onsoctcp ", "informix", "123456"); if (!dbc) { exit(); }

/*--- try to insert the BLOB ---*/

310

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch09.fm

$stmt= $dbc->prepare("INSERT INTO catalog VALUES (0,302,'KAR',?,?,'All sports

Goods')");

$file = fopen ("C:\README.txt","r");

$file1 = fopen ("C:\picture.jpg","r");

$stmt->bindParam(1,$file, PDO::PARAM_LOB);

$stmt->bindParam(2,$file1, PDO::PARAM_LOB);

$stmt->execute(); fclose($file); fclose($file1);

$error=$dbc->errorInfo(); if ( $error["1"]) { printf(" execute insert blobs failed with %s \n",$error["1"]); exit(1);

}

/*---try to get the BLOB from the database back ---*/

$query=$dbc->query("SELECT * FROM catalog where stock_num=302 and

manu_code='KAR' ");

$error=$dbc->errorInfo(); if ( $error["1"]) { printf(" select blobs failed with %s \n",$error["1"]); exit(1);

}

$count=1;

$row=$query->fetch(PDO::FETCH_ASSOC);

while ( $row ) {

$file = fopen ("C:\README.$count.txt","w");

$test=fread($row["CAT_DESCR"],100000); while($test) { fwrite ( $file, $test) ;

$test=fread($row["CAT_DESCR"],100000);

} fclose ( $file);

$file = fopen ("C:\PICTURE.$count.jpg","w");

$test1=fread($row["CAT_PICTURE"],100000);

while($test1) { fwrite ( $file, $test1) ;

$test1=fread($row["CAT_PICTURE"],100000);

} fclose ( $file);

$count++;

$row=$query->fetch(PDO::FETCH_ASSOC);

}

?>

In Example 9-17 on page 310, the data was selected as a stream in string data

type. Example 9-18 on page 312 shows how to bind variables to a SELECT.

Binding The data is placed in the variables by column.

Chapter 9. Working with PHP

311

7884ch09.fm

Draft Document for Review August 23, 2010 10:53 am

Example 9-18 Select BLOB with bind.

<?php

$dbc = new PDO("informix:host=9.14.23.34; database=stores_demo; server=ol_svr_custom; protocol=onsoctcp ", "informix", "123456"); if (!dbc) { exit(); }

/*--- try to select the BLOB from the database into bind strings ---*/

$stmt=$dbc->query("SELECT catalog_num, cat_descr, cat_picture FROM catalog where stock_num=302 and manu_code='KAR'");

$count=1;

$str="";

$str1="";

$id=0;

$stmt->bindColumn(1, $id, PDO::PARAM_INT);

$stmt->bindColumn(2, $str, PDO::PARAM_STR,100000);

$stmt->bindColumn(3, $str1, PDO::PARAM_STR,100000); while ( $stmt->fetch(PDO::FETCH_BOUND) )

{

$file = fopen ("C:\README.$count.txt","w");

$file1 = fopen ("C:\PICTURE.$count.jpg","w"); fwrite($file,$str); fwrite($file1,$str1); fclose ($file); fclose ($file1);

$count++;

}

?>

Example 9-19 shows how to update existing BLOB fields with Informix PDO

using a prepare statement and parameter for the BLOB columns.

Example 9-19 BLOB update

<?php

$dbc = new PDO("informix:host=9.14.23.34; database=stores_demo; server=ol_svr_custom; protocol=onsoctcp ", "informix", "123456"); if (!dbc) { exit(); }

/* try to update the BLOB columns

*/

$stmt= $dbc->prepare("UPDATE catalog SET cat_descr=? , cat_picture=? where

stock_num=302 and manu_code='KAR'");

$error=$dbc->errorInfo(); if ( $error["1"]) { printf(" prepare update blob columns failed with %s \n",$error["1"]); exit(1);

}

$descr="This is an PDO descr clob text";

312

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

$file= fopen ("C:\picture1.jpg","r");

$stmt->bindParam(1, $descr);

$stmt->bindParam(2, $file);

$stmt->execute();

$error=$dbc->errorInfo();

?>

7884ch09.fm

9.3.4 Working with PHP extensions

In addition to the PDO drivers for the PHP PDO extension, there are two PHP extensions, PHP_INFORMIX and IBM_DB2, that allow you to connect to an

Informix database server.

These extensions provide a set of additional PHP functions to work with an

Informix database. In addition to the normal create, read, update, and write database operations, they also offer extensive access to the database metadata.

Table 9-1 lists a few of the functions included in the Informix PHP extensions as

examples.

Table 9-1 PHP extension functions

Function Description

ifx_connect() Open Informix server connection ifx_fieldproperties() ifxus_open_slob() ifx_create_blob() ifx_fetch_row()

List of SQL fieldproperties

Opens an slob object

Creates an blob object

Get row as an associative array ifx_query() db2_connect() db2_client_info() db2_primary_keys() db2_special_columns() db2_bind_param() db2_commit()

Send Informix query

Returns a connection to a database

Returns information describing DB2 database client

Returns a result set listing primary keys for a table

Returns a result set listing the unique row identifier columns for a table

Binds a PHP variable to an SQL statement parameter

Commits a transaction

Chapter 9. Working with PHP

313

7884ch09.fm

Draft Document for Review August 23, 2010 10:53 am

For a complete list of all the functions implemented inthe PHP_INFORMIX and

IBM_DB2 extensions refer to the PHP open source website at http://www.php.net/manual/en/ref.ifx.php

http://www.php.net/manual/en/ref.ibm-db2.php

PHP_INFORMIX

A PHP script can connect to an Informix database using the ifx_connect() function provided in the PHP_INFORMIX extension.

Example 9-20 shows a simple PHP script used to test connectivity with the

PHP_INFORMIX extension.

Example 9-20 connect.php

C:\work>type connect.php

<?php

$conn= ifx_connect ($argv[1], $argv[2],$argv[3]);

echo "Connection succeeded.\n"; ifx_close($conn);

?>

C:\work>php connect.php stores_demo informix password

Connection succeeded.

C:\work>

Functions such as ifx_query() and ifx_affected_rows() can be used to run

SQL statements and retrieve the number of rows affected. Example 9-21

demonstrates how to delete a row from the state table using the ifx_query() function.

Example 9-21 delete.php

C:\work>type delete.php

<?php

$conn= ifx_connect ("stores_demo", "informix", "password");

$result = ifx_query("DELETE FROM state where code='".$argv[1]."'", $conn); printf("Deleted %d records", ifx_affected_rows($result)); ifx_close($conn);

?>

C:\work>php delete.php UK

Deleted 1 records

C:\work>

The application can select data from an Informix database using the ifx_prepare() and ifx_fetch_row() functions.

314

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch09.fm

Example 9-22 shows how to select the first three rows from the

state table using a prepared statement and the ifx_fetch_row() function.

Example 9-22 select.php

C:\work>cat select.php

<?php

$conn= ifx_connect ("stores_demo", "informix", "password");

$rid = ifx_prepare ("SELECT FIRST 3 code,sname FROM state",$conn, IFX_SCROLL); if (! ifx_do ($rid)) {

die ("error\n");

}

$row = ifx_fetch_row ($rid, "NEXT");

while (is_array($row)) {

for (reset($row); $fieldname=key($row); next($row)) {

$fieldvalue = $row[$fieldname];

printf ("%s = %s ", $fieldname, $fieldvalue);

}

printf("\n");

$row = ifx_fetch_row($rid, "NEXT");

} ifx_free_result ($rid); ifx_close($conn);

?>

C:\work>php select.php

code = AK sname = Alaska code = HI sname = Hawaii code = CA sname = California

C:\work>

For more information and examples regarding the PHP_INFORMIX extension, refer to the PHP open source website at: http://www.php.net/manual/en/book.ifx.php

IBM_DB2

This PHP extension provides access to IBM Data Servers including IBM Informix and IBM DB2.

In the same way as the PDO driver, PDO_IBM, The IBM_DB2 extension requires the IBM CLI driver to communicate with the database server. The IBM CLI driver is included as part of the IBM Data Server Driver for ODBC and CLI package.

This PHP extension provides functions such as db2_connect()

, db2_exec()

, and db2_server_info()

that can be used to perform typical tasks against an Informix database server.

Chapter 9. Working with PHP

315

7884ch09.fm

Draft Document for Review August 23, 2010 10:53 am

Example 9-23 demonstrates how to use the

db2_connect() and db2_server_info() functions to retrieve metadata information from the database.

Example 9-23 connect_ibm.php

C:\work>type "C:\Documents and Settings\Administrator\db2cli.ini"

[dsc_dsn]

Protocol=TCPIP

Port=9089

Hostname=kodiak

Database=stores_demo

C:\work>cat connect_ibm.php

<?php

$conn = db2_connect('dsc_dsn', 'informix','password'); if ($conn) {

echo "Connection succeeded.\n";

$server = db2_server_info( $conn );

printf ("Database name = %s\n", $server->DBMS_NAME);

printf ("Datbase version = %s\n", $server->DBMS_VER);

db2_close($conn);

} else {

echo "Connection failed.";

}

?>

C:\work>php connect_ibm.php

Connection succeeded.

Database name = IDS/NT64

Datbase version = 11.50.0000

C:\work>

The IBM_DB2 extension can use the connection details in the db2cli.ini

configuration file. Refer to the 3.2.2, “IBM Data Server Driver for ODBC and CLI” on page 66

for more information regarding the db2cli.ini configuration file.

There are several functions that can be used to select data from the database.

Example 9-24 shows how to use the

db2_fecth_object()

function to retrieve the first three rows of the state

table as a PHP object.

Example 9-24 select_ibm.php

C:\work>cat select_ibm.php

<?php

$conn = db2_connect('dsc_dsn', 'informix','password');

316

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch09.fm

if ($conn) {

echo "Connection succeeded.\n";

$stmt = db2_exec($conn, "SELECT FIRST 3 code,sname FROM state");

while ($row = db2_fetch_object($stmt)) {

printf ("%s, %s\n", $row->code,$row->sname);

}

db2_close($conn);

} else {

echo "Connection failed.";

}

?>

C:\work>php select_ibm.php

Connection succeeded.

AK, Alaska

HI, Hawaii

CA, California

C:\work>

A full description of the IBM_DB2 extension can be found in the Informix

Information Center website at: http://publib.boulder.ibm.com/infocenter/db2luw/v9/topic/com.ibm.db2.udb.apdv.p

hp.doc/doc/t0023132.htm

9.3.5 Exception handling

Error handling or exception handling is important for all applications, including web-based applications. Consider an Informix PHP application that shows the following error message while the user is using the application?

Warning: odbc_connect(): SQL error: [unixODBC][Informix][Informix

ODBCDriver][Informix]User (informix) password “123456” is not able to connect for the database server, Server is down, SQL state 28000 in SQLConnect in

/usr/local/apache2/htdocs/odbc/error/error.php on line 4

Fail in exception handling in this case creates a security exposure. In the this section we describe many aspects related to exception handling using Informix

PDO.

PHP 5 has introduced, as a part of the new object-oriented programming interface, the exception handling mechanism that are already used for other programming languages. We strongly suggest you consider exceptions for the usage of Informix PDO. Additionally, you can advance this interface by creating, throwing, and catching your own exceptions.

Chapter 9. Working with PHP

317

7884ch09.fm

Draft Document for Review August 23, 2010 10:53 am

Informix PDO defines, in comparison with the procedural-oriented interface, two ways of expressing an error in a database environment:

򐂰

Exceptions raised internally by the PDO based on an error condition.

򐂰 Database-generated errors. This type of exception can be captured and handled by calling the PDO class errorInfo() or errorCode() function.

Example 9-25 shows two exceptions raised by Informix PDO functions. One is a

connection request to the database that failed because the specified database does not exist. The other is an attempt to start a transaction twice.

Example 9-25 Without exception handling sample

<?php

$dbc = new PDO("informix:; database=stores; server=ol_svr_custom;","informix",

"123456");

?>

Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE=HY000,

SQLDriverConnect: -329 [Informix][Informix ODBC Driver][Informix]Database not

found or no system permission.' in C:\Program

Files\OpenAdmin\Apache_2.2.4\htdocs\excep1.php:2 Stack trace: #0 C:\Program

Files\OpenAdmin\Apache_2.2.4\htdocs\excep1.php(2): PDO->__construct('informix:; data...', 'informix', '123456') #1 {main} thrown in C:\Program

Files\OpenAdmin\Apache_2.2.4\htdocs\excep1.php on line 2

<?php

$dbc = new PDO("informix:; database=stores_demo; server=ol_svr_custom;","informix", "123456");

$dbc->beginTransaction();

$dbc->beginTransaction();

?>

Fatal error: Uncaught exception 'PDOException' with message 'There is already

an active transaction' in C:\Program

Files\OpenAdmin\Apache_2.2.4\htdocs\excep1.php:4 Stack trace: #0 C:\Program

Files\OpenAdmin\Apache_2.2.4\htdocs\excep1.php(4): PDO->beginTransaction() #1

{main} thrown in C:\Program Files\OpenAdmin\Apache_2.2.4\htdocs\excep1.php on line 4

If these exceptions are not caught and processed, the application terminates.

Example 9-26 on page 319 shows the usage of the basic exception handler

provided by PHP 5 to cover these errors. The action that should be taken once an exception is caught depends on where the error originates. For example, if the error occurs in the connecting to the database phase and the application cannot continue, the action should be to generate an “out of order” web page with contact details. If it is a minor database error, logging the error and retrying the activity should be an appropriate action.

318

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

Example 9-26 Simple exception handle code

<?php

try

{

$dbc = new PDO("informix:; database=stores_demo; server=ol_svr_custom;","informix", "123456");

$dbc->beginTransaction();

$dbc->beginTransaction();

}

catch (PDOException $e )

{ printf("Error: %s \n",$e->getMessage());

}

?>

Output:

Error: There is already an active transaction.

7884ch09.fm

The error information generated during executing the SQL statements in the database server is different from the exceptions generated by the Informix PDO extension. The Informix PDO function errorInfo() can be used to capture the status of the last executed SQL statement in the database. This function returns an array with three elements, the SQLSTATE, the SQLCODE, and the error message. The details of the meaning of the codes are described in http://publib.boulder.ibm.com/infocenter/idshelp/v115/topic/com.ibm.esqlc.doc/s ii-11-40709.htm#sii-11-40709.

The function errorCode()

is available to retrieve the SQL statement status. This

function returns only the SQLSTATE information. Example 9-27 shows how to

use the errorInfo()

and what the output looks like.

Example 9-27 ErrorInfo() sample

<?php

$dbc = new PDO("informix:; database=stores_demo; server=ol_svr_custom;","informix", "123456");

$stmt=$dbc->query('SELECT * FROM nonexistingtable ');

/* question the error code output of the error Routines

*/

$error=$dbc->errorInfo(); print_r($error);

if (!$error[1])

$row=$stmt->fetch(PDO::FETCH_ASSOC);

?>

Chapter 9. Working with PHP

319

7884ch09.fm

Draft Document for Review August 23, 2010 10:53 am

Output:

Array

(

[0] => 42S02

[1] => -206

[2] => [Informix][Informix ODBC Driver][Informix]The specified table

(nonexistingtable) is not in the database. (SQLPrepare[-206] at at ext\pdo_informix\informix_driver.c:118)

)

In addition to using the generic exceptions provided by the PHP 5, you are open to extend the exception class of your own exceptions. For example, you can define different severities for SQL errors. Critical database errors are, for instance, tables which do not exist or the database connections cannot be established. The application will not be able to continue with these critical errors.

Non-critical errors, such as locking errors, could be handled by a retry.

Example 9-28 demonstrates how to define your own exceptions with PHP 5 and

Informix PDO. This example extends the standard exception class with two new database exception classes, and depending on the severity, different actions are taken.

Example 9-28 Custom exceptions

<?php

/* own Exception classes for minor and major errors

*/

class CriticalDatabaseErrors extends Exception

{ public function __construct($message, $code = 0) { parent::__construct($message, $code);

}

}

class NonCriticalDatabaseErrors extends Exception

{

}

} public function __construct($message, $code = 0) { parent::__construct($message, $code); try

{

$dbc = new PDO("informix:host=9.14.23.34; database=stores_demo; server=ol_svr_custom; protocol=onsoctcp ", "informix", "123456");

$stmt=$dbc->exec("SET ISOLATION REPEATABLE READ");

$stmt=$dbc->query('SELECT * FROM carr');

$error=$dbc->errorInfo(); if (!$error[1]) { do

320

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch09.fm

{

$row=$stmt->fetch(PDO::FETCH_ASSOC);

$error=$dbc->errorInfo(); if ($error[1]) throw new NonCriticalDatabaseErrors($error[1]);

} while($row) ;

} else {

throw new CriticalDatabaseErrors($error[2]);

}

}

catch ( CriticalDatabaseErrors $cde )

{ printf("<pre>CritError!: %s \n</pre>",$cde->getMessage()) ;

}

catch ( NonCriticalDatabaseErrors $ncde )

{ printf("<pre>NonCritError!: %s \n</pre>",$ncde->getMessage()) ;

} catch (PDOExecption $ncde) {

printf("<pre>Error!: %s \n</pre>",$e->getMessage()) ; exit;

}

?>

Output:

CritError!: [Informix][Informix ODBC Driver][Informix]The specified table (carr) is not in the database. (SQLPrepare[-206] at ext\pdo_informix\informix_driver.c:131)

9.3.6 Troubleshooting

In this section we describe a couple of commonly seen errors in setting the database connectivity:

򐂰

Missing environment variable setting

Setting the environment variable INFORMIXDIR is required for starting the

Apache. If this variable is not set properly, the database connection will also

fail. Example 9-29 shows the error message when you have improper

INFORMIXDIR set. The message occurs at the first line of any PHP program which is generally the connection string. If you get this message check your

INFORMIXDIR setting and correct it if its wrongly set.

Example 9-29 Unspecified error

Error!: SQLSTATE=HY000, SQLDriverConnect: -23101

[Informix][Informix ODBC Driver][Informix]Unspecified System Error =

-23101.

򐂰 Mismatched settings

Chapter 9. Working with PHP

321

7884ch09.fm

Draft Document for Review August 23, 2010 10:53 am

Another important item affecting the connectivity is the setup of the Informix run-time environment. Informix Connect or Informix Client SDK provides the connectivity at run time. If the settings between the environment variables and the sqlhosts do not match, you will see messages similar to the one shown in

Example 9-30.

Example 9-30 Wrong connection information

/usr/local/bin/php pdoconnect.php

Error!: SQLSTATE=HY000, SQLDriverConnect: -25555

[Informix] [Informix ODBC Driver][Informix]Server ol_svr_custom is not

listed as a dbserver name in sqlhosts.

322

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch10.fm

10

Chapter 10.

User defined routines

In this chapter we discuss the creation and use of User Defined Routines

(UDRs), a routine that you create, that can be invoked in an SQL statement, by the database server, or from another UDR. A routine is a collection of program statements that perform a particular task. By understanding UDRs, you can take the next step and extend the database server, either a little bit or in steps that lead to something bigger, such as a bladelet or DataBlade module.

We undertake to do this by looking at three areas:

򐂰 An Overview of UDR and database extensions

򐂰 Developing User defined routines

򐂰 DataBlades and bladelets

Extending the database server requires an understanding of the parts required to implement the extending. An extension can be as simple as one user defined routine, or as complex as a new data type with many supporting routines. We first discuss UDRs and user defined types (UDTs), to provide the scope for what is needed. Then we provide examples.

323

© Copyright IBM Corp. 2010. All rights reserved.

7884ch10.fm

Draft Document for Review August 23, 2010 10:53 am

10.1 An Overview of UDRs and database extensions

IBM Informix database servers have the built-in ability to retrieve, store, manipulate, and sort a number of standard data types, some of which are unique to Informix servers. A developer can choose to modify or extend the built-in data types, and modify or extend how various operations work with the resulting new data type extensions. You can extend the data types in the following ways:

򐂰 Extend operations that are used to process built-in data types.

򐂰 Create complex data types based on built-in data types.

򐂰 Create user defined data types (UDTs), both distinct and opaque data types.

򐂰 Create new operations to process extended data types.

Database extensions and extended data types allow the developer to make customized routines and functions transparent, since you have the capability to actually build it into the database server. The transparency is visible as:

򐂰 Better performance: Through optimized routines, faster queries. and reduced network traffic.

򐂰 Simpler applications: Modules you write result in streamlined code, and easy to upgrade applications.

򐂰 Transaction control: Modules have automatic recovery, backup, and rollback capability provided by the server.

򐂰 Scalability: Database extensions automatically scale with the database size and user count.

In the context of discussing user defined routines and database extensions, we may also mention DataBlade modules. A DataBlade module is a software package that extends the functionality of the IBM Informix database server. Each package includes SQL statements and supporting code written in an external language or in Stored Procedure Language. A DataBlade module enables the same level of support for new data types as the database server provides for built-in data types. DataBlade modules can also use SQL queries or the

DataBlade API to access data types and routines in other DataBlade modules.

Note: Extended Parallel Server and Standard Engine support stored

procedures but not UDRs.

10.1.1 Considerations for user defined routines

A user define routine can be written using the IBM Informix Stored Procedure

Language (SPL) or with an external language. A routine written with SPL is simple to use and easy to implement. An SPL based UDR has flow-control

324

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch10.fm

extensions (conditional clauses and while loops), and works with SQL statements. Once the routine has been created and is ready to use, the database server parses and optimizes it, and stores it in system catalog tables, ready to execute.

The system catalog tables are used to keep track of the information the database server uses to manage the database server. UDR related information is stored in a small group of catalog tables that can tell us a lot about the UDR layouts. The catalog tables that are common to all UDRs are:

򐂰

sysprocedures table: This table is used to track the name, owner, and to indicate whether the UDR is a user-defined function or a user-defined procedure (functions return values. procedures do not).

򐂰 sysprocauth table: This table tracks who can execute the procedure.

򐂰

sysprocbody table: This table contains the actual code for the SPL routines.

UDRs can also be written with an external language. The body of an external-language routine allows language-based operations such as flow control and looping, while also using special Informix library calls to access the database server. The database server also stores information for external-language routines in three system catalog tables:

򐂰 sysprocedures table: The information kept in this table is same as the SPL user define routines.

򐂰

sysroutinelangs table: This table tracks the language information.

򐂰 syslangauth table: This table tracks the users of the server who can use the particular external language.

You need to use an appropriate compiler to parse and compile an external-language routine into an executable format. We discuss this with specific examples of the language and API methods that are available for writing these extensions. The external languages that can be used are:

򐂰

C: To execute SQL statements in C UDRs, you must use the DataBlade API, and you cannot use ESQL/C. To write routines in C, you need a C compiler.

Additional information on writing UDRs in C, is found in the IBM Informix

DataBlade API Programmer’s Guide, Version 11.50, SC23-9429-03, and IBM

Informix DataBlade API Function Reference, Version 11.50, SC23-9428-01.

򐂰 Java: To write Java routines, you must use IBM Informix database server with

J/Foundation and with the Java Development Kit (JDK) to compile your Java routines. Additional information about how to write Java UDRs, is found in

J/Foundation Developer's Guide, Version 10.0, G251-2291-00.

Chapter 10. User defined routines

325

7884ch10.fm

Draft Document for Review August 23, 2010 10:53 am

10.1.2 About user-defined routines

Table 10-1 lists the UDR types that are supported by SPL, C, and Java in IBM

Informix database server.

Table 10-1 Supported UDR tasks by languages

UDR task SPL routines C routines

Cast function

Cost function

Yes

No

Yes

Yes

End-user routine

Iterator function

Negator function

Opaque data type support

Yes

No

Yes

No

Yes

Yes

Yes

Yes

Parallelizable UDR

Statistics function

Selectivity function

User-defined aggregate

Operator function

Operator-Class function

No

No

No

Yes

Yes

Yes

Yes

Yes

Yes

Yes

Yes

Yes

Yes

Yes

No

Some

Yes

Yes

Java routines

Yes

No

Yes

Yes

Yes

Yes

The following are the definitions of the terminologies in this table:

򐂰

Cast: An routine to convert from one data type to another. Built-in data types have automatic casts between most data types. For User Defined Data Types

(UDTs), casting have to be defined from scratch.

򐂰 Cost function: A routine that informs the optimizer of cost factors for execution of a particular UDR.

򐂰

End-user function: A routine used to encapsulate multiple SQL statements into one function.

򐂰 Iterator function: A routine that is designed to return to its calling SQL statement several times, each time returning a value.

򐂰

Negator function: A routine used for a NOT condition that involves a Boolean

UDR.

򐂰 Opaque data type support: When you create a new data type, you must provide several basic support functions for your UDT. The following functions are required:

326

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch10.fm

– Text input and output routines

– Binary send and receive routines

– Text import and export routines

– Binary import and export routines

򐂰

Parallel UDR: A routine that can run in parallel within parallel queries.

򐂰 Statistics function: A routine to create distribution statistics for a UDT.

򐂰

Selectivity function: A routine to determine the percentage of rows for which a

Boolean UDR is expected to return true.

򐂰 User-defined aggregate: An SQL invoked routine that takes values selected and returns information about those rows (a summarizing method).

򐂰

Operator function: A routine used within expressions with a symbol, such as

“+,-,<,>,=”. Built-in data type operators cannot be extended. All UDTs require some operators in order to function within an SQL context.

򐂰 Operator-Class function: A set of operators that the server will associate with how to build an access method (that is, an index), how to arrange values in the access method, how to select values based on operator function, and ways to allow the query optimizer to consider using the access method to return results for a query.

For more details on any of these functions, and for details on functionality not discussed here, see the IBM Informix User-Defined Routines and Data Types

Developer's Guide, Version 11.50, SC23-9438-00.

Invoking a UDR

You can invoke a UDR implicitly or explicitly. Implicit invocation would be the result of an operator function, an implicit cast, or some type of query processing.

For this handbook, we mainly discuss explicit invocation. You can use either

EXECUTE PROCEDURE or EXECUTE FUNCTION statements to run a UDR.

When the database server executes an SQL statement that contains a UDR, it loads the UDR executable code as a shared-object into memory. It determines which shared-object file to load from the externalname column of the row in the sysprocedures system catalog table that describes the UDR. The sysprocedures entry is created when you register the UDR, as a result of the CREATE

FUNCTION or CREATE PROCEDURE statement.

In more general terms, when you invoke a UDR, the database server parses the statement into syntactic parts, call the system catalog to resolve the routine parts, generate a query plan, and then execute the query. If the query involves more than one database, each database requires that all the UDRs and UDTs must be registered in the participating databases.

Chapter 10. User defined routines

327

7884ch10.fm

Draft Document for Review August 23, 2010 10:53 am

10.1.3 Considerations for extending data types

A significant aspect of UDR is the support for an extended data type. IBM

Informix database servers have several built-in data types. Why do we need more? An extended data type is a new data type, which has different core properties, new functionality, and new operator methods that go beyond a basic data type. As an example, consider a datetime data type. Imagine, as a programmer if you had to add “a day and a half” to a specific datetime event.

Intuitively, we recognize that the value “‘day and a half” is an interval of time, but the database serve would not recognize this construct as an interval. We would need to manually convert it to a usable interval, then add it to a datetime value.

Using a user defined routine, an unconventional interval name such as this could be passed through a function, which automatically translates it to an “normal” interval, applies the addition operation, and returns a datetime value with the result. To do this, we would be applying a functional behavior change, which would extend the data type. The result of processes like these can simplify a repeating data task and make the development task easier.

A quick review of the data type hierarchy is useful. Figure 10-1 shows a summary

of these data types.

Figure 10-1 Hierarchy of data types in Informix Servers

The Extended data types break out into user defined data types and complex data types. We are especially interested in user defined types. These can be described as follows:

򐂰 Distinct: Internally stored the same as a source data type, but it is overlaid with different casts and functions defined beyond the basic source type. The server sees distinct types as different from the source type. It is necessary to tell the server:

– Source data type information and how the internal structure is defined.

– The functions of how this data type interacts with its internal structure.

328

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch10.fm

– The operations that are valid with this distinct data type.

– Any secondary access methods on how to handle this type.

– Cast functions to move data in and out of the distinct type are automatic.

򐂰

Opaque: A fundamental, user defined data type. It cannot be broken into smaller pieces, though it can serve as the building block for other data types.

The internal structure of the opaque data type is invisible to the server. When you define and use an opaque type, the developer must provide all of the following:

– How the internal structure is defined.

– The functions that enable routines to interact with its internal structure.

– The operations that are valid with this distinct data type.

– Any secondary access methods on how to handle this type.

– Cast functions to move data in and out of the distinct type need to be provided.

10.2 Developing user defined routines

To develop a user define routines, you should plan it then write the routine. We follow the directions given in the UDR and Data Types Developers Guide for planning our routines:

򐂰

Use a sensible name.

򐂰 Avoid modal arguments (an argument in the function determines how the function will work).

򐂰

Always declare routine parameter data types.

򐂰 Declare the type that is returned when the routine is returning a value

The source for an external routine resides in a separate text file. To prepare UDR source code:

򐂰

You will compile the C-language UDR and store the executable version in a shared-object (.so or .o on UNIX) file.

򐂰 Compile the Java-language UDR and store the executable version in a .jar file.

You must install shared object files and .jar files on all database servers that need to run the UDRs, including database servers involved in Enterprise

Replication (ER) and High-Availability Data Replication (HDR). The shared object files and .jar files need to be installed under the same absolute path name.

Chapter 10. User defined routines

329

7884ch10.fm

Draft Document for Review August 23, 2010 10:53 am

Tip: Although not required, use the DataBlade Developer’s Kit (DBDK) to help

write UDRs is advantageous. DBDK books and software can help enforce standards that facilitate migration between different versions of the database server. Because external-language routines are external to the database, be aware that you must compile the UDR source code and store it where the database server can access it when the routine is invoked.

For information about C UDRs, refer to the IBM Informix DataBlade API

Programmer’s Guide, Version 11.50, SC23-9429-03 and the IBM Informix

DataBlade API Function Reference, Version 11.50, SC23-9428-01. For information about Java UDRs, refer to the J/Foundation Developer's Guide,

Version 10.0, G251-2291-00.

10.2.1 User defined routines in SQL

You can use Informix Stored Procedure Language (SPL) statements to write routines and store these SPL routines in the database. SPL extends SQL and helps to reduce SQL coding, by minimizing the visible code in large SQL operations. It has the advantage that it is run as a server side routine, the executable code stays inside the engine, and it is optimized only as needed. The end result is lower application startup costs and better performance. As an SQL extension, it can do flow control, such as looping and branching. SPL routines can also execute routines written in C or other external languages, and other

UDR routines can execute SPL routines.

We provide examples of different UDRs written in SQL in the following sections.

As we do so, a couple of rules for SQL UDRs to keep in mind are:

򐂰

If you use any parameters, they have to be declared as built-in or user-defined data types.

򐂰 An SPL routine does not have access to the user state of its execution sequence. If the routine is going to be called more than once and you want to retain information about previous executions in the transaction, you will want to use an SPL routine that states WITH RESUME as a part of the RETURN statement for multiple executions of the same SPL routine within the same routine sequence.

򐂰

When an SPL routine is executed, the parameters (also known as the dependency list) will be checked. If it is determined that an item in the dependency list needs reoptimization, optimization occurs at this point. If an item needed in the execution of the SQL statement is missing (for example, a column or table has been dropped), an error is returned.

330

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch10.fm

򐂰 UDRs can be overloaded. This means that a function can have more than one way to operate, depending on the list of data types that are provided as parameters. There is a precedence hierarchy to decide how the parameter list is to be executed. This may be important if you have more than one UDR with the same name, but a different parameter list. See the IBM Informix

User-Defined Routines and Data Types Developer's Guide, Version 11.50,

SC23-9438-00 for more details.

Routine examples in SQL

Using a stored procedure method for a UDR is simple, as long as you can recognize the incoming and outgoing parameters properly.

Using a stored procedure method for a UDR is simple, as long as you can recognize the incoming and outgoing parameters properly. The incoming parameters, which are provided in the function definition, must have their data types defined when the parameter is first created and declared. The parameter values, which are to be returned from the function, also should have declared data types. By following this general rule, you can avoid many of the initial problems you can get with SPL

UDRs.

For the routines with SPL, we use the Informix stores

sample database, defined as stores@demo_on

.

One variable in, one result out

For this example, we want a function that provides a count of all the orders received in a numerical month (N) from the orders table of the stores database.

This example demonstrates what happens when selecting an aggregating value, once.

Example 10-1 shows the function code and ways to invoke the function to get

output.

Example 10-1 CREATE FUNCTION new_orders (month_num INT)

CREATE FUNCTION new_orders ( month_num INT )

RETURNING INT ;

DEFINE nrows INT;

SELECT COUNT(order_date) INTO nrows FROM orders

WHERE month(order_date)=month_num;

RETURN nrows;

END FUNCTION;

# -- Execute it as a function:

EXECUTE FUNCTION new_orders(5);

(expression)

7

Chapter 10. User defined routines

331

7884ch10.fm

Draft Document for Review August 23, 2010 10:53 am

# -- Execute it as a select statement.

# -- Note that we have to force “first 1” as a criteria so we can assure we are

# -- only getting one value. Otherwise we would get an error.

SELECT FIRST 1 new_orders(5) FROM orders;

(expression)

7

One variable in, several results out

In Example 10-2, we perform three SELECT statements, and each does an

aggregation, returning one value from each select. In this case we return three values and label each one in the returned result. This shows how to aggregate three separately selected value returns in one call, and still not use a cursor.

Example 10-2 Selecting three and returning three

CREATE FUNCTION new_orders ( month_num INT )

RETURNING INT as TotalOrders,INT as ShippedOrders,INT as Backorders;

DEFINE nrows INT;

DEFINE mrows INT;

DEFINE b_rows INT;

SELECT COUNT(ship_date) INTO mrows FROM orders

WHERE month(ship_date)=month_num;

SELECT COUNT(order_date) INTO nrows FROM orders

WHERE MONTH(order_date)=month_num;

SELECT COUNT(order_date) INTO b_rows FROM orders

WHERE MONTH(order_date)=month_num AND ship_date IS NULL;

RETURN nrows,mrows,b_rows;

END FUNCTION;

# -- Since we are returning three values with labels, calling the execute

# -- function is the most appropriate way to make our SQL call.

EXECUTE FUNCTION new_orders(5); totalorders shippedorders backorders

7 3 1

Using the WITH RESUME clause to return a cursor result

In Example 10-3 on page 333, we collect better details for the new orders. To

return a detailed listing of orders made, we use WITH RESUME in the function.

In this case, we assume (and expect) more than one row is returned, so the

WITH RESUME clause is needed.

332

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

Example 10-3 A WITH RESUME ROUTINE that uses a cursor

CREATE FUNCTION new_orders ( month_num INT )

RETURNING INT as Num, INT as ord_num;

DEFINE ord_num INT;

DEFINE Num INT;

LET Num=1;

FOREACH cursor1 FOR

SELECT order_num INTO ord_num FROM orders

WHERE month(order_date)=month_num

RETURN Num, ord_num WITH RESUME;

LET Num=Num+1;

END FOREACH;

END FUNCTION;

EXECUTE FUNCTION new_orders(5);

------num ord_num-----

1 1001

2 1002

3 1003

4 1004

5 1005

6 1006

7 1007

7884ch10.fm

Multi-table select using a cursor

In Example 10-4, we perform a multi-table join with a summary expression return

and a group by. We ask for all the orders placed in a specific month, the name of the person placing the order, and the total amount for each order.

Example 10-4 A multi-table select using a cursor

CREATE FUNCTION new_orders ( month_num INT )

RETURNING INT as Ord_Num, char(15) as ord_fname, char(15) as ord_lname, money(8,2) as Amt;

DEFINE ord_num INT;

DEFINE ord_fname char(15);

DEFINE ord_lname char(15);

DEFINE Amt money(8,2);

FOREACH cursor1 FOR

SELECT o.order_num, c.fname,c.lname,sum(i.quantity*i.total_price)

INTO ord_num, ord_fname, ord_lname, Amt

FROM orders o, customer c, items i

WHERE month(order_date)=month_num

AND o.customer_num=c.customer_num

AND i.order_num=o.order_num

group by o.order_num,c.fname,c.lname

Chapter 10. User defined routines

333

7884ch10.fm

Draft Document for Review August 23, 2010 10:53 am

RETURN ord_num, ord_fname, ord_lname, Amt WITH RESUME;

END FOREACH;

END FUNCTION;

EXECUTE FUNCTION new_orders(5)

----ord_num ord_fname ord_lname amt

1001 Anthony Higgins $250.00

1003 Anthony Higgins $1355.00

1006 Margaret Lawson $1904.00

1004 George Watson $1416.00

1005 Jean Parmelee $4864.00

1002 Ludwig Pauli $1200.00

1007 Arnold Sipes $1696.00

10.2.2 User defined routines in Java

It may be helpful to point out that we must distinguish between JDBC and Java

Virtual Machine (JVM) applications. JDBC can be used to write standalone applications. If you want to connect with other databases that support Java, you will typically write standalone Java (JDBC) applications since these applications require specific driver methods to communicate with other database servers.

When you write a Java UDR, you must use the IBM Informix JDBC Driver, which is based on the JDBC 2.0 API. The generated code is processed by a Java

Virtual Machine that runs as a process inside the IBM Informix Server. The generated code (jar file) is stored in an sbspace, and may also refer to a jar file in a storage location outside of the server

Java allows you to create user-defined routines, cast support functions, aggregates, and opaque data type support routines. However, Java routines cannot handle row or collection data types.

For ordinary UDR with IBM Informix database servers, you can use the Java

Developers Kit (version 1.5 at this writing). A Java Virtual Machine comes pre-installed with the IBM Informix database server (with J/Foundation). To confirm it is present, simply make sure you have an existing directory path to

INFORMIXDIR/extend/kraratoa

.

Java based UDR, once developed, is placed into a Java archive (jar) file. The jar file is stored inside an sbspace, or it may have additional supporting files on the file system. If the jar file is very large, or perhaps proprietary, you can leave it on the file system. Smaller jar files, or something you may want to update frequently, should be stored in the sbspace.

334

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch10.fm

Configuration

Make sure you use the JVM system that came with your server engine, and make sure the onconfig and environment variables are set to accurate working paths. The environment settings for our testing setup had the following variables in the environment:

JRE_HOME=/usr/lib/jvm/java/jre

JAVA_BINDIR=/usr/lib/jvm/java/bin

JAVA_HOME=/usr/lib/jvm/java

SDK_HOME=/usr/lib/jvm/java

JJDK_HOME=/usr/lib/jvm/java

JAVA_ROOT=/usr/lib/jvm/java

The

JAVA_ROOT

environment variable is mostly determined by the developer. It is the path to the file system directory where you are developing your jar files:

CLASSPATH=location_for_your_java_classes:.:.:.

The INFORMIXDIR/etc/ONCONFIG file also has a small group of parameters that must have verified settings. The following are standard:

JVPJAVAHOME $INFORMIXDIR/extend/krakatoa/jre

JVPHOME $INFORMIXDIR/extend/krakatoa

JVPPROPFILE $INFORMIXDIR/extend/krakatoa/.jvpprops

JVPJAVALIB /bin

JVPJAVAVM jvm

The

JVPJAVALIB

and

JVPJAVAVM onconfig parameters are important for development. This one specifies where Java problems are written to (make sure the path exists):

JVPLOGFILE $INFORMIXDIR/jvp.log

If you are going to use external jar files, you must add them to JVPCLASSPATH :

JVPCLASSPATH $INFORMIXDIR/extend/krakatoa/krakatoa.jar:$INFORMIXDIR/extend/krakatoa/jdbc.jar

Note: Jar paths added to JVPCLASSPATH are only visible after being added

to the ONCONFIG file, and the database engine must be restarted.

Routine examples in Java

In the examples which follow, we create our Java routines in

/work/

, which defines the UNIX directory we use for our working CLASSPATH. You must change the directory path in some of the code expressions if you use a different directory. Once your code is compiled, the source code is not used for execution, but you should keep it in a safe place in case you want to improve it later.

Chapter 10. User defined routines

335

7884ch10.fm

Draft Document for Review August 23, 2010 10:53 am

A function extension

This example illustrates a simple way to extend functionality. This routine provides an SQL function to “multiply a value times ten”. The developing procedure is as follows:

1. Create a simple class file, named Times.java

in the working JVPCLASSPATH

directory. Example 10-5 shows the source code.

Example 10-5 A java function to multiply a value times ten

/*Times.java */ public class Times {

public static int TimesTen(int x) {

return x * 10;

}

}

2. At a command prompt, compile the file using the following command: javac Times.java

3. Compress it into a jar file: jar cvf Times.jar Times.class

As this runs, it shows output similar to the following: added manifest adding: Times.class(in = 245) (out= 187)(deflated 23%)

4. Register the routine:

Start dbaccess to connect to the database and run the following SQL to register and add the jar file into our sbspace: execute procedure sqlj.install_jar ("file://work/Times.jar" , "Times_jar");

Routine executed.

5. With the jar file in storage and accessible, from dbaccess , we create a function

that calls our routine in the jar file. See Example 10-6.

Example 10-6 Calling routine

create function times_ten(value int) returning int

with (class = "jvp")

external name "Times_jar:Times.TimesTen"

language JAVA;

6. The procedure is ready to run. We test it in dbaccess

:

EXECUTE function times_ten(13)

(expression)

130

336

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch10.fm

For an alternate method, try:

SELECT ship_charge, times_ten(ship_charge) X10 FROM orders;

A Java user-defined routine with two input parameters

Here we demonstrate how to create a Java routine with multiple input parameters. Java language and IBM Informix servers express decimals in different ways. In this example, we create a new sales tax function Salestax that includes a new Java function and the existing Times_ten

function created in “A function extension” on page 336. We need to include an external standard Java

library that has a math class. You might find that multiplying decimal values in

Java is different than what you may be used to. In addition, Java uses a different naming convention than Informix data types. If you get the class wrong or the library is incorrect, things simply do not work and you will get errors.

We use the following procedure to create the salestax function:

1. Create a Java class called

Tax.java

, using an editor such as vi

.

Example 10-7 shows the source code.

Example 10-7 Tax.java

/*Tax.java*/ import java.math.BigDecimal; public class Tax { public static BigDecimal salestax(BigDecimal x,BigDecimal xtax )

{

BigDecimal ratePlusOne = xtax.add(BigDecimal.valueOf(1));

BigDecimal afterTax = x.multiply(ratePlusOne);

afterTax = afterTax.setScale(2, BigDecimal.ROUND_HALF_UP);

return (afterTax);

}

}

2. Compile the file. At a command prompt, run the following command: javac Tax.java

3. Compress it and add it to our existing jar file Times.jar

.

jar cvf Times.jar Tax.class

As this runs it shows a line similar to the following: added manifest adding: Tax.class(in = 546) (out= 318)(deflated 41%)

4. Add the updated jar file to sbspace.

For this example we want to update an existing function that already exists in our sbspace jar. Since we can not replace an existing function in a sbspace jar directly, in order to update an sbspace jar function, we must replace the

Chapter 10. User defined routines

337

7884ch10.fm

Draft Document for Review August 23, 2010 10:53 am entire jar. To do this, we must remove (drop) the sbspace jar file, then replace it with an updated version from our working path.

A jar file in an sbspace must be empty, in order to drop the jar. Drop all the

UDRs in the jar to empty the jar. Otherwise, you will receive the error message “

Invalid jar removal. All dependent UDRs not dropped

”.

Our Times_jar file exists in the database. To drop the function, we start dbaccess, connect to the database, then run the following command:

DROP FUNCTION times_ten;

Now, we can remove the jar:

EXECUTE PROCEDURE sqlj.remove_jar ("Times_jar");

5. Add the updated jar file into sbspace. Run the following SQL,:

EXECUTE PROCEDURE sqlj.install_jar ("file://work/Times.jar" , "Times_jar");

6. The updated jar is now in sbspace storage. Recreate the dropped

Times_ten function: create function times_ten(value int) returning int

with (class = "jvp")

external name "Times_jar:Times.TimesTen"

language JAVA;

7. Add the new function to call on the same jar file: create function salestax(value decimal,xtax decimal)

returning decimal(8,2)

with (class = "jvp")

external name "Times_jar:Tax.salestax"

language JAVA;

8. Now we can test the expanded function from dbaccess:

EXECUTE FUNCTION salestax(250.00,.065);

(expression)

266.25

As an alternative test using SQL, try:

SELECT o.order_num, salestax (sum(i.quantity*i.total_price), .065) Amt_w_Tax

FROM orders o, items i WHERE month(order_date)=5

AND i.order_num=o.order_num group by o.order_num

Creating a routine that uses external Java APIs

In this example, we demonstrate how to create a Java UDR that requires support from one or more Java APIs which lie outside the database server. The import references in the code indicate that an external Java API exists to help support the UDR. The references on the import list remain outside the database server.

338

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch10.fm

The Java Virtual Machine runs using the jar calls in the sbspace storage location and sends calls to the external Java functions based on the import reference in the jar file.

Note that the import reference does not have a full directory path. Any Java API or jar file that is not residing in an sbspace is external to the instance. In order to help the server instance find the external jar files, you must supply all Jar API path locations in the onconfig file.

Note: The onconfig file must be updated so the JVM knows the directory path

for any supporting APIs. The full path location for the supporting Java file specified on an import list must be included in JVPCLASSPATH.

For our example, JVPCLASSPATH is set to:

/usr3/11.50/extend/krakatoa/krakatoa_g.jar:/usr3/11.50/extend/krakatoa/jdbc_g.j

ar:/usr3/11.50/extend/krakatoa/jre/lib/rt.jar:/work/mailapi.jar:/work/activatio n.jar:/work/smtp.jar

For our example to work, the engine needs the Java mail API classes. The files required are mailapi.jar

, activation.jar

, and smtp.jar

from the Java website at http://java.sun.com/products/javamail/downloads/index.html

We use these steps to create the sendmail

routine:

1. Install the downloaded jar files and add jar files with full path to

JVPCLASSPATH.

In this example, the paths are

/work/mailapi.jar

,

/work/activation.jar

, and

/work/smtp.jar.

2. Create the file MailClient.java

as shown in Example 10-8. You have to

update the italicized references in the example with your own information.

Example 10-8 A SQL based sendmail() UDR

---- MailClient.java --import javax.mail.*; import javax.mail.internet.*; import java.io.*; import java.util.Properties; public class MailClient

{

public static void send(String to, String text)

{

try

{

MailClient client = new MailClient();

Chapter 10. User defined routines

339

7884ch10.fm

Draft Document for Review August 23, 2010 10:53 am

Properties props = System.getProperties();

props.put("mail.smtp.host", "smtp.server.com");

Session session = Session.getDefaultInstance(props, null);

Message message = new MimeMessage(session);

message.setFrom(new InternetAddress("Name_showing@fromfield")); message.addRecipient(Message.RecipientType.TO, new InternetAddress(to));

message.setSubject("Message from the database");

message.setText(text);

Transport.send(message);

}

catch(Exception e)

{

e.printStackTrace(System.out);

}

}

}

---- MailClient.java ---

3. Compile and compress your file: javac MailClient.java

jar cvf MailClient.jar MailClient.class

4. Install the jar into the sbspace:

EXECUTE PROCEDURE sqlj.install_jar ("file://work/MailClient.jar" ,

"MailClient_jar");

Make sure JVPCLASSPATH is set as indicated in step 1.

5. Create the sendmail

procedure from dbaccess:

CREATE PROCEDURE sendemail(to LVARCHAR, message LVARCHAR)

WITH (class = "jvp")

EXTERNAL NAME "MailClient_jar:MailClient.send"

LANGUAGE JAVA;

6. Test the procedure:

EXECUTE PROCEDURE sendemail('[email protected]','Error deleting from table');

Troubleshooting tips

Sometimes you may have trouble getting a Java UDR up and running. There are three points of exposure for errors:

򐂰

At the time of a Java compile.

If you get an error here, the issue relates to a Java language problem, most likely resulting from syntax or a Java method. Consult a Java Programming

Language Guide for assistance.

340

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch10.fm

򐂰 At the jar install point or later.

Check the jvp.log

at the path in the onconfig file specified by the JVPLOG parameter. You should see no errors at the time of install, and no errors at runtime. When you start the server instance the JVM starts, and jar files should be loaded into the process memory as needed. The MSGPATH file

(online.log) will often reveal the success or failure of JVM and jar loading. If the files cannot load, they cannot run.

򐂰 UDR runtiime errors

If there are errors, study the Java error messages returned, and determine the cause for whatever did not resolve.

Troubleshooting can be a trial and error approach. Once you have an understanding of how the provided UDR examples work, do them over again, and break something in the Java code. Go through the example with slightly broken syntax and review the results. For example, In the BigDecimal code example, change BigDecimal to Float or Double, and work through the example again.

10.2.3 User defined routines in C

C allows you to create user-defined routines, cast support functions, aggregates, and opaque data type support routines. C can also handle row and collection data types. Working with C UDR adds an extra layer of difficulty since these routines have to be compiled using a compiler, specific to the machine and operating system where you have products installed. Compiled C is not stored in sbspace, but rather, it is stored outside the server.

In addition to compiler difficulties, it is a good idea to develop and test UDRs on a development server and not in a production environment. C UDR code runs as a database server process that works closely with internal structures. The routine should not do anything that would negatively affect the database server. A poorly designed C UDR is likely to crash the server. If you plan to work with C UDRs, there are three good reference books:

򐂰

IBM Informix User-Defined Routines and Data Types Developer's Guide,

Version 11.50, SC23-9438-00

򐂰

IBM Informix DataBlade API Programmer’s Guide, Version 11.50,

SC23-9429-03

򐂰

IBM Informix DataBlade API Function Reference, Version 11.50,

SC23-9428-01

Chapter 10. User defined routines

341

7884ch10.fm

Draft Document for Review August 23, 2010 10:53 am

If you are interested in using C++ Datablade modules, the IBM Informix

Developer Zone that provides the latest recommendations on C++ programming options is at this website: http://www.ibm.com/software/data/developer/informix

Routine examples in C

In this section, we undertake a few examples written in C. With Java we have portability that extend across platforms, but some of our functionality is limited. C is flexible since it can extend the database by way of data types, new functions, and new operators. For each database across an enterprise, the extensibility that you provide through C must be specifically compiled with each operating system.

For the examples in this section, we use a Solaris machine.

A simple function using C

For our first example, we start with a function similar to what we did in our Java example, a multiplying function. For each of our C examples, we must include the

DataBlade API files (referenced in the example as mi.h and milib.h). The

DataBlade APIs provide the interface to allow C language calls to interface with

IBM Informix database SQL calls. To prevent a conflict with our times_ten

Java

UDR function, we name this example times_five

. We use the following steps to create this routine:

1. Create the text file that holds the C code. Example 10-9 shows the source file

times.c

.

Example 10-9 A C UDR which multiplies times 5

#include <stdlib.h>

#include "mi.h"

#include "milib.h" mi_integer* TimesFive(mi_integer value); mi_integer* TimesFive(mi_integer value)

{

return (mi_integer *) (value * 5);

}

2. Compile and link the C code.

The compile command (

cc

or

gcc

) depends on the operating system. The first way to identify your compiler is to examine the text of man cc (on UNIX), or check the command for your operating system compiler in the

INFORMIXDIR/release/en_us/0333/ids_machine_notes_vers.txt

file.

At a minimum, your compile line for UDR preparation usually includes:

-DMI_SERVBUILD -KPIC -I$INFORMIXDIR/incl/public -I/$INFORMIXDIR/incl

342

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch10.fm

Where

-DMI_SERVBUILD

is the flag to indicate that this is a server-oriented C UDR application which uses the DataBlade API (required).

– -KPIC is the flag to indicate that the symbol table is dynamic (for UNIX and

Linux only).

-I$INFORMIXDIR/incl/public -I/$INFORMIXDIR/incl are the location of the mi_ libs

.

The compile command for our code sample (on Solaris) is: cc -DMI_SERVBUILD -KPIC -I$INFORMIXDIR/incl/public -I/$INFORMIXDIR/incl -o times.o -c times.c

Run the link command to put the compiled object file into our Blade library file: ld -dy -G -Bsymbolic -o times.bld times.o

3. Set the bld file permissions as user informix: chmod 555 ./times.bld

4. In dbaccess, after connecting to the database, create the times_five function:

CREATE FUNCTION times_five(value int) RETURNING int

WITH (handlesnulls)

EXTERNAL NAME "/work/times.bld(TimesFive)"

LANGUAGE C;

Adjust the external work path as needed.

5. Test the routine: execute function times_five(20);

(expression)

100

In Java UDR, the jar file serves as a library (collection-repository) for all of the compiled routines. In C, a collection of compiled routines is stored in a shared library (.so or .o) file. On Windows, a shared object file has a .dll extension

(dynamic link library).

Creating a C routine using large object column

In our next example we explore the use of working with a large object column reference. Without a text search DataBlade, searching a character large object

(CLOB) file for a particular value can be a laborious SQL task. This example shows how to access a CLOB file, copy the CLOB contents into an LVARCHAR, and search for a specific text item, while using a simple function. We create a C file that handles two parameters. The first parameter is a CLOB column

Chapter 10. User defined routines

343

7884ch10.fm

Draft Document for Review August 23, 2010 10:53 am reference, the second parameter is the LVARCHAR text value for our search. It returns a count for the number of successful finds.

We use the following procedure to implement our search routine:

1. Create the CLOB column search routine source file un.c as shown in

Example 10-10.

Example 10-10 A UDR for searching a CLOB

#include <ifxgls.h>

#include <mi.h>

#include <milib.h>

#include <fcntl.h>

#include <stdio.h>

#include <stdlib.h> typedef unsigned char byte; mi_integer contains(MI_LO_HANDLE* loptr, mi_lvarchar* pattern, MI_FPARAM* fp); mi_integer contains(MI_LO_HANDLE* loptr, mi_lvarchar* value, MI_FPARAM* fp)

{ mi_unsigned_integer crc = (mi_fp_argisnull(fp, 1) == MI_TRUE) ? 0 :

(mi_unsigned_integer)1;

MI_CONNECTION *conn;

MI_LO_SPEC *lo_spec = NULL;

MI_LO_FD lo_fd;

MI_LO_STAT *lo_stat = NULL;

char *buff = NULL;

char *pattern = NULL;

mi_integer buffsize = 4096;

mi_integer found=0;

mi_integer result=0;

pattern = mi_lvarchar_to_string(value);

if ((conn = mi_open(NULL, NULL, NULL)) == NULL) return (mi_integer) -1;

if ((buff = (char*)mi_alloc(buffsize)) == NULL) return (mi_integer) -2;

if ((lo_fd = mi_lo_open(conn, loptr, MI_LO_RDONLY)) == MI_ERROR)

return (mi_integer) -3;

do {

if ((result = mi_lo_read(conn, lo_fd, buff, buffsize)) == MI_ERROR)

break;

if (result == 0)

break;

if (strstr(buff,pattern)!=NULL)

{

found=1;

break;

}

if (result < buffsize)

break;

} while(1);

mi_lo_close(conn,lo_fd);

344

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch10.fm

if (buff)

mi_free(buff);

return (mi_integer)found;

}

2. Compile and link the C routine. We use the following Solaris compile line: cc -DMI_SERVBUILD -KPIC -I$INFORMIXDIR/incl/public

-I$INFORMIXDIR/incl/public -I$INFORMIXDIR/incl/esql -I/$INFORMIXDIR/incl -o un.o -c un.c

Here is the link line: ld -dy -G -Bsymbolic -o un.bld un.o

3. Set the bld file permissions as user informix : chmod 555 ./un.bld

4. Create the function in dbaccess.

create function contains(clob,lvarchar) returns integer external name '/work/un.bld(contains)' language C;

5. Set up for testing. Create a table and populate it with our c file.

CREATE TABLE tclob (c1 INT, c2 CLOB);

INSERT INTO tclob VALUES (1,filetoclob('un.c','server'));

6. Test the routine:

SELECT c2 FROM tclob;

SELECT CONTAINS(c2,'pattern') FROM tclob;

SELECT CONTAINS(c2,'nopattern') FROM tclob;

SELECT c1 FROM tclob WHERE CONTAINS(c2,'buff')=1;

Troubleshooting tips

In order to track down the cause of problems with C UDRs, The most affective approach is to use a debugger. To debug your UDR, use a debugger that can attach to the active server process and access the symbol tables of the dynamically loaded shared object files. On UNIX and Linux, the debugger and

dbx utilities meet these criteria. To start a debugger, enter the following command at the shell prompt, in which pid is the process identifier of the CPU or virtual processor: debugger - pid

This command starts the debugger on the server virtual-processor process without starting a new instance of the virtual processor. For more information about available debugger commands, see the debugger manual page, and learn

Chapter 10. User defined routines

345

7884ch10.fm

Draft Document for Review August 23, 2010 10:53 am more at the Information Center web page that describes Debugging a UDR located at: http://publib.boulder.ibm.com/infocenter/idshelp/v115/index.jsp?topic=/com.ibm.

dapip.doc/sii111026637.htm

10.3 DataBlades and bladelets

Your initial collection of UDRs will increase over time. It may not be long until you have UDRs, special functions, and stored procedure UDRs that reduce work complexity and provide great functionality. If you choose not to write your own

DataBlade, you can still choose from a nice selection of BataBlade modules. Any

DataBlade module you use will provide functions that can dramatically increase the usefulness of business data, or perhaps generate income for you -- as a software developer that develops and sells licensed DataBlades. IBM Informix has several books on the subject of planning, designing, and implementing

DataBlades. With a taste of the programming examples presented earlier in this chapter, you may be ready to take the next step and program a DataBlade in C or

Java. From a technical perspective, the IBM Informix DataBlade Developers Kit

User's Guide, Version 4.20, G229-6366-01 is specifically oriented to the development of DataBlade modules. It provides detailed help for programming

DataBlade modules in Java and C.

If you would like to work with a DataBlade before deciding on whether you have a need to write your own, in the sections that follow we will take a tour through the

DataBlades available with IBM Informix Server.

10.3.1 Configuration

Configuration for a Datablade module only requires three steps:

򐂰 Prepare the database serve.r

򐂰 Install the DataBlade.

򐂰 Register the DataBlade.

Conceptually, the process is the same, regardless of the operating system and hardware. Small differences exist in interface or command lines, which we will point out.

Database preparation

Database preparation involves setting up environment variables, and making sure the database you are going to use with a DataBlade is set to a logged database in advance.

346

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch10.fm

The environment settings required are

򐂰

On UNIX and Linux:

LD_LIBRARY_PATH

,

INFORMIXSERVER

, and

ONCONFIG

򐂰

On Windows:

INFORMIXSERVER

and

ONCONFIG

When you get to the step for BladeManager usage, you also require an environment setting for

LD_LIBRARY_PATH

.

Though a logged database is not required for every DataBlades, a logged database can help avoid concurrency problems and thus is recommended. Also, while it is the case that not all DataBlade modules require a logged database, some of them do require logged sbspace. Keep this in mind as you install and configure the DataBlade you select.

DataBlade installation

Any DataBlades installed with IBM Informix Servers are installed in separate subdirectories under INFORMIXDIR/extend directory. Several subdirectories for

DataBlades are established when the IBM Informix Server is installed. There may be some variation to the list, based on your exact version and operating

system. Example 10-11 shows the subdirectory listing for 11.50.UC6 on Linux

with J/Foundation.

Example 10-11 A sample INFORMIXDIR/extend subdirectory

opt/IBM/informix/extend:> ls binaryudt.1.0 ifxmngr LLD.1.20.UC2 spatial.8.21.UC3

bts.2.00 ifxrltree.2.00 mqblade.2.0 web.4.13.UC4

ifxbuiltins.1.1 krakatoa Node.2.0 wfs.1.00.UC1

If you do not see the DataBlade directory reference for the one you want, you must acquire it by way of a download or CD.

Installation on UNIX is simply a matter of uncompressing the new DataBlade module into a temporary directory. Once the files are expanded, run the install script,

./install

. The install script creates a new module directory under the

INFORMIXDIR/extend directory. Some file expansions may result in more than one new module. If there is more than one module, you must run the

./install for each one.

Installation on Windows requires that you go to the install location and run

setup.exe

. Select Typical installation option. The other dialog verification is the

INFORMIXDIR location. With those items confirmed, the software is installed.

When the installation is complete, the module directory is installed under

INFORMIXDIR\extend directory.

Chapter 10. User defined routines

347

7884ch10.fm

Draft Document for Review August 23, 2010 10:53 am

Datablade registration

With a DataBlade directory in place, the active database server is not aware of the DataBlade directories until the software is registered in the database.

Registration is the process of executing the SQL statements that create the

DataBlade module database objects and identify the DataBlade module shared object file or dynamic link library to the database server.

With the release of 11.50.XC4, IBM Informix began providing two distinct methods for DataBlade registration:

򐂰 BladeManager: This method has been around since the beginning of Informix datablades. The BladeManager is an interface that automates the registration process, by performing a series of SQL steps in the database engine.

򐂰 sysbldprepare(): The is an Informix function for DataBlade registration. At its simplest, you can run the command inside dbaccess, with your target database open, to install a DataBlade. It has a few usage restrictions which you can read about in the IBM Informix DataBlade Module Installation and

Registration Guide, Version 4.20, G229-6368-03. Here is an example of how the bts

DataBlade is registered with this interface:

EXECUTE FUNCTION sysbldprepare('bts.*','create');

The following are steps to register a DataBlade module using BladeManger:

1. Start BladeManager:

– On UNIX, or at the MS-DOS prompt, the BladeManager is started with the

blademgr

command.

– To start BladeManager on Windows, select Start

Programs

Informix program group name

BladeManager or double-click the

BladeManager icon in the Informix program group.

If the BladeManager fails to start, it is either not installed or you do not have the environment variables set, as noted in the previous section.

2. Set confirmations.

If you would like an auto confirmation after each step, turn the prompt on: set confirm on

Commands run when you press the carriage return.

3. Connect to an Informix instance: show servers set server demo_on < Use you own server name for demo_on>

If you want to connect as a different user, try: set user <username>

348

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch10.fm

At the password prompt, enter your password. Validation does not occur until connection, on the next step.

To connect to a database, run one of the following commands: list stores register module_name database_name unregister module_name database_name

The module_name represents the name of the DataBlade module directory.

These names typically follow the form of the DataBlade module name followed by the version number.

When BladeManager registers a DataBlade module, it executes a series of SQL

CREATE statements to register each database object in the module. You must have resource permissions on the database to register the DataBlade. In addition, if your server has implemented the ONCONFIG EXTEND role, you must be granted the EXTEND role by user informix .

If the registration of a module fails, BladeManager returns the database to its prior state. To see the SQL statements that failed, look at the corresponding log file and check the procedure in Appendix A. Troubleshooting Registration

Problems of the IBM Informix DataBlade Module Installation and Registration

Guide, Version 4.20, G229-6368-03, for possible solutions.

Occasionally, DataBlade modules have more than one interface. If there are additional modules, there are also dependencies. You have to make sure that each of the interfaces are registered correctly in order for the DataBlade to work.

BladeManager automatically checks for dependencies and registers any dependencies it might need. If the BladeManager cannot do the registration, it will prompt you to do so manually.

Important: BladeManager does not verify the integrity of DataBlade modules

that have additional interfaces, nor does it not check for the presence of required database objects.

Datablade modules written in the Java language can only be registered in IBM

Informix Servers with J/Foundation database servers.

10.3.2 IBM Informix provided DataBlades

Table 10-2 on page 350 the DataBlades that are available with IBM Informix

database servers.

Chapter 10. User defined routines

349

7884ch10.fm

Draft Document for Review August 23, 2010 10:53 am

Table 10-2 Informix provided DataBlades

IBM Informix

DataBlade module name Description

Large Object

Locator

MQ DataBlade

A foundation Datablade module for large objects management that can be used by other modules that create or store large-object data.

Allows IBM Informix database applications to communicate with other

MQSeries® applications with MQ messaging.

Binary DataBlade

Basic Text Search

Node DataBlade

Web Feature

Service

This module includes binary data types to store binary-encoded strings that can be indexed for quick retrieval.

Permits text search of words and phrases in an unstructured document repository stored in a column of a table.

This module is for the hierarchical data type, to represent hierarchical data within a relational database.

This module is an add-on to allow Open

Geospatial Consortium (OGC) web feature service as a presentation layer for the Spatial and Geodetic DataBlade modules

J/Foundation krakatoa ifxbuilt-ins ifxmngr.2.00

A library of classes and interfaces that allow programmers to create and execute

Java user-defined routines that access

Informix database servers

This is not really a DataBlade, but it sets up definitions and functions for the standard data types offered in the informix server.

This is the API that supports the

BladeManager.

Special notes

Available on standard install

(LLD.1.20.UC2)

Available on standard install

(mqblade.2.0)

Available on standard install.

(binaryudt.1.0)

Available on standard install.

(bts.2.00)

Available on standard install.

(Node.2.0)

Available on standard install.

(wfs.1.00.UC1)

Available as a part of Informix Server with J/Foundation

Available on standard install

(ifxbuiltins.1.1)

Available on standard UNIX install

350

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch10.fm

IBM Informix

DataBlade module name

ifxrltree.2.00

Image Foundation

Excalibur Text

Search

Geodetic

Spatial

Description

This is a foundational, multidimensional, index called “Region tree” (R-tree) (also known as Range Tree). This blade is needed for both spatial and time related data management.

This module is a foundation DataBlade which provides a base on which new or specialized image types and image processing technologies can be added or changed. Because the foundation is open, secure, and scalable, it provides a clear path toward reusing and repurposing valuable image assets.

This module enables provides extensive text-searching capabilities; It supports full-text indexing, including extensive fuzzy-search logic for indexing scanned text. Can search document types including: ASCII, Word, Excel, HTML,

PowerPoint, WordPerfect, and PDF.

Includes an adaptive pattern recognition process (APRP) and capabilities such as multiple stop-word lists, proximity searching and synonym lists.

This blade supports global space- and time based queries. It is designed to treat earth as a globe rather than a flat plane.

Supports client-side Geographic

Information Systems (GIS) software.

This blade transforms locations and traditional 2-d map data into useful information. Uses SQL-based spatial data types and functions that can be used directly through standard SQL queries or with client-side Geographic Information

Systems (GIS) software.

Special notes

Available on standard install

No charge download

License fee applies

License fee applies

No charge download

Chapter 10. User defined routines

351

7884ch10.fm

Draft Document for Review August 23, 2010 10:53 am

IBM Informix

DataBlade module name

TimeSeries

Video Foundation

Web

Description

This module supports data for managing time-series and temporal data. A “time series” is any set of data that is accessed in sequence by time and can be processed and analyzed in a chronological order.

This blade allows you to incorporate video servers, external control devices, compression codes, and cataloging tools to manage video content and metadata or information about the content. Allows metadata elements in the database, while allowing video content to be maintained on disk, video tape, video server, or other external storage devices.

This module supports most Web server

APIs and has a web client application to build and run SQL queries to work with your database. Enables customized Web applications. Allows you to track persistent session variables between

AppPages.

Special notes

License fee applies.

License fee applies.

License fee applies

10.3.3 Developing a bladelet routine

We can define a bladelet as a small, unofficial DataBlade module. It is meant to be useful (and complete with source code), from the time you set it up, but it becomes your own application (with no support or warranty). If you have tried out our UDR development examples, you have a bladelet.

As you may have observed from having to drop and recreate the jar API in the server in our earlier example, you can understand that if you have a large number of UDRs and have gone to the trouble of creating user defined data types, the whole package of tasks required to set up, change or update a DataBlade object inside the server may not be a convenient task.

On a large scale, if you have API dependencies, dozens of UDRs, and other

DataBlade related objects, you will want to move them and install them as a package. IBM Informix provides a Windows-based interface for this, which has the ability to do the package preparation work for you. The package preparation

352

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch10.fm

interface, called BladeSmith, allows you to populate a properties definition dictionary.

When the properties are all defined and you proceed, BladeSmith creates, assembles, and arranges a directory structure with a complete tree layout of all the components that are required and handled in a DataBlade registration process. The resulting directory tree layout and assembly pieces provide a prepared package that is ready to ship to an operating system of your choice.

Likewise, any language source code that is output for the preparation task is parcelled out for the appropriate component nodes also.

The dispensation for the BlabdeSmith file components and directory structure is

laid out based on the type of component node, described in Table 10-3.

Table 10-3 Bladesmith file package creation layout

Component node What is generated

Source All source code in the coding languages you use for your

DataBlade module objects

Client

Server

Client code (activeX or Java)

Server code in the coding language you specified for BladeSmith

Individual language Source code for the represented language (C, Java, or SPL)

For further information on creating datablade objects using BladeSmith generating files, visit the IBM Information Center website under the Datablade

Developers Kit Users Guide Section at http://publib.boulder.ibm.com/infocenter/idshelp/v115/index.jsp?topic=/com.ibm.

dbdk.doc/sii-smith-27272.htm

For further information or examples of existing bladelets and downloads developed by users, check out the article Downloadable Bladelets and Demos at http://www.ibm.com/developerworks/data/zones/informix/library/samples/db_downlo ads.html

There is also a downloads page featuring bladelets at the International Informix

Users Group site, called “ORDBMS - Object-Relational Database Extensibility,

DataBlades” at http://www.iiug.org/software/index_ORDBMS.html

Chapter 10. User defined routines

353

7884ch10.fm

Draft Document for Review August 23, 2010 10:53 am

354

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch11.fm

11

Chapter 11.

Working with Ruby on Rails

This chapter contains information about how to develop applications against an

IBM Informix database using the Ruby programming language and the Rails web development framework.

In this chapter, we discuss the following topics:

򐂰 Introduction to Ruby and Ruby on Rails

򐂰 Installing Ruby on Rails

򐂰 Options available to use an IBM Informix database with Ruby

򐂰 How to perform basic database operations

򐂰 Use of specific Informix data types

򐂰 Using Rails with an Informix database.

© Copyright IBM Corp. 2010. All rights reserved.

355

7884ch11.fm

Draft Document for Review August 23, 2010 10:53 am

11.1 A brief overview of Ruby on Rails

Ruby is a open source programming scripting language with a focus on simplicity and productivity. Ruby is similar to other scripting languages like Perl or Python with the difference that Ruby is an object-oriented language. Ruby is both technology and platform independent. You can find implementations of the Ruby runtime on C, Java, and even .NET. This makes Ruby a really useful option for any scripting needs.

Refer to the Ruby website for more information about the Ruby language http://www.ruby-lang.org/en/about/

Rails is an open source Ruby framework for developing database-backed web applications. Rails explodes the object-orientated core design of Ruby helping developers to build websites and applications with minimum coding efforts.

Rails is based on two key principles:

򐂰 Convention over Configuration (CoC) where developers need to focus only on the exceptions to the conventions. Every other aspect of the application, from design to implementation, is automatically done by the defined conventions.

The conventions define rules such as use a plural for the table names. For example, if the application uses an entity call Book, the table that stores this entity must be called Books, if it stores details about a Person, the table must be called People.

򐂰 Don’t Repeat Yourself (DRY). Information is located in one place only.

Database object definitions, documentation, configuration scripts all are kept in one global place and consulted when information about them is required.

Refer to the Ruby on Rails website for more information at http://rubyonrails.org/documentation

11.1.1 Architecture of Ruby on Rails

Ruby on Rails is build with the Model-View-Controller (MVC) architecture that is typically used in web based GUI programming. This architecture has three main concepts:

򐂰 Model: This is the business logic of the system. This also encompasses the persistence layer because it interacts with a database back end.

򐂰 View: This is the GUI interface of the Model to the end user. There can be many Views for one Model.

356

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch11.fm

򐂰 Controller: This is the action taken by the user using the View. It takes inputs from the end user through the View and executes the business logic encapsulated in the Model.

The Rails framework provides a set of utilities and components designed to facilitate the development of web applications:

򐂰

Rake:

Rake is a build tool bundled with the Ruby programming language. It is the equivalent to the Make on UNIX.

򐂰

WEBrick:

WEBrick is the web server bundled along with Ruby on Rails.

򐂰

Active Record:

ActiveRecord is the object-relational mapper of Rails and provides for persistence. It presents the database table as a class, which in Rails is called model.

򐂰

Action Controller

Action Controller is the component that manages the controllers in a Rails application. It also processes and dispatches incoming requests.

򐂰

Action View

Action View manages the views in a Rails application.

11.1.2 Ruby driver and Rails adapter

IBM Informix supports database access for client applications written in the Ruby programming language and web application development with the Rail framework.

Ruby driver

To use an database with Ruby, the application requires a Ruby driver. This driver provides the layer that connect the Ruby runtime with the database server.

There are two drivers which allows Ruby to connect to an IBM Informix database:

򐂰 Ruby Informix driver:

The Ruby Informix driver is an Open Source project supported by the Open

Source community. It allows Ruby to connect to any IBM Informix database server. The Ruby driver is developed using the IBM Informix ESQL/C language that provides full support for all the Informix database features and data types. Because it uses the Informix Client SDK libraries,

򐂰 Ruby Driver for IBM Data Servers driver (IBM_DB):

Chapter 11. Working with Ruby on Rails

357

7884ch11.fm

Draft Document for Review August 23, 2010 10:53 am

The Data Server Ruby driver, or IBM_DB, is provided, supported, and developed by IBM as an Open Source project. The Ruby driver is bundled together with the Rails Adapter in the Rails Adapter/Driver for IBM Data

Servers package.

Rails adapter

A Rails adapter is a Ruby script that allows you to use a specific Ruby driver within the Rails framework. It provides the required Ruby objects, for example the

ActiveRecord object, that enables the full use of the Ruby driver inside the Rails framework.

IBM Informix supports two Rails adapters:

򐂰 Informix_adapter.rb, used in conjunction with the Ruby Informix driver.

Requires the IBM Informix Client SDK libraries for the communication with the

Informix database server.

򐂰

ibm_db_adapter.rb, used with the Ruby Driver for IBM Data Servers. Requires the IBM Data Server Driver for ODBC and CLI package.

Both adapters are available from the Ruby repository as Ruby gems. Ruby Gems are self-contained packages containing all the libraries, source files, and scripts needed for the Ruby component.

11.2 Setup and configuration

This section describes how to set up and configure both Ruby drivers and Rails adapters for use with an IBM Informix database.

11.2.1 Ruby Informix driver

The Ruby Informix driver is available for download at the SourceForge website at: http://rubyforge.org/projects/ruby-informix

You can use the Ruby utility Gem to download the Ruby Informix driver automatically from the Ruby repository and install it in the Ruby environment.

Ruby Gems are self-contained packages with the libraries, source code, and scripts for Ruby libraries.

Run the following command from your Ruby session to install the Ruby Informix driver: gem install ruby-informix

358

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch11.fm

Because the driver shared library, informixc.so

, is built during the installation process, the environment should contain the correct settings for compiling

ESQL/C applications. Refer to chapter Chapter 4, “Working with ESQL/C” on page 121 for ESQL/C the setting details.

You can find more information about the install process in the README file

inside the Gem directory. See Example 11-1 for the list of files included with the

Ruby Informix driver.

Example 11-1 Gem directory

Directory of C:\work\Ruby187\lib\ruby\gems\1.8\gems\ruby-informix-0.7.3

03/07/2010 19:34 <DIR> .

03/07/2010 19:34 <DIR> ..

03/07/2010 19:19 8,383 Changelog

03/07/2010 19:19 1,470 COPYRIGHT

03/07/2010 19:29 <DIR> ext

03/07/2010 19:35 <DIR> lib

03/07/2010 19:19 4,500 README

03/07/2010 19:19 <DIR> test

3 File(s) 14,353 bytes

5 Dir(s) 76,168,769,536 bytes free

Configuration

The Ruby Informix uses the same connectivity information as other Informix

Client SDK components. It uses the environment variable

INFORMIXDIR

to locate the libraries and resources such as error message files or configuration files.

By default, the Ruby driver connects to the database server specified in the

INFORMIXSERVER

environment variable. Same as the other Informix Client SDK components, the information regarding the

INFORMIXSERVER

value is stored on the

sqlhosts file or the Windows registry. For more information, refer to 2.2.2, “Setting up IBM Informix Client Software Development Kit” on page 33.

The shared library search path variables, for example,

LD_LIBRARY_PATH

or

SHLIB_PATH

, must contain the

$INFORMIX/libl

and

$INFORMIX/lib/esql directories, otherwise the Ruby driver may fail to load the ESQL/C libraries that it requires for work.

Data types

The Ruby Informix driver provides the data types to be used against an IBM

Informix database. The driver provides specific types such as

Informix::IntervalYTM or Informix::Slob to handle specific Informix types.

Table 11-1 on page 360 shows the data type mapping between the Ruby Informix

driver and the Informix database.

Chapter 11. Working with Ruby on Rails

359

7884ch11.fm

Draft Document for Review August 23, 2010 10:53 am

Table 11-1 Ruby Informix data type mapping

Informix data type Ruby data type

Numeric SMALLINT, INT, INT8, FLOAT, SERIAL and SERIAL8

CHAR, NCHAR, VARCHAR,

NVARCHAR

String

DATE Date

DATETIME TIME

INTERVAL

DECIMAL, MONEY

Informix::IntervalYTM, Informix::IntervalDTS

BigDecimal

BOOL

BYTE, TEXT

CLOB, BLOB

TrueClass, FalseClass

StringIO, String

Informix::Slob

Verifying connectivity

Ruby includes an interactive shell called

irb

that can be used to run simple Ruby

statements. irb

is located in the bin directory of the Ruby installation.

The driver name used inside the Ruby scripts to reference the Ruby Informix driver is

informix

.

To test if the Ruby driver can connect to a database, you must load the Ruby driver and then create an connection using the Ruby Informix object.

Example 11-2 demonstrates how to load the Ruby Informix driver and connect to

an IBM Informix database. The fist command,

require 'informix'

, tells Ruby runtime to load the Ruby Informix driver. After that we create a Ruby Informix connection object and print the database version information.

Example 11-2 Testing connection with Ruby informix

C:\work>irb irb(main):001:0> require 'informix'

=> true irb(main):002:0> db=Informix.connect('stores_demo','informix','password')

=> #<Informix::Database:0x8176110> irb(main):003:0> puts db.version

IBM Informix Dynamic Server Version 11.50.FC6

=> nil irb(main):004:0>

360

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch11.fm

11.2.2 Data Server Ruby driver

The Data Server Ruby driver uses the Data Server CLI driver to connect the

Informix database. It uses the DRDA protocol so the version of the IBM Informix database server must be 11.10 or 11.50.

The driver is included as part of the IBM Data Server Driver package and it is also available to download directly from the RubyForge website at: http://rubyforge.org/projects/rubyibm/

The complete package can be installed using the Ruby Gem utility by running the following command from a Ruby session: gem install ibm_db

For information about the build process and setup process for the Data Server

Driver, consult the README file in the driver directory.

Example 11-3 shows the Data Server Ruby driver directory.

Example 11-3 ibm_db gem directory

Directory of C:\work\Ruby187\lib\ruby\gems\1.8\gems\ibm_db-0.10.0-x86-mswin32

03/07/2010 17:30 <DIR> .

03/07/2010 17:30 <DIR> ..

03/07/2010 17:30 6,063 CHANGES

03/07/2010 17:30 <DIR> ext

03/07/2010 17:30 1,656 init.rb

03/07/2010 18:06 <DIR> lib

03/07/2010 17:30 1,088 LICENSE

03/07/2010 17:30 299 MANIFEST

03/07/2010 17:30 13,402 README

03/07/2010 17:30 <DIR> test

5 File(s) 22,508 bytes

5 Dir(s) 76,167,290,880 bytes free

You can find additional information regarding the Ruby driver for IBM Data

Servers at http://publib.boulder.ibm.com/infocenter/db2luw/v9r5/topic/com.ibm.db2.luw.apdv

.ruby.doc/doc/t0052765.html

On some platforms, such as Windows, the shared library for the Ruby driver is already included in the package, therefore, there is no need for a C build environment.

Chapter 11. Working with Ruby on Rails

361

7884ch11.fm

Draft Document for Review August 23, 2010 10:53 am

Example 11-4 shows the Ruby driver directory from the Data Server Client on

Windows after the installation.

Example 11-4 Windows Data Server Ruby directory

C:\work>dir "C:\Program Files\IBM\IBM DATA SERVER DRIVER\ruby"

Volume in drive C is W2003

Volume Serial Number is 50DA-70D7

Directory of C:\Program Files\IBM\IBM DATA SERVER DRIVER\ruby

17/05/2010 02:16 <DIR> .

17/05/2010 02:16 <DIR> ..

30/05/2009 11:09 198,144 ibm_db-0.10.0-mswin32.gem

1 File(s) 198,144 bytes

2 Dir(s) 76,167,372,800 bytes free

C:\work>

Configuration

The Data Server Ruby driver uses the Data Server ODBC/CLI driver for the connection to the database.

The configuration details are the same as with the ODCB/CLI driver. These

details are usually keep in the db2profile.ini file. Refer to the 2.2.3, “Setting up

IBM Data Server drivers” on page 40

chapter for detail information about the

Data Server Driver configuration.

Data Types

There are no specific Ruby objects to use Informix data types. The Data Server

Ruby driver supports the same Informix data types as the Data Server Driver for

CLI.

Verifying connectivity

We use a irb session to test the connectivity against an IBM Informix database server.

The reference name of the Data Server Ruby driver is ibm_db, you must load this driver before creating the Ruby connection object.

Example 11-5 shows how to load the Ruby driver and how to connect to the

Informix server.

Example 11-5 Testing connection with data server ruby driver

C:\work>irb

362

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am irb(main):001:0> require 'mswin32/ibm_db'

=> true irb(main):002:0> db=IBM_DB.connect 'dsc_dsn','informix','password'

=> #<IBM_DB::Connection:0x81fb6d0> irb(main):003:0>

7884ch11.fm

First we load the Ruby driver with require 'mswin32/ibm_db' , then open the connection using the IBM_DB::connect method.

Note: Because we are using the Windows version of the Ruby driver we must

prefix the driver name with the mswin32 directory

You can also made a dsn-less connection by specifying all the required parameters in the connection string:

IBM_DB.connect 'DRIVER={IBM DB2 ODBC DRIVER};DATABASE=stores_demo;

HOSTNAME=kodiak;PORT=9089;PROTOCOL=TCPIP;UID=informix;PWD=password;', '', ''

11.2.3 Rails adapters

The Ruby informix Rails Adapter provides the Ruby ActiveRecord object that makes the use of the Ruby driver to work on the Rails framework possible.

The Rails adapter for the Ruby Informix driver is a free download available at http://rubyforge.org/projects/rails-informix/

It can be automatically installed as a Ruby Gem using the

gem

utility.

Example 11-6 shows how to install the Ruby Informix adapter.

Example 11-6 Installing Ruby Informix adapter

C:\work>gem install activerecord-informix-adapter -v 1.1.1

Successfully installed activerecord-informix-adapter-1.1.1

1 gem installed

Installing ri documentation for activerecord-informix-adapter-1.1.1...

Installing RDoc documentation for activerecord-informix-adapter-1.1.1...

C:\work>

The configuration of the adapter depends on the version of Rails installed in the

Ruby environment. On versions older than 2.x the adapter script file informix_adapter.rb

has to be copied into the connection_adapters

directory.

Example 11-7 on page 364 shows the connection_adapter directory with both

Rails adapters installed:

Chapter 11. Working with Ruby on Rails

363

7884ch11.fm

Draft Document for Review August 23, 2010 10:53 am

Example 11-7 connection _adapter directory

Directory of

C:\work\Ruby187\lib\ruby\gems\1.8\gems\activerecord-1.15.6\lib\active_record\co nnection_adapters

3/07/2010 18:02 <DIR> .

3/07/2010 18:02 <DIR> ..

3/07/2010 17:01 <DIR> abstract

3/07/2010 17:01 5,235 abstract_adapter.rb

3/07/2010 17:01 6,957 db2_adapter.rb

3/07/2010 17:01 27,749 firebird_adapter.rb

3/07/2010 17:01 30,751 frontbase_adapter.rb

3/07/2010 17:30 70,854 ibm_db_adapter.rb

3/07/2010 20:06 9,916 informix_adapter.rb

3/07/2010 17:01 13,774 mysql_adapter.rb

3/07/2010 17:01 11,531 openbase_adapter.rb

3/07/2010 17:01 25,897 oracle_adapter.rb

3/07/2010 17:01 21,513 postgresql_adapter.rb

3/07/2010 17:01 13,162 sqlite_adapter.rb

3/07/2010 17:01 22,087 sqlserver_adapter.rb

3/07/2010 17:01 22,622 sybase_adapter.rb

13 File(s) 282,048 bytes

3 Dir(s) 76,166,725,632 bytes free

When using versions of Rails older than 2.x, it is also required to include the reference name of the Ruby driver in the RAILS_CONNECTION_ADAPTER parameter in the ActiveRecord

ruby script. See Example 11-8 for an example.

Example 11-8 active_record file

C:\work\Ruby187\lib\ruby\gems\1.8\gems\activerecord-1.15.6\lib>grep informix active_record.rb

RAILS_CONNECTION_ADAPTERS = %w( mysql postgresql sqlite firebird sqlserver db2 oracle sybase openbase frontbase informix ibm_db )

C:\work\Ruby187\lib\ruby\gems\1.8\gems\activerecord-1.15.6\lib>

After creating a Rails project, the project configuration file that contains the database information, database.yml

, must be updated with the connection details of the IBM Informix database. This file is located in the <project>/config directory and has three sections,

development

,

test

and

production

. These sections point to databases on the respective environments. The database connectivity properties include:

򐂰 adapter: The Ruby driver used. You do not have to give the complete version.

򐂰 database: Database to be connected to.

򐂰 username and password: To connect to the Informix server.

364

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch11.fm

򐂰 server: The machine that Informix server is running on.

򐂰 port: The DRDA port on the Informix server.

Example 11-9 shows a typical database.yml file with the details for an IBM

Informix database. The Rails application is named stores7 and we are connecting to an Informix server called demo_on

.

We use the Ruby Informix driver reference name for the adapter parameter informix . The server parameter identifies the IBM Informix server to connect to.

The information about the Informix server such as host and port is retrieved from the sqlhosts file or Windows registry.

Example 11-9 database.yml for the Ruby informix Adapter

C:\work\stores7\config>type database.yml

development:

adapter: informix

database: stores7

pool: 5

timeout: 5000

server: demo_on

username: informix

password: password

# Warning: The database defined as 'test' will be erased and

# re-generated from your development database when you run 'rake'.

# Do not set this db to the same as development or production.

test:

adapter: mysql

database: stores7

username: root

password:

host: localhost production:

adapter: informix

database: stores7

pool: 5

timeout: 5000

server: demo_on

username: informix

password: password

C:\work\stores7\config>

Chapter 11. Working with Ruby on Rails

365

7884ch11.fm

Draft Document for Review August 23, 2010 10:53 am

Rails Adapter for IBM Data Server

The Rails Adapter for the IBM Data Server Ruby driver is bundled with the Ruby driver. It is installed at the same time as the Ruby driver is installed.

In the same way as with the Ruby Informix Rails adapter, if the Rails Adapter for

IBM Data Server is installed on a version of Rails older than 2.x, the adapter script ( informix_adapter.rb

) must be copied in the connection_adapter directory, and the RAILS_CONNECTION_ADAPTER parameter in the active_record.rb

Ruby script has to be updated.

The database configuration file for a Rails project, database.yml

, has to be updated with the details for the IBM Informix server.

Example 11-10 shows a

database.yml

used in a Rails project that connects to an

IBM Informix database.

Example 11-10 database.yml for the Rails adapter for IBM Data Servers

C:\work\stores7\config>type database.yml

development:

adapter: ibm_db

database: stores7

pool: 5

timeout: 5000

host: kodiak

port: 9089

username: informix

password: password

# Warning: The database defined as 'test' will be erased and

# re-generated from your development database when you run 'rake'.

# Do not set this db to the same as development or production.

test:

adapter: mysql

database: stores7

username: root

password:

host: localhost

C:\work\stores7\config>

The adapter parameter is set to the reference name of the Data Server Ruby driver ibm_db. It also contains the host name and the port parameter with the details about the DRDA Informix instance. These details are the same as used in the Data Server driver for ODBC/CLI.

366

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch11.fm

For a list of all the parameters refer to Info Center documentation at http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.swg.im.dbcli

ent.ruby.doc/doc/t0052780.html

11.3 Database operations

This section provides examples of using both Ruby drivers to perform basic operations against an IBM Informix database server. We also demonstrate how to use the Rails adapter to create basic web applications.

Using Ruby Informix driver

In this section we discuss the basic database operation using the Ruby Informix driver.

Connection to the database

Example 11-11 shows how to connect to an Informix database. The database

name, user name, and password are passed as the parameters in the command line.

Example 11-11 ifx_connect.rb output

C:\work>type ifx_connect.rb

# load the informix driver require 'informix'

# Connect to the database

db = Informix.connect(ARGV[0],ARGV[1],ARGV[2])

# print database information

print "Connected to #{db.version}"

db.close

C:\work>ruby ifx_connect.rb stores_demo informix password

Connected to IBM Informix Dynamic Server Version 11.50.FC6

C:\work>

Getting information about a table

Example 11-12 demonstrate how to use the Ruby connection object to retrieve

metadata information about the state table. We use the columns() method of the

Informix connection object to retrieve a Ruby array with all the metadata information.

Example 11-12 ifx_metadata.rb output

C:\work>cat ifx_metadata.rb

Chapter 11. Working with Ruby on Rails

367

7884ch11.fm

Draft Document for Review August 23, 2010 10:53 am

# load the informix driver require 'informix'

# Connect to the database

db = Informix.connect(ARGV[0])

# print database information print "Connected to #{db.version}\n"

db.columns(ARGV[1]).each {

|name| name.each {|elem| print " #{elem[0]} #{elem[1]}\n"}

} db.close

C:\work>ruby ifx_metadata.rb stores_demo state

Connected to IBM Informix Dynamic Server Version 11.50.FC6

precision 0

type 0

scale 0

length 2

xid 0

nullable true

name code

stype CHAR

...

Executing a simple SQL statement

Using the Ruby driver you can run an SQL statement directly from the Ruby connection object or through a prepared statement object.

Example 11-13 demonstrates how to run a simple SQL statement using a

prepared statement Ruby object. The execute() method returns the number of affected rows.

Example 11-13 ifx_execute.rb output

C:\work>cat ifx_execute.rb

# load the informix driver

require 'informix'

# Connect to the database

db = Informix.connect(ARGV[0])

# print database information

print "Connected to #{db.version}\n"

# create a prepare object with the SQL passed

stmt = db.prepare(ARGV[1])

# Execute the prepared statement

rc=stmt.execute()

print "Result=#{rc}"

db.close

368

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch11.fm

C:\work>ruby ifx_execute.rb stores_demo "DELETE from STATE where CODE='AR'"

Connected to IBM Informix Dynamic Server Version 11.50.FC6

Result=1

C:\work>

If the SQL statement returns only one row, the execute()

method can be used to

retrieve that value. See Example 11-14 for a example.

Example 11-14 ifx_execute.rb output

C:\work>ruby ifx_execute.rb stores_demo "SELECT sname FROM state WHERE

code='CA'"

Connected to IBM Informix Dynamic Server Version 11.50.FC6

Result=snameCalifornia

C:\work>

Using parameters

Example 11-15 shows how to prepare and execute a parametrized INSERT

statement using the Ruby driver.

Example 11-15 ifx_parameters output

C:\work>cat ifx_insert.rb

# load the informix driver

require 'informix'

# Connect to the database db = Informix.connect('stores_demo')

# print database information

print "Connected to #{db.version}\n"

# create a prepare object with the SQL passed

stmt = db.prepare('INSERT INTO state(code,sname) VALUES (?,?)')

# Execute the statement using parameters

rc=stmt.execute(ARGV[0],ARGV[1])

# Execute the prepared statement

print "Result=#{rc}"

db.close

C:\work>ruby ifx_insert.rb AR Arizona

Connected to IBM Informix Dynamic Server Version 11.50.FC6

Result=1

C:\work>

Chapter 11. Working with Ruby on Rails

369

7884ch11.fm

Draft Document for Review August 23, 2010 10:53 am

Selecting data from the database

When selecting multiple records from the database the application must create a

cursor object to fetch the selected rows. Example 11-16 illustrates how to return

information using an Informix cursor.

Example 11-16 ifx_cursor.rb output

C:\work>cat ifx_cursor.rb

# load the informix driver

require 'informix'

# Connect to the database

db = Informix.connect('stores_demo')

# display database information

print "Connected to #{db.version}\n"

# Create a Cursor object

cur = db.cursor(ARGV[0])

# Open the cursor and fetch some rows

cur.open.each {|rows|

puts rows*" = "

}.close

# Close connection

db.close

C:\work>ruby ifx_cursor.rb "SELECT FIRST 3 sname FROM state"

Connected to IBM Informix Dynamic Server Version 11.50.FC6

Alaska

Hawaii

California

C:\work>

Using the Ruby Informix IfxSlob class

The Slob class is the Ruby interface for handling Smart Large Objects. It provides methods for every action applicable with a smart large object. By using the Informix::Slob class, it is possible to perform the same operations against a smart large object as with other programming languages and drivers. The Slob methods such as Seek() or Lock() allow random I/O to individuals part of the large object that can only be achieved using this Ruby driver.

Example 11-17 shows how to select a BLOB from a database table. It retrieves

the catalog_advert CLOB column from the catalog table and prints out the content of the large object and the size of the large object.

Example 11-17 ifx_blob.rb output

C:\work>cat ifx_blob.rb

# load the informix driver

require 'informix'

370

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch11.fm

# Connect to the database

db = Informix.connect("stores_demo")

# Creates an Informix Slob object

slob = Informix::Slob

# Opens a cursor to retrieve

cur = db.cursor("SELECT catalog_num,advert_descr FROM catalog WHERE

catalog_num=?")

cur.open(ARGV[0]).each {|rows|

slob = rows[1].open

print "Number = #{rows[0]}\n"

# Reads the blob data as a String

print "Clob data= #{rows[1].read(rows[1].size)}\n"

print "Clob Size= #{rows[1].size}\n"

# Close the Slob object

slob.close

}

# Close database connection

db.close

C:\work>

C:\work>ruby ifx_blob.rb 10001

Number = 10001

Clob data= Brown leather. Specify first baseman's or infield/outfield style.

Clob Size= 98

C:\work>ruby ifx_blob.rb 10027

Number = 10027

Clob data=

Double or triple crankset with choice of chainrings or chunky bacon. For double crankset...

Clob Size= 154

C:\work>ruby ifx_blob.rb 10031

Number = 10031

Clob data= No buckle so no plastic touches your chin. Meets both ANSI and

Snell...

Clob Size= 123

C:\work>

For examples and a full description of all the method implemented by the

Informix::Slob class, refer to the Ruby Informix driver documentation at http://ruby-informix.rubyforge.org/doc/classes/Informix/Slob.html

Using the Ruby Informix INTERVAL

The Ruby Informix driver provides a specific class to deal with the Informix

INTERVAL data type.

Chapter 11. Working with Ruby on Rails

371

7884ch11.fm

Draft Document for Review August 23, 2010 10:53 am

Example 11-18 shows how to define and use the

Informix::Interval class. In this example we create an Interval Year to Month with one year and one month as the value. The code performs a simple arithmetic operation adding the Interval to the current date.

Example 11-18 ifx_interval.rb output

# Creates an Informix Interval object

minterval = Informix::Interval.year_to_month(1, 1)

print "Interval \t=#{minterval}\n"

today = Date.today

print "Current date \t=#{today}\n"

print"Interval+today\t=#{minterval + today}\n"

C:\work>ruby ifx_interval.rb

Interval =1-01

Current date =2010-07-04

Interval+today =2011-08-04

C:\work>

You can fine the full documentation about all the methods supported by the Ruby

Informix driver at http://ruby-informix.rubyforge.org/doc/

Using Data Server Ruby driver

In this section we discuss the basic database operation using the Data Server

Ruby driver.

Connecting to the database

The syntax for opening a connection with an Informix database server using the

Data Server Ruby driver differs from the syntax used by the Ruby Informix driver.

Example 11-19 shows a simple Ruby script that creates a connection object and

opens the connection. In the example code we also retrieve information about the Informix server using the IBM_DB::server_info class.

Example 11-19 dsc_connect.rb

C:\work>cat dsc_connect.rb

# load the informix driver

require 'mswin32/ibm_db'

# Connect to the database

db = IBM_DB.connect(ARGV[0],ARGV[1],ARGV[2])

info = IBM_DB.server_info(db)

# display database information

372

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

print "Connected to #{info.DBMS_NAME} #{info.DBMS_VER}"

C:\work>ruby dsc_connect.rb testdsc informix password

Connected to IDS/NT64 11.50.0000

C:\work>

7884ch11.fm

The Data Server Ruby driver is based on calls to the CLI driver, this means it

takes the connection details from the db2cli.ini configuration file. Example 11-20

shows the contents of the db2cli.ini used for this test.

Example 11-20 db2cli.ini

C:\work>type "c:\Documents and Settings\Administrator\db2cli.ini"

[dsc_dsn]

Protocol=TCPIP

Port=9089

Hostname=kodiak

Database=stores_demo

PWD=password

UID=informix

C:\work>

Executing an SQL statement

Example 11-21 demonstrate how to execute an SQL statement using the

prepare()

and execute() methods of the IBM_DB driver. Both methods, prepare()

and execute()

, require the connection and statement objects as a parameters.

Example 11-21 dsc_execute.rb output

C:\work>cat dsc_execute.rb

# load the informix driver

require 'mswin32/ibm_db'

# Connect to the database

db = IBM_DB.connect(ARGV[0],'','')

info = IBM_DB.server_info(db)

# display database information

print "Connected to #{info.DBMS_NAME} #{info.DBMS_VER}\n"

# create a prepare object with the SQL passed

stmt = IBM_DB.prepare(db,ARGV[1])

# Execute the prepared statement

rc=IBM_DB.execute(stmt)

print "Result=#{rc}"

Chapter 11. Working with Ruby on Rails

373

7884ch11.fm

Draft Document for Review August 23, 2010 10:53 am

C:\work>ruby dsc_execute.rb dsc_dsn "DELETE from STATE WHERE code='NW'"

Connected to IDS/NT64 11.50.0000

Result=true

C:\work>

Parametrized SQL statement

When using parameters for an SQL statement, the application can use the execute() method and provide the parameters as second argument for the method call.

Example 11-22 insert a new record into the

state table with the values passed to the script through the command line.

Example 11-22 dsc_param.rb output

C:\work>cat dsc_param.rb

# load the informix driver

require 'mswin32/ibm_db'

# Connect to the database

db = IBM_DB.connect('dsc_dsn','','')

info = IBM_DB.server_info(db)

# display database information

print "Connected to #{info.DBMS_NAME} #{info.DBMS_VER}\n"

sql = 'INSERT INTO state(code, sname) VALUES (?,?)'

# create a prepare object

stmt = IBM_DB.prepare(db,sql)

# display Statement and parameters

print "SQL=#{sql}\n"

# Execute the prepared statement

rc=IBM_DB.execute(stmt,[ARGV[0],ARGV[1]])

print "Result=#{rc}"

C:\work>

C:\work>ruby dsc_param.rb "NW" "NewState"

Connected to IDS/NT64 11.50.0000

SQL=INSERT INTO state(code, sname) VALUES (?,?)

Result=true

C:\work>

Selecting data

The Data Server Ruby driver has several methods that allow retrieving data from the database, such as f etch_array() , fetch_assoc() , and fetch_row() .

374

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch11.fm

Example 11-23 shows a simple Ruby script that returns the first two columns of

an SQL SELECT statement passed through the command line. The script uses the fecth_array() method to retrieve the rows as an array object.

Example 11-23 Select data using fetch_array()

C:\work>cat dsc_fetch.rb

# load the informix driver

require 'mswin32/ibm_db'

# Connect to the database

db = IBM_DB.connect(ARGV[0],'','')

info = IBM_DB.server_info(db)

# display database information

print "Connected to #{info.DBMS_NAME} #{info.DBMS_VER}\n"

# create a prepare object with the SQL passed

stmt = IBM_DB.prepare(db,ARGV[1])

# Execute the prepared statement

IBM_DB.execute(stmt)

while row = IBM_DB.fetch_array(stmt)

puts "#{row[0]}:#{row[1]}"

end

C:\work>ruby dsc_fetch.rb dsc_dsn "SELECT FIRST 3 code,sname FROM state"

Connected to IDS/NT64 11.50.0000

AK:Alaska

HI:Hawaii

CA:California

C:\work>

Using Smart Large Objects

The Data Server Ruby driver handles smart large objects as normal data types. It does not support all the smart features that are normally available with other drivers. However, it simplify the code needed to deal with these data types.

Example 11-24 retrieves a CLOB column from the

catalog

table and displays the contents.

Example 11-24 dsc_blob.rb

C:\work>cat dsc_blob.rb

# load the informix driver

require 'mswin32/ibm_db'

# Connect to the database

db = IBM_DB.connect('dsc_dsn','','')

Chapter 11. Working with Ruby on Rails

375

7884ch11.fm

Draft Document for Review August 23, 2010 10:53 am

info = IBM_DB.server_info(db)

# display database information

print "Connected to #{info.DBMS_NAME} #{info.DBMS_VER}\n"

# create a prepare object with the SQL passed

sql = "SELECT catalog_num,advert_descr FROM catalog WHERE catalog_num=?"

stmt = IBM_DB.prepare(db,sql)

# Execute the prepared statement

IBM_DB.execute(stmt,ARGV)

while row = IBM_DB.fetch_array(stmt)

puts "#{row[0]}:#{row[1]}"

end

C:\work>ruby dsc_blob.rb 10001

Connected to IDS/NT64 11.50.0000

10001:Brown leather. Specify first baseman's or infield/outfield style.

Specify right- or left-handed.

C:\work>

You can find additional documentation about the methods for the Ruby for IBM

Data Server at http://rubyibm.rubyforge.org/docs/driver/2.0.0/doc/ or in the IBM DB2 Information Center website at http://publib.boulder.ibm.com/infocenter/db2luw/v9r7/topic/com.ibm.swg.im.dbcli

ent.ruby.doc/doc/c0052760.html

11.4 Using the Rails adapter with Ruby Informix

In this section we demonstrate how to create a basic web application using the

Rails framework with the Ruby Informix Adapter.

One of the key concepts of Rails is Convention over Configuration. This means that you must follow the convention rules when designing your database so the

Rails framework can automatically generate code to handle typical operations with the database.

Some of the convention rules required by the Rails framework are:

򐂰

Table name must be a plural name for the entity it contains. For example, if the table contains information about books, it should be called Books.

򐂰 The table must contains an unique primary key column and should be called

ID.

376

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch11.fm

򐂰 For both Ruby drivers, an Informix SQL SEQUENCE must be created for each of the tables used. The name of the sequence must be tablename_seq.

You can find additional information about Rails conventions on the RailsGuides website at: http://guides.rubyonrails.org/

Creating database objects

The following examples use the orders

and items

tables from the stores7 database. Due to the convention rules used on Rails, we must modify the schema of the tables to follow the Rails conventions.

Example 11-25 shows the SQL script we use to change the name of the two

tables, create views to incorporate the ID column, and create the SQL sequence required for object reference.

Example 11-25 setup.sql script

-- Orders table

RENAME TABLE orders TO order;

CREATE VIEW orders(

id,

order_date,

customer_num,

ship_instruct,

backlog,

po_num,

ship_date,

ship_weigh,

ship_charge,

paid_date) AS

SELECT * FROM order;

CREATE SEQUENCE orders_seq;

-- Items table

RENAME TABLE items TO item;

CREATE VIEW items (

id,

order_num,

stock_num,

manu_code,

quantity,

total_price) AS

SELECT * FROM item;

CREATE SEQUENCE items_seq;

Chapter 11. Working with Ruby on Rails

377

7884ch11.fm

Draft Document for Review August 23, 2010 10:53 am

Creating the Rails application

You must create a Rails application using Rails commands before adding any objects or definitions.

Example 11-26 shows the output of the

rail stores

command

Example 11-26 Output of the rail stores command

C:\work>rails stores

create

create app/controllers

create app/helpers

create app/models

create app/views/layouts

create config/environments

create components

create db

create doc

create lib

create lib/tasks

create log

create public/images

create public/javascripts

create public/stylesheets

...

For more information refer to the Rails documentation at http://rubyonrails.org/documentation

Modifying the database configuration file

The database.yml

must include the connection details of the database.

Example 11-27 shows the database configuration file used by our application.

Example 11-27 database.yml file

C:\work\stores>type config\database.yml

development:

adapter: informix

database: stores7

pool: 5

timeout: 5000

server: demo_on

username: informix

password: password

# Warning: The database defined as 'test' will be erased and

378

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

# re-generated from your development database when you run 'rake'.

# Do not set this db to the same as development or production.

test:

adapter: mysql

database: stores7

username: root

password:

host: localhost production:

adapter: informix

database: stores7

pool: 5

timeout: 5000

server: demo_on

username: informix

password: password

C:\work\stores>

7884ch11.fm

Creating the Rails model and controllers

To make Rails aware of the database tables, you create model and controller in your application. We use the model and controller Ruby script to create model and controller for the two tables used in our application.

Example 11-28 shows the batch script used to generate the model and controller

for the

Items

and

Orders

table.

Example 11-28 objects.cmd

ruby script\generate model Order ruby script\generate controller Order ruby script\generate model Item ruby script\generate controller Item

Example 11-29 shows the output of each of the commands in the

objects.cmd

batch script.

Example 11-29 Output of objects.cmd

C:\work\stores>ruby script\generate model Order

exists app/models/

exists test/unit/

exists test/fixtures/

create app/models/order.rb

create test/unit/order_test.rb

create test/fixtures/orders.yml

exists db/migrate

Chapter 11. Working with Ruby on Rails

379

7884ch11.fm

Draft Document for Review August 23, 2010 10:53 am

create db/migrate/004_create_orders.rb

C:\work\stores>ruby script\generate controller Order

exists app/controllers/

exists app/helpers/

create app/views/order

exists test/functional/

create app/controllers/order_controller.rb

create test/functional/order_controller_test.rb

create app/helpers/order_helper.rb

C:\work\stores>ruby script\generate model Item

exists app/models/

exists test/unit/

exists test/fixtures/

create app/models/item.rb

create test/unit/item_test.rb

create test/fixtures/items.yml

exists db/migrate

create db/migrate/005_create_items.rb

C:\work\stores>ruby script\generate controller Item

exists app/controllers/

exists app/helpers/

create app/views/item

exists test/functional/

create app/controllers/item_controller.rb

create test/functional/item_controller_test.rb

create app/helpers/item_helper.rb

C:\work\stores>

After the objects are created, you must modify the controller Ruby file for each object to build the object scaffold.

We use Rails 1.2.6 on our examples. Rails 2.x does not support dynamic scaffolding. This means it can not retrieve the information for the table column dynamically. In this case, the scaffold for the objects must be created manually while creating the model object. We add the instruction scaffold: object_name to each of the files for creating scaffold.

Example 11-30 shows the Ruby script file for the

Item

and

Order

controllers.

Example 11-30 Controller script

C:\work\stores>cat app/controllers/order_controller.rb class OrderController < ApplicationController

380

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

scaffold :Order end

C:\work\stores>cat app/controllers/item_controller.rb class ItemController < ApplicationController

scaffold :Item end

C:\work\stores>

7884ch11.fm

For more information about the changes in Rails 2.x refer to Rails documentation at http://rubyonrails.org/documentation

Starting the Rails web server

To start the Rails web server use the

rails scripts/server

command.

Example 11-31 demonstrates how to start the server.

Example 11-31 Rails web server

C:\work\stores>ruby script/server

=> Booting WEBrick...

=> Rails application started on http://0.0.0.0:3000

=> Ctrl-C to shutdown server; call with --help for options

[2010-07-05 10:40:00] INFO WEBrick 1.3.1

[2010-07-05 10:40:00] INFO ruby 1.8.7 (2010-01-10) [i386-mingw32]

[2010-07-05 10:40:00] INFO WEBrick::HTTPServer#start: pid=1092 port=3000

Demonstrating Website application

At this point, Rails should have constructed the application for you and you can browse and change the information for your table.

We can open a Web browser and navigate to the local web server to browse the the Order and Item tables: http://127.0.0.1:3000/item http://127.0.0.1:3000/order

Figure 11-1 on page 382 shows the

Item

table listing web page. The web page contains links to perform all the typical operations associated with a database table (select, insert, update, and delete).

Chapter 11. Working with Ruby on Rails

381

7884ch11.fm

Draft Document for Review August 23, 2010 10:53 am

Figure 11-1 Item listing web page

Figure 11-2 shows the New Item website with all the fields from the Item table

ready to be used to insert a new record into the table.

Figure 11-2 Item New web page

Figure 11-3 on page 383 shows the Order listing page.

382

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch11.fm

Figure 11-3 List Order webpage

The Web applications development with Ruby on Rails was designed to be an effortless task. With just four commands and an little configuration, we have created a website that can handle the common table operations for a database application.

11.5 Using the Rails adapter with IBM_DB

In this section we demonstrate how to create a basic web application using the

Rails framework with the IBM_DB Adapter. The sample program is a simple telephone directory application for user to list, add, update, and delete phone entries.

Rails can be used to generate the Data Definition Language (DDL) for the database objects, we show how to create tables with Ruby on Rails.

Creating the Rails application

Use the

rails

command to create the Rails application. We create our application sample in the directory C:\RailsProjects .

Example 11-32 shows how to create a rails application and the

rails

command output of our application.

Example 11-32 Creating a Rails application

C:\RailsProjects>rails sample

create

Chapter 11. Working with Ruby on Rails

383

7884ch11.fm

Draft Document for Review August 23, 2010 10:53 am

create app/controllers

create app/helpers

create app/models

create app/views/layouts

create config/environments

create config/initializers

...

Modifying the database configuration file

Update the database configuration file database.yml with the database connectivity details.

Example 11-33 shows the configuration file for our development database. The

name of the adapter, ibm_db, correspond to the Ruby Adapter for IBM Data

Servers.

Example 11-33 database.yml file

development:

adapter: ibm_db

database: ruby

username: informix

password: Ifmx4you

host: kefka.lenexa.ibm.com

port: 9089

# Warning: The database defined as "test" will be erased and

# re-generated from your development database when you run "rake".

# Do not set this db to the same as development or production.

test: production:

Creating model, control, and view

Ruby on Rails worked on a

Model-Control-View

architecture. You can create model, control, and view components in stages. Here we show a quick way of using the

scaffold

command to have the Rails create the complete application for us including all the directories and necessary files.

The telephone table of our application use strings for first name, last name, and phone number. This table layout forms the

model

for our application. We specify

this model right on the scaffold command as shown in Example 11-34 on page 385.

We invoke the command from the root directory of our project with the

ruby script\generate

script. The syntax for the scaffold options is:

384

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch11.fm

scaffold <model name> <column name: attributes> .. <column name: attributes>

The output shows that Rails creates the necessary models, views and controllers. This command also generate the script to create the tables necessary to associate with the model.

Example 11-34 Creating a scaffold

C:\RailsProjects\sample>ruby script\generate scaffold phonedir

first_name:string last_name:string phone:string

exists app/models/

exists app/controllers/

exists app/helpers/

create app/views/phonedirs

exists app/views/layouts/

exists test/functional/

exists test/unit/

create test/unit/helpers/

exists public/stylesheets/

create app/views/phonedirs/index.html.erb

...

dependency model

exists app/models/

exists test/unit/

exists test/fixtures/

create app/models/phonedir.rb

create test/unit/phonedir_test.rb

create test/fixtures/phonedirs.yml

create db/migrate

create db/migrate/20100704234009_create_phonedirs.rb

Migrating the model

Ruby on Rails calls the creation of the database objects backing the model as

migration

. The scaffold command created a

migrate

script for creating the table attached to the model.

Example 11-35 shows the migration file

db/migrate/20100704234009_create_phonedirs.rb created by the scaffold command. This script has both create and drop sections that means you can rollback any migration. We created a model by name phonedir . Ruby on Rails then created the table phonedirs which is a plural form of the model name. This is the Ruby on Rails convention.

Example 11-35 the phonedir migration file

class CreatePhonedirs < ActiveRecord::Migration

def self.up

create_table :phonedirs do |t|

Chapter 11. Working with Ruby on Rails

385

7884ch11.fm

Draft Document for Review August 23, 2010 10:53 am

t.string :first_name

t.string :last_name

t.string :phone

t.timestamps

end

end

def self.down

drop_table :phonedirs

end end

Use the

rake

utility to migrate the file and create table in the database. rake a simple ruby build script with capabilities similar to make. It can be used to generate the database schema using a migration file.

Example 11-36 shows how to run the rake script to create the model in the

database.

Example 11-36 Creating model

C:\RailsProjects\sample>rake db:migrate

(in C:/RailsProjects/sample)

== CreatePhonedirs: migrating ================================================

-- create_table(:phonedirs)

-> 0.0781s

== CreatePhonedirs: migrated (0.0781s) =======================================

In Example 11-37, we use the Informix

dbschema

utility to export the table schema to check the tables created Ruby on Rails migration. We started with an empty database and the output shows that two tables were created:

򐂰 schema_migrations: Ruby on Rails uses this table to keep track of the various version of the table. This allows you to roll back to the previous version.

򐂰 phonedirs: In this application table, Ruby added a few columns that we did not specify:

– id: This serial column is for the primary key required by Ruby on Rails.

– created_at and updated_at: Ruby on Rails uses these optionally.

Example 11-37 dbschema on database ruby output

% dbschema -d ruby

DBSCHEMA Schema Utility INFORMIX-SQL Version 11.50.FC7

grant dba to "informix";

...

386

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch11.fm

create table "informix".schema_migrations

(

version varchar(255) not null

);

...

create table "informix".phonedirs

(

id serial not null ,

first_name varchar(255),

last_name varchar(255),

phone varchar(255),

created_at datetime year to fraction(5),

updated_at datetime year to fraction(5),

primary key (id)

);

...

create unique index "informix".unique_schema_migrations on "informix"

.schema_migrations (version) using btree ;

Starting the Rails web server

Example 11-38 shows how to start the Rails WEBrick server from the root

directory. The http port number is 3000.

Example 11-38 Starting the WEBrick server

C:\RailsProjects\sample>ruby script\server

=> Booting WEBrick

=> Rails 2.3.8 application starting on http://0.0.0.0:3000

=> Call with -d to detach

=> Ctrl-C to shutdown server

[2010-07-04 17:25:22] INFO WEBrick 1.3.1

[2010-07-04 17:25:22] INFO ruby 1.9.1 (2010-01-10) [i386-mingw32]

[2010-07-04 17:25:22] INFO WEBrick::HTTPServer#start: pid=292 port=3000

Checking the application from website

You can start the web application using the local web server address: http://localhost:3000/phonedirs

Figure 11-4 on page 388 shows the initial screen of our application brought up

with http://localhost:3000/phonedirs .

Chapter 11. Working with Ruby on Rails

387

7884ch11.fm

Draft Document for Review August 23, 2010 10:53 am

Figure 11-4 Initial screen of the application

We add one phone entry to our directory as shown in Figure 11-5.

Figure 11-5 Creating a new phone listing

Figure 11-6 phone entry has been added

Figure 11-6 Listing phonedir after the new entry

For more information regarding the development with Ruby and Ruby on Rails refer to the Ruby on Rails website at: http://rubyonrails.org/documentation

388

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch12.fm

12

Chapter 12.

Informix 4GL Web Services

In this chapter we introduce the new Web Services feature of IBM Informix 4GL.

This chapter provides an overview and configuring and building Web Services using Informix 4GL.

In this chapter, we discuss the following:

򐂰 Informix 4GL

򐂰 Web Services and Service Oriented Architecture (SOA)

򐂰 Environment setup when developing Web Services with I4GL

򐂰 Using I4GL to publish and consume a Web Service

򐂰 How to diagnose typical problems

© Copyright IBM Corp. 2010. All rights reserved.

389

7884ch12.fm

Draft Document for Review August 23, 2010 10:53 am

12.1 Basic concepts

In this section we provide an introduction of the products and technologies mention in this chapter.

12.1.1 IBM Informix 4GL

Informix 4GL is a programming language developed by IBM for interacting with

Informix database servers. It provides a rich environment for easy development of relational database applications. Informix 4GL provides all the component needed to develop character based applications using an Informix database, for example, project management, reports, debugger, and so on.

Informix 4GL supports compilers that can convert the I4GL applications to C language or to generate platform-independent pseudo code that can be executed using a I4GL runner.

For more information about Informix 4GL, refer to the 4GL Reference Manual at http://publib.boulder.ibm.com/infocenter/ifxhelp/v0/index.jsp?topic=/com.ibm.to

ols.doc/4gl.html.

12.1.2 Service Oriented Architecture and Web Services

Service Oriented Architecture or SOA is an architectural style that provides methods for systems development and integration, allowing applications developed with different technologies or programing languages to exchange data with one another.

This exchange of data is accomplished through the use of web services. Web services are saleable functions that can be accessed independent of platforms and programming languages. These functions take a set of inputs and return a set of outputs to accomplish a specific task.

Refer to the IBM Service Oriented Architecture portal for more information at http://www.ibm.com/software/solutions/soa/

12.1.3 Web Services development

A Web Service can be created with any web-aware technology. The most common language used for Web Services development is Java. however, Web

Services can be created with other language and technologies such as C or

.NET

390

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch12.fm

IBM provides several options for SOA development including:

򐂰

IBM SOA Sandbox

򐂰

IBM Rational® Application Developer

򐂰 eKit: Enterprise Architect for SOA

The development of a Web Service that requires the use of an IBM Informix database can be achieved using the following languages:

򐂰 Java, using any of the JDBC driver for an Informix database

򐂰 Any .NET language, using any of the Informix .NET providers available

򐂰 IBM Informix 4GL

12.1.4 Informix 4GL and Web Services

Starting form version 7.50 of IBM Informix, 4GL developers can manage and create Web Services using the 4GL language.

One of the key benefits of using Informix 4GL is the easy interaction with the

Informix database server. The use of SQL statements to access the database objects does not require any specific code as with other programming languages because SQL is embedded in the I4GL language.

The ability of create Web Services directly with I4GL allows the reuse of legacy code. Existing solutions developed with I4GL can be converted to Web solutions without much effort.

With Informix 4GL you can publish existing I4GL functions as web services as well as consume exiting Web Services from any I4GL application.

12.1.5 Components

Informix 4GL uses the Axis2 web service wrapper API to implement the interface required to communicate between the web server and the Informix 4GL libraries.

The components used for a typical I4GL Web Service solution are:

򐂰

Apache AXIS2C server

򐂰

Web Service

򐂰

Informix 4GL

򐂰

Informix Database Server

There are only two possible operations to perform with a Web Service, Create or

Consume:

򐂰 Create is the process of creating the Web Service and publish it to made it available to consumers.

Chapter 12. Informix 4GL Web Services

391

7884ch12.fm

Draft Document for Review August 23, 2010 10:53 am

The term used in Informix 4GL for this task is

Publish

.

򐂰

Consume is the process of using the Web Service, providing input parameters and retrieving the result as output parameters for the function.

The term used in Informix 4GL for this task is

Subscribe

.

Axis2 C functions are used for both operations as the wrapper code between the

Web Service and Informix 4GL.

12.2 Setup and configuration

In this section, we discuss the setup and configuration needed to develop Web

Services with Informix 4GL.

12.2.1 Prerequisites and supported platforms

The following is the requisites for using the Web Services with Informix 4GL.

򐂰

Apache Axis2/C version 1.5.1 (bundled with Informix 4GL)

򐂰

Apache Axis2/Java version 1.3.1 (bundled with Informix 4GL)

򐂰

IBM Informix database server version 10 or later

򐂰

Java Runtime Environment (JRE) 1.5 or later

򐂰

Perl 5.8.8

IBM Informix 4GL 7.50 is supported in the following platforms:

򐂰 HP-IA 11.23 and 11.31

򐂰 AIX 5.3 and 6.1

򐂰 Solaris 5.9 or 5.10

򐂰 Red Hat Enterprise Linux 4 and 5

򐂰 SUSE Linux Enterprise Server 10

Note: The Web Service feature was added to version 7.50.xC1 of Informix

4GL but it was only available for Linux platforms. Since version 7.50.xC3, all the above platforms are supported.

12.2.2 Environment

The utilities for using Web Service with Informix 4GL are installed in the same directory as Informix 4GL.

We do not cover how to install and set up Informix 4GL in this book, refer to the

Informix 4GL Installation Guide at

392

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch12.fm

http://publib.boulder.ibm.com/infocenter/idshelp/v115/topic/com.ibm.4gl_install

.doc/fgl_ing_010.htm

To use any of the I4GL Web Services tools, the variables listed in Table 12-1

must be set in the development environment. These variables define the location of those 4GL, Java, and Axis2 resources that you need for application development and deployment.

Table 12-1 Environment variables

Variable

AXIS2C_HOME

CLASSPATH

DBPATH

INFORMIXDIR

INFORMIXSERVER

INFORMIXSQLHOSTS

JAVA_HOME

Load Library Path for example: LD_LIBRARY_PATH

PATH

SOA_ERR_LOG

PROGRAM_DESIGN_DBS

Description

Specifies the Axis2 installation directory

Path to the required Java classes

Path for support files. Must be $INFORMIXDIR/etc

Directory where the 4GL files are installed

Default database server

Optional: Specifies the location of the sqlhosts file, which contains database connectivity information

Must be set to point to JRE 1.5 or later

Specifies which directories to search for client or shared IBM Informix general libraries

Specifies which directories to search for executable programs. Must include

$INFORMIXDIR/bin and $JAVA_HOME/bin

Optional: Specifies the directory where the log file

(w4glerr.log) is created, defaults to /tmp

Optional: Database used for storing Web service definitions, defaults to syspgm4gl

Example 12-1 shows a typical shell script to set up these variables.

Example 12-1 setup.ksh

AXIS2C_HOME=$INFORMIXDIR/AXIS2C

AXJDIR=$INFORMIXDIR/AXIS2C/AXIS2JARS

CLASSPATH=$AXJDIR/wsdl4j-1.6.2.jar:$AXJDIR/backport-util-concurrent-2.2.jar:$AX

JDIR/XmlSchema.jar:$AXJDIR/XmlSchema-1.3.1.jar:$AXJDIR/xbean-2.2.0.jar:$AXJDIR/ axiom-dom-1.3.1.jar:$AXJDIR/axiom-impl-1.3.1.jar:$AXJDIR/axiom-api-1.3.1.jar:$A

XJDIR/neethi-1.3.1.jar:$AXJDIR/axis.jar:$AXJDIR/commons-logging.jar:$AXJDIR/wsd l2ws.jar:$AXJDIR/commons-discovery.jar:$AXJDIR/jaxrpc.jar:$AXJDIR/saaj.jar:$AXJ

Chapter 12. Informix 4GL Web Services

393

7884ch12.fm

Draft Document for Review August 23, 2010 10:53 am

DIR/wsdl4j.jar:$AXJDIR/axis2-java2wsdl-1.3.1.jar:$AXJDIR/axis2-codegen-1.3.1.ja

r:$AXJDIR/axis2-kernel-1.3.1.jar

DBPATH=$INFORMIXDIR/etc

LD_LIBRARY_PATH=$INFORMIXDIR/AXIS2C/lib:$LD_LIBRARY_PATH export AXIS2C_HOME AXJDIR CLASSPATH DBPATH LD_LIBRARY_PATH

Some of the I4GL Web Services utilities such as w4gl keep design and configuration information in a database on the Informix database server. The default name for this database is syspgm4gl . The database is created the first time the w4gl tool is invoked. You can specify your own database name using the environment variable PROGRAM_DESIGN_DBS .

12.3 I4GL Web Service tools

This section describes the tools available within Informix 4GL to publish, deploy, package, and subscribe web services.

12.3.1 Web Service Compiler w4glc

The I4GL Web Service Compiler w4glc is a script based on Perl. w4glc performs all the required task to use Web Services within 4GL, from the creating process to the deploying and packaging.

The w4glc script is used by other I4GL utilities in a non-interactive way. Any error or failure generated during the execution is written to the

SOA_ERR_LOG log file.

The syntax for executing the w4glc tool is: w4glc {-option} <configuration-file>

The w4glc utility does not keep any information in the database, it only uses configuration files. The configuration file is a text file that specifies the details about the I4GL function to be created as a Web service. It contains information such as the location of the 4GL source files, input and output parameters, and database connectivity information.

See Table 12-2 for a description of all the parameters available with the

w4glc tool.

Table 12-2 w4glc parameter list

Option Description

check Reads the configuration file and performs basic checks, such as ensuring that the identified source files exist.

394

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch12.fm

Option

compile deploy force generate help keep package silent version

Description

Compile generated intermediate code

Deploy web service on the AXIS2C server

Overwrite existing service with identical name

Generate intermediate code for publish/subscribe

Provides basic help information

Retain intermediate source files for troubleshooting

Bundling a web service for production deployment

Generates code without on-screen display

Prints the version number

Example 12-2 shows the output for the generate option.

Example 12-2 w4glc generate output

informix@irk:/work$ w4glc -generate ./ws_zipcode_irk.4cf

Begin environment check ...

Environment check is completed.

Generating code. Please wait ...

Generating Wrapper code ....

The wrapper file is /tmp/w4gl_informix/zipcode_details_wrap.c

Generating WSDL ....

Generating headers ....

Generating skeletal code ....

Code generation completed.

Removing /tmp/w4gl_informix/zipcode_details_wrap.c ...

Removing /tmp/w4gl_informix/zipcode_details.wsdl ...

Removing /tmp/w4gl_informix/axis2_skel_ws_zipcode.h ...

Removing /tmp/w4gl_informix/axis2_svc_skel_ws_zipcode.c ...

Removing /tmp/w4gl_informix/services.xml ...

Removing /tmp/w4gl_informix/axis2_skel_ws_zipcode.c ...

informix@irk:/work$

For additional information about the I4GL Web Service Compiler refer to http://publib.boulder.ibm.com/infocenter/idshelp/v115/topic/com.ibm.4gl_admin.d

oc/fgl_wsg_500.htm

Chapter 12. Informix 4GL Web Services

395

7884ch12.fm

Draft Document for Review August 23, 2010 10:53 am

12.3.2 The w4gl utility

The character-based Interface w4gl utility is the main tool when using Web

Services with Informix 4GL. It allows you to perform the same task as the command line tool, w4glc , however, it also manages the data within the program design database, syspgm4gl .

The design database contains information about the Web Services environment including:

򐂰

Information for the host machine, such as name or temporary directories

򐂰

Location for the Axis2 web server

򐂰

Details for the Informix servers to which the Web Services connects

򐂰

Definition for Web Services, such as function names or parameters types

The Web Service definition specified through the tool is saved in database tables and hence is available for future reuse and modification thus reducing development effort.

The w4gl

tool uses the same I4GL character-based interface as other 4GL tools to accomplish the creation and consumption of Web Services.

Example 12-3 shows the main menu of the w4gl tool.

Example 12-3 w4gl main menu

+------------------------------------------------------------------------------+

|W4GL: Publish Subscribe Host name App server Exit |

|Create and Deploy web services from I4GL functions. |

|--------------------------------[ irkpgm4gl ]-------------------[Help: CTRL-W]|

| |

| |

| |

| |

| |

| |

| |

| |

| |

| |

| |

| |

| |

| |

| |

| |

| |

| |

+------------------------------------------------------------------------------+

396

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch12.fm

The main options of the w4gl are

򐂰

Publish: This option is used to create a new web service.

򐂰 Subscribe: This option is used to consume a web service.

򐂰

Host name: This option is used to managed the host information stored in the design database.

򐂰 Application server: This option is used to managed the Axis2 information stored in the design database.

For a details description of all the w4gl menu options, refer to the 4GL Web

Services Administration Guide at http://publib.boulder.ibm.com/infocenter/idshelp/v115/index.jsp?topic=/com.ibm.

4gl_admin.doc/fgl_wsg_006.htm

12.3.3 Web Service Description Language Parser (wsdl_parser)

Web Service Description Language (WSDL) is an XML-based language for describing network services. You can use WSDL to describe all the functions and parameters for a Web Service

When you subscribe a Web service, the wsdl_parser

tool parses the WSDL file to retrieve all the information that is required to define a Web service.

The syntax for invoking the wsdl_parser tool is: wsdl_parser sid wsdl_path ws_func i4gl_func target_dir target_file

Table 12-3 describes each parameter. All of the parameters are required for the

tool to work correctly.

Table 12-3 wsdl_parse parameters list

Parameter Description

sid An integer that uniquely identifies the subscriber. wsdl_path ws_func i4gl_func target_dir

Location of the file that describes the complete description of the

Web service, can be an online or a local copy of the WSDL file

Function to consume within the designated Web service.

Name for the wrapper function to be used by the I4GL program.

target_file

The path where files are stored while the Web service is being consumed.

The file name containing the generated subscriber client code

Chapter 12. Informix 4GL Web Services

397

7884ch12.fm

Draft Document for Review August 23, 2010 10:53 am

Note: The

SID

parameter is used only when the wsdl_parser

is invoked from the w4gl

tool. The parameter is ignored if wsdl_parse is used from the command line.

Example 12-4 shows the

wsdl_parser tool been used to generate the configuration file for a ws_zipcode Web Service. We pass the WSDL definition directly from a web server as wsdl_path parameter http://irk:9876/axis/services/ws_zipcode?wsdl

Example 12-4 wsdl_parser output

informix@irk:/work$ wsdl_parser 0 http://irk:9876/axis/services/ws_zipcode?wsdl

zipcode_details zipcode4gl `pwd`/publish zipcode4gl.c

informix@irk:/work$ ls publish local.wsdl zipcode4gl.c_zipcode4gl.4cf

informix@irk:/work$

12.3.4 I4GL Web Services process

Figure 12-1 illustrates how the I4GL Web Services tools work together.

Figure 12-1 I4GL Web Service tools

12.4 Developing a Web Service with I4GL

In this section we demonstrate the steps required to create a Web Service using

IBM Informix 4GL. Publish and subscribe are two operations to perform with a

Web Service:

򐂰 Publish

398

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch12.fm

The tasks required to create a new Web Service with the w4gl tool are: a. Add the Host name and an Axis2 server information.

b. Add the Web service definition details.

c. Generate the Web service configuration file for publishing.

d. Deploy a Web service registering the service in the Axis2 web server.

e. Package a Web service as a single file (tar file) ready for the production server.

򐂰 Subscribe

The tasks needed to consume a Web Service are with the w4gl tool are: a. Add details for the Web service to consume.

b. Compile the Web Services wrapper code which generates the configuration file for subscription.

We publish a simple

I4GL

function as a Web Service and show the function can be used from other languages such as Java.

12.4.1 Example I4GL function

We use a basic

I4GL

function state_name()

for the Web Service. This function connects to the database server and retrieves the name for a specific state code.

Example 12-5 shows the 4GL

code state_name()

saved in the state_name.4gl

file. This function queries the state

table from the stores_demo

database. The state_name()

function takes one input parameter state code of type CHAR(2) and returns the state name that has CHAR(15) data type.

Example 12-5 state_name.4gl

FUNCTION state_name(code)

DEFINE state_rec RECORD

code CHAR(2),

sname CHAR(15)

END RECORD,

code CHAR(2),

sel_stmt CHAR(100);

LET sel_stmt= "SELECT code, sname FROM state WHERE code = ?";

PREPARE st_id FROM sel_stmt;

DECLARE cur_id CURSOR FOR st_id;

OPEN cur_id USING code;

FETCH cur_id INTO state_rec.*;

Chapter 12. Informix 4GL Web Services

399

7884ch12.fm

Draft Document for Review August 23, 2010 10:53 am

CLOSE cur_id;

FREE cur_id;

FREE st_id;

RETURN state_rec.sname

END FUNCTION

To make sure the 4GL code is correct, we compile the function with the I4GL

compiler, c4gl as shown in Example 12-6.

Example 12-6 Compile 4GL function

informix@irk:/work$ c4gl -c state_name.4gl informix@irk:/work$

12.4.2 Host and application details

Before adding any of the details for the Web Service we must provide details about the machine where the Web Service will run and the Axis2 Server used.

This tasks are done using the Host name and Application server menus from the w4gl tool.

Example 12-7 shows the HOST INFORMATION form with a host name

irk and a temporary directory /tmp/w4gl_informix .

Example 12-7 Host name menu

+------------------------------------------------------------------------------+

|HOST NAME: Query Next Previous Add Modify Remove Exit |

|See the existing host name details. |

|[1 of 1]------------------------[ irkpgm4gl ]-------------------[Help: CTRL-W]|

| |

| HOST INFORMATION |

| |

| Machine ID [ 1] |

| Host Name [irk ] |

| Temporary Directory [/tmp/w4gl_informix ] |

| [ ] |

| |

| |

| |

| |

| |

| |

| |

| |

| |

| |

| |

400

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch12.fm

+------------------------------------------------------------------------------+

There are three fields for the host information:

򐂰 Machine ID: This is an automatic identifier number.

򐂰

Host Name: This is the machine name where the Axis2 server is installed.

򐂰 Temporary Directory: Directory used by the w4glc tool for creating the temporary files.

After defining the host information we add the information for the Axis2 application server using the App server menu.

Example 12-8 shows the APP SERVER form.

Example 12-8 Application menu

+------------------------------------------------------------------------------+

|APP SERVER: Query Next Previous Add Modify Remove Exit |

|Go to the next app server |

|[1 of 1]------------------------[ irkpgm4gl ]-------------------[Help: CTRL-W]|

| |

| APP SERVER INFORMATION |

| Server ID [ 1] |

| Server Name [axis ] |

| Host Name [irk ] |

| Port Number [ 9876] |

| ENVIRONMENT VARIABLES |

| INFORMIXDIR [/usr3/4gl750 ] |

| INFORMIXSQLHOSTS [/usr3/sqlhosts ] |

| CLIENT_LOCALE [en_us.utf8 ] |

| DBDATE [Y4MD- ] |

| Notes [ ] |

| [ ] |

| [ ] |

| [ ] |

| |

| |

| |

+------------------------------------------------------------------------------+

An application server is identified by the following fields:

򐂰

Server ID: This is an automatic identifier number.

򐂰

Server Name: This is the name of the Axis2 server.

򐂰

Host Name: This is the machine name where the Axis2 server runs.

򐂰

Port Number: This is the port used for incoming connections to the web serve.

The App serv option is also used to stored specific environment information for the application server. This information is required because the Axis2 server

Chapter 12. Informix 4GL Web Services

401

7884ch12.fm

Draft Document for Review August 23, 2010 10:53 am binary loads the I4GL libraries that might need additional resource files located in the $INFORMIXDIR directory.

12.4.3 Definition of the Web Service

In this section we demonstrate how to define a Web Service from the w4gl tool.

The task to perform are:

򐂰

Add the IBM Informix database the Web Service would use.

򐂰 Add the definition for the Web Service such as the name of the service or the name of the 4GL function.

򐂰

Add specific details for the Web Service such as input and output variables.

򐂰 Add the location of the 4GL source code file.

Add Informix database details

This task is done using the Database menu from the w4gl tool.

Example 12-9 shows the DATABASE INFORMATION form with the details of the

database used in our example.

Example 12-9 Database option

+------------------------------------------------------------------------------+

|DATABASE: Query Next Previous Add Modify Remove Exit |

|Go to the previous database record. |

|[1 of 1]------------------------[ irkpgm4gl ]-------------------[Help: CTRL-W]|

| |

| DATABASE INFORMATION |

| |

| Database ID [ 1] |

| Database Name [stores7 ] |

| Database Server [irk1150 ] |

| IDS Version [11.50 ] |

| DB_LOCALE [en_US.819 ] |

| Notes [ ] |

| [ ] |

| [ ] |

| [ ] |

| |

| |

| |

| |

| |

| |

+------------------------------------------------------------------------------+

The fields used in this menu option are:

402

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch12.fm

򐂰 Database ID: This is an automatic number that identifies a database definition.

򐂰

Database name: The database name to which the Web Server connects.

򐂰 IDS Version: This is Informix database server version number.

򐂰

DB_LOCALE: This is the locale of the database. The default DB_LOCALE is en_US.819.

Add details about the Web service

The definition of the Web Service is done using Add option in the Web Service menu.

Example 12-10 Shows this option.

Example 12-10 Add of Web Service menu

+------------------------------------------------------------------------------+

|WEB SERVICE: Query Next Previous Add Modify Remove Install ... |

|Specify a new service record. |

|--------------------------------[ irkpgm4gl ]-------------------[Help: CTRL-W]|

| |

| |

| |

The first step is to add the Web Service name and the function name using the

Detail menu option. Example 12-11 shows this input form with the details of our

Web Service.

Example 12-11 Web Service details

+------------------------------------------------------------------------------+

|ADD: Detail Variable File Exit |

|Specify the web service parameters. |

|--------------------------------[ irkpgm4gl ]-------------------[Help: CTRL-W]|

| |

| Webservice ID [ 4] |

| Webservice Name [ws_statename ] |

| Function Name [state_name ] |

| Notes [Returns the state name for a given code ] |

| [ ] |

| [ ] |

| [ ] |

| |

| |

| |

| |

| |

| |

| |

| |

Chapter 12. Informix 4GL Web Services

403

7884ch12.fm

Draft Document for Review August 23, 2010 10:53 am

| |

| |

+------------------------------------------------------------------------------+

The input details on this form describes a Web Service:

򐂰 Web Service ID: This is an automatic generated identifier for the Web

Service.

򐂰

Web service Name: This is the name of the Web Service.

򐂰 Function Name: This is the name of the 4gl function.

Input and output variables

The next step on the definition of a Web Service is to add the input and output variables used by the Web Service. This is done using the Variable menu option.

Example 12-12 shows this menu option. Our function takes an CHAR(2) input

parameter and returns a CHAR(15) value.

Example 12-12 Web Service Variable option

+------------------------------------------------------------------------------+

|VARIABLE: Input Output Exit |

|Exit the Variable menu. |

|--------------------------------[ irkpgm4gl ]-------------------[Help: CTRL-W]|

| |

| [ 1] Input parameter - Variable name Data type |

| |

| [ 1][code ][CHAR(2) ] |

| [ ][ ][ ] |

| [ ][ ][ ] |

| [ ][ ][ ] |

| [ ][ ][ ] |

| |

| [ 1] Output parameter - Variable name Data type |

| |

| [ 1][sname ][CHAR(15) ] |

| [ ][ ][ ] |

| [ ][ ][ ] |

| [ ][ ][ ] |

| [ ][ ][ ] |

| |

| |

+------------------------------------------------------------------------------+

Source file information

This is the last step required to define a Web Service. We stored the location of the I4GL source file that contains our function using the File menu option.

404

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch12.fm

Example 12-13 shows the fields used by the File option.

Example 12-13 Web Service File option

+------------------------------------------------------------------------------+

|ADD: Detail Variable File Exit |

|Exit the web services Add menu. |

|--------------------------------[ irkpgm4gl ]-------------------[Help: CTRL-W]|

| |

| Service Name [ws_state_name ] |

| Function Name [state_name ] |

| |

| File Number [ 1] |

| Directory [/work ] |

| File Name [state_name.4gl ] |

| |

| File Number [ ] |

| Directory [ ] |

| File Name [ ] |

| |

| File Number [ ] |

| Directory [ ] |

| File Name [ ] |

| |

| |

| |

+------------------------------------------------------------------------------+

A I4GL function may require more than one I4Gl file, you must supply all the required file names and their directories. We supply the 4gl file state_name.4gl containing the state_name() function.

12.4.4 Generate the configuration file

With the details of the Web Service stored in the design database we can proceed to generate the configuration file (.4cf) for a Publish operation. The

Generate option is inside the Install menu option.

Example 12-14 shows the Generate form. You must fill out every field in the form.

If you have stored the definition for all those items in the design database, you can retrieve them using the Ctrl+B key shortcut.

Example 12-14 Generate form

+------------------------------------------------------------------------------+

|INSTALL: Generate Deploy Package Exit |

|Generate the configuration file for a web service. |

|[1 of 1]------------------------[ irkpgm4gl ]-------------------[Help: CTRL-W]|

| |

| +-----------------------------------------------------+ |

Chapter 12. Informix 4GL Web Services

405

7884ch12.fm

Draft Document for Review August 23, 2010 10:53 am

| |DATABASES: Query Previous query Exit | |

| Service ID [ 4] M|Make a new selection | |

| |-----------------------------------------------------| |

| Service Name [ws_s| DATABASE INFORMATION | |

| Host Name [irk | | |

| Temp Directory [/tmp|ID Database Name | |

| [ |[ 1] [stores7 ]| |

| App-Server Name [axis|[ ] [ ]| |

| Port Number [ 98|[ ] [ ]| |

| Database Name [ |[ ] [ ]| |

| Database Server [ |[ ] [ ]| |

| |[ ] [ ]| |

| | | |

| |Arrow key - Press Esc to Accept or press Ctrl+C to Ca| |

| +-----------------------------------------------------+ |

| |

+------------------------------------------------------------------------------+

After all the information is entered, use the Generate option to create the

configuration file. Example 12-15 shows the output of the Generate task.

Example 12-15 Generate option

+------------------------------------------------------------------------------+

|INSTALL: Generate Deploy Package Exit |

|Generate the configuration file for a web service. |

|[1 of 1]------------------------[ irkpgm4gl ]-------------------[Help: CTRL-W]|

| |

| GENERATE CONFIGURATION |

| |

| Service ID [ 4] Machine ID [ 1] Server ID [ 1] Database ID [ 1] |

| |

| Service Name [ws_state_name ] |

| Host Name [irk ] |

| Temp Directory [/tmp/w4gl_informix ] |

| [ ] |

| App-Server Name [axis ] |

| Port Number [ 9876] |

| Database Name [stores7 ] |

| Database Server [irk1150 ] |

| |

| |

| |

| |

| Generated configuration file ws_state_name_irk.4cf |

+------------------------------------------------------------------------------+

The Generate operation creates the configuration file required for publishing a

Web Service. The name of the file is constructed using the Web Service name, the Host name, and .4cf extension. In our example the name of the file is ws_state_name_irk.4cf

406

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch12.fm

Example 12-16 shows the configuration file for the

ws_state_name Web Service.

Example 12-16 ws_state_name_irk.4cf file

[SERVICE]

TYPE = publisher

INFORMIXDIR = /usr3/4gl750uc3

DATABASE = stores7

CLIENT_LOCALE = en_us.utf8

DB_LOCALE = en_US.819

INFORMIXSERVER = irk1150

HOSTNAME = irk

PORTNO = 9876

I4GLVERSION = 7.50.xC3

WSHOME = /usr3/4gl750uc3/AXIS2C

WSVERSION = axis

TMPDIR = /tmp/w4gl_informix

SERVICENAME = ws_state_name

[FUNCTION]

NAME = state_name

[INPUT]

[VARIABLE] NAME = code TYPE = CHAR(2) [END-VARIABLE]

[END-INPUT]

[OUTPUT]

[VARIABLE] NAME = sname TYPE = CHAR(15) [END-VARIABLE]

[END-OUTPUT]

[END-FUNCTION]

[DIRECTORY]

NAME = /work

FILE = state_name.4gl,

[END-DIRECTORY]

[END-SERVICE]

A configuration file (4cf) can be used with the Web 4GL compiler (w4glc) tool to perform tasks, such as generate and compile, directly from the command line.

Example 12-17 shows how to perform all the steps that the w4gl

deploy options does using the w4glc utility.

Example 12-17 w4glc use

informix@irk:/work$ w4glc -generate -compile -deploy ws_state_name_irk.4cf

Begin environment check ...

Environment check is completed.

Generating code. Please wait ...

Generating Wrapper code ....

The wrapper file is /tmp/w4gl_informix/state_name_wrap.c

Generating WSDL ....

Generating headers ....

Generating skeletal code ....

Chapter 12. Informix 4GL Web Services

407

7884ch12.fm

Draft Document for Review August 23, 2010 10:53 am

Code generation completed.

Generating shared object for service ws_state_name ....

Compiling code. Please wait...

Executing: c4gl --shared -o /tmp/w4gl_informix/libws_state_name.so

-I/usr3/4gl750/AXIS2C/include/axis2-1.5.0 -L/usr3/4gl750/AXIS2C/lib

-laxis2_engine -laxutil -laxis2_axiom /tmp/w4gl_informix/state_name_wrap.c

/tmp/w4gl_informix/axis2_skel_ws_state_name.c

/tmp/w4gl_informix/axis2_svc_skel_ws_state_name.c /work/state_name.4gl

/usr3/4gl750/lib/tools/w4glutil.a /usr3/4gl750/lib/tools/lib4gl.a

Compilation done.

Deploying service ws_state_name ...

Deploying the service. Please wait ...

Copying /tmp/w4gl_informix/libws_state_name.so ...

Copying /tmp/w4gl_informix/services.xml ...

Copying /tmp/w4gl_informix/state_name.wsdl ...

Service name: ws_state_name

The wrapper file is /tmp/w4gl_informix/state_name_wrap.c

Generating WSDL ....

Generating headers ....

Generating skeletal code ....

Code generation completed.

Generating shared object for service ws_state_name ....

Compiling code. Please wait...

Executing: c4gl --shared -o /tmp/w4gl_informix/libws_state_name.so

-I/usr3/4gl750/AXIS2C/include/axis2-1.5.0 -L/usr3/4gl750/AXIS2C/lib

-laxis2_engine -laxutil -laxis2_axiom /tmp/w4gl_informix/state_name_wrap.c

/tmp/w4gl_informix/axis2_skel_ws_state_name.c

/tmp/w4gl_informix/axis2_svc_skel_ws_state_name.c /work/state_name.4gl

/usr3/4gl750/lib/tools/w4glutil.a /usr3/4gl750/lib/tools/lib4gl.a

Compilation done.

Deploying service ws_state_name ...

Deploying the service. Please wait ...

Copying /tmp/w4gl_informix/libws_state_name.so ...

Copying /tmp/w4gl_informix/services.xml ...

Copying /tmp/w4gl_informix/state_name.wsdl ...

Service name: ws_state_name

Deployed at : /usr3/4gl750/AXIS2C/services/ws_state_name

Removing /tmp/w4gl_informix/state_name_wrap.c ...

Removing /tmp/w4gl_informix/state_name.wsdl ...

Removing /tmp/w4gl_informix/axis2_skel_ws_state_name.h ...

Removing /tmp/w4gl_informix/axis2_svc_skel_ws_state_name.c ...

Removing /tmp/w4gl_informix/services.xml ...

Removing /tmp/w4gl_informix/axis2_skel_ws_state_name.c ...

Removing /tmp/w4gl_informix/libws_state_name.so ...

The output of the command line tool shows all the steps done while creating and compiling the wrapper function. When errors appear during the deployment

408

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch12.fm

process, running each individual step with the w4glc may help to diagnose the reason for the problem.

12.4.5 Deployment of the Web Service

This process generates the auxiliary code required to link the Axis2 application server with the IBM Informix 4GL function. During the deployment, the C code for the Web Service is created and compiled automatically using the 4Gl libraries.

The result of this process is a shared library ready to be use in the application server.

This process also creates a Web Services Description Language (WSDL) file for the Web Service and copy this file, together with the Web Service shared library, into the application server directory.

The Deploy option is part of the Install menu. Example 12-18 shows the

deployment of the ws_state_name Web Service.

Example 12-18 Deploy form

+------------------------------------------------------------------------------+

|INSTALL: Generate Deploy Package Exit |

|Deploy the web service. |

|[1 of 1]------------------------[ irkpgm4gl ]-------------------[Help: CTRL-W]|

| |

| CONFIGURATION TO DEPLOY |

| |

| File Name [ws_state_name_irk.4cf ] |

| [ ] |

| [ ] |

| |

| |

| |

| |

| |

| |

| |

| |

| |

| |

| |

| Deployed ws_state_name. |

+------------------------------------------------------------------------------+

After a successful deployment, the Web Service would be ready to be consume by any application. The files are automatically copied into the Axis2 services directory.

Chapter 12. Informix 4GL Web Services

409

7884ch12.fm

Draft Document for Review August 23, 2010 10:53 am

Example 12-19 on page 410 shows the Web Service files on the application

server.

Example 12-19 Application Server services directory

informix@irk:/work$ ls $INFORMIXDIR/AX*/services/ws_state_name

libws_state_name.so services.xml state_name.wsdl

informix@irk:/work$

12.4.6 Packaging of the Web Service

Packaging a Web Service is the process of creating a compress file with all the components required by the Web Service. The compressed file, in tar format, can be used on other Axis2 servers.

Example 12-20 shows the Package menu option.

Example 12-20 Package option.

+------------------------------------------------------------------------------+

|INSTALL: Generate Deploy Package Exit |

|Package the web service. |

|[1 of 1]------------------------[ irkpgm4gl ]-------------------[Help: CTRL-W]|

| |

| SERVICE PACKAGING |

| |

| File Name [ws_state_name_irk.4cf ] |

| [ ] |

| [ ] |

| |

| |

| |

| |

| |

| |

| |

| |

| |

| |

| |

| Packaging successful. Check $TMPDIR directory (in config file) for .tar file |

+------------------------------------------------------------------------------+

The compressed file is left in the $TMPDIR directory. Example 12-21 shows the

contents of the packaged file for the ws_state_name

Web Service.

Example 12-21 Packaged tar file

informix@irk:/work$ tar tvf /tmp/w4gl_informix/ws_state_name.tar drwxr-xr-x informix/informix 2010-07-05 21:01 ws_state_name/

410

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch12.fm

-rw-r--r-- informix/informix 2010-07-05 21:01 ws_state_name/services.xml

-rw-r--r-- informix/informix 2010-07-05 21:01 ws_state_name/state_name.wsdl

-rwxr-xr-x informix/informix 2010-07-05 21:01 ws_state_name/libws_state_name.so

informix@irk:/work$

12.4.7 Starting the Axis2 application server

An Axis2 application server is included with the Informix 4GL package. It is located in the AXIS2C directory under $INFORMIXDIR.

The Axis2 application server must be started to consume a Web Service. It is not required during the development or deploy process.

Example 12-22 demonstrates how to start the Axis2 application server.

Example 12-22 Starting Axis2

informix@irk:/usr3/4gl750/AXIS2C/bin$ ./axis2_http_server -p 9876

Started Simple Axis2 HTTP Server ...

For more information about the Axis2 application server, refer to the Axis2/C

Manual at http://ws.apache.org/axis2/c/docs/axis2c_manual.html

12.4.8 Consuming the I4GL Web Service

The main feature of a Web Service is that it can be used by any application in any platform. A Web Service is not tied to the technology or programming language used to develop the service. Any application that supports the Simple Object

Access Protocol or SOAP, can make use of the functions implemented inside a

Web Service. SOAP is a simple XML-based protocol used to exchange information over a HTTP link.

In this section we demonstrate how to use the ws_state_nam e Web Service using basic Java application.

Getting a list of available Web Services

You can get a list of available Web Services in the Axis2 application server by opening a web browser and connecting to the Axis2 server.

http://hostname:port/axis/services

Figure 12-2 on page 412 shows the Web Services available in our example.

Chapter 12. Informix 4GL Web Services

411

7884ch12.fm

Draft Document for Review August 23, 2010 10:53 am

Figure 12-2 Axis2 Web Services

You can use the ?wsdl keyword to retrieve the WSDL file as follows: http://hostname:port/axis/services/ws_state_name?wsdl

Figure 12-3 shows the WSDL information for the ws_state_name service.

Figure 12-3 WSDL information for the ws_state_name service

412

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch12.fm

Java application

The main advantages of Web Services is that the application that uses the services does not need to know anything about how the service is implemented.

The information needed for consuming a Web Service is defined in the WSDL file, name of the operations it supports and parameters it requires.

Example 12-23 demonstrates how the I4GL Web Service

ws_state_name

can be used from a simple Java application.

Example 12-23 state_name.java

informix@irk:/work$ cat state_name.java

import org.apache.axis.client.Call;

import org.apache.axis.client.Service;

import javax.xml.namespace.QName;

public class state_name {

public static void main(String [] args) {

try {

String endpoint = "http://irk:9876/axis/services/ws_state_name";

String qname = "http://www.ibm.com/ws_state_name";

Service service = new Service();

Call call = (Call) service.createCall();

call.setTargetEndpointAddress( new java.net.URL(endpoint) );

call.setOperationName(new QName(qname, "state_name"));

String ret = (String) call.invoke( new Object[] { args[0] } );

System.out.println("Sent 'CA', got '" + ret + "'");

} catch (Exception e) {

System.err.println(e.toString());

}

}

} informix@irk:/work$ javac state_name.java

informix@irk:/work$ java state_name CA

Sent 'CA', got 'California '

informix@irk:/work$ java state_name AR

Sent 'CA', got 'Arkansas ' informix@irk:/work$

Chapter 12. Informix 4GL Web Services

413

7884ch12.fm

Draft Document for Review August 23, 2010 10:53 am

12.5 Consuming a Web Service with I4GL

In this section we demonstrate all the steps required to consume a Web Service using IBM Informix 4GL.

12.5.1 Web service to consume

You can use the w4gl tool to insert details about the specific Web Service you want to consume. The menu option Subscribe allows you to manage definitions for Web Services in the design database.

Example 12-24 shows the Subscribe form with the details referring to the

ws_state_name Web Service.

Example 12-24 Subscribe form

+------------------------------------------------------------------------------+

|SUBSCRIBE: Query Next Previous Add Modify Remove Compile Exit |

|Specify a new web service definition. |

|--------------------------------[ irkpgm4gl ]-------------------[Help: CTRL-W]|

| |

| Subscription ID [ 3] |

| WSDL Path [http://irk:9876/axis/services/ws_state_name?wsdl ] |

| [ ] |

| Webservice Function[state_name ] |

| I4GL Function [statename ] |

| Target Directory [/work/publish ] |

| Target File Name [statename ] |

| Notes [Wrapper for ws_state_name Web Service ] |

| [ ] |

| [ ] |

| |

| |

| |

| |

| |

| |

| |

+------------------------------------------------------------------------------+

The details for this form are:

򐂰

Subscription ID: This is an automatic generated identifier of the Web Service.

򐂰 WSDL Path: This is the complete path of the WSDL file for the service. This can be a local file or a URL.

򐂰

Web service Function: This is the function name provided by the Web

Service.

414

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch12.fm

򐂰 I4GL Function: This is the name of the wrapper C function. This is the function our I4GL would use to invoke the Web Service operation.

򐂰

Target Directory: This is the directory where the wrapper and configuration files are created.

򐂰 Target File Name: This is the name of the C source file with the I4GL function.

The configuration file for a publish operation is automatically generated by the w4gl tool, but it can also be created using the wsdl_parser as shown in

Example 12-25.

Example 12-25 Generating configuration file

informix@irk:/work$ wsdl_parser 0

http://irk:9876/axis/services/ws_state_name?wsdl state_name wsstatecode

`pwd`/publish statecode.c

informix@irk:/work$ ls publish local.wsdl statecode.c_wsstatecode.4cf

informix@irk:/work$ cat publish/statecode.c_wsstatecode.4cf

[SERVICE]

TYPE = subscriber

I4GLVERSION = 7.50.xC4

WSHOME = 0

TARGET_DIR = /work/publish

I4GL_FUNCTION = wsstatecode

TARGET_FILE = statecode.c

[WSDL_INFO]

WSDL_PATH = /work/publish/local.wsdl

WSDL_NAME_SPACE = http://www.ibm.com/state_name

[FUNCTION]

SERVICENAME = ws_state_name

NAME = state_name

[INPUT]

[VARIABLE] NAME = code TYPE = char(2) [END-VARIABLE]

[END-INPUT]

[OUTPUT]

[VARIABLE] NAME = sname TYPE = char(15) [END-VARIABLE]

[END-OUTPUT]

[END-FUNCTION]

[END-WSDL_INFO]

[END-SERVICE]

12.5.2 Compiling the wrapper code

The next step to consume a Web Service is to generate and compile the wrapper code. This is achieved using the Compile menu option of the w4gl tool.

Chapter 12. Informix 4GL Web Services

415

7884ch12.fm

Draft Document for Review August 23, 2010 10:53 am

Example 12-26 shows the w4gl screen after compiling the wrapper code for the

ws_state_name Web Service.

Example 12-26 Compile option.

+------------------------------------------------------------------------------+

|SUBSCRIBE: Query Next Previous Add Modify Remove Compile Exit |

|Compile the subscriber client code. |

|--------------------------------[ irkpgm4gl ]-------------------[Help: CTRL-W]|

| |

| Subscription ID [ 3] |

| WSDL Path [http://irk:9876/axis/services/ws_state_name?wsdl ] |

| [ ] |

| Webservice Function[state_name ] |

| I4GL Function [statename ] |

| Target Directory [/work/publish ] |

| Target File Name [statename ] |

| Notes [Wrapper for ws_state_name Web Service ] |

| +---------------------------------------------------------------------------+|

| | ||

| |Subscriber code has been compiled successfully. ||

| +---------------------------------------------------------------------------+|

| |

| |

| |

| |

| |

+------------------------------------------------------------------------------+

After this process is complete, the C files for the wrapper function, including the object file containing the function code, are left in the Target Directory specified in the Web Service definition.

Example 12-27 shows the files for the

ws_state_name Web Service. These files can be used from an Informix 4GL program to consume the Web Service.

Example 12-27 Web Service files

informix@irk:/work/publish$ ls axis2_stub_ws_state_name_statename.h statename.c_statename.4cf

statename.c statename.o informix@irk:/work/publish$

12.5.3 Using the Web Service from an I4GL application

To consume a Web Service from I4GL we have to link the object file for the wrapper function in our 4GL code, or use the C source file generated during the subscribe compile process.

416

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch12.fm

Example 12-28 shows a simple 4GL program which uses the wrapper function

for the ws_state_name Web Service. The wrapper function can be called like any other C function in I4GL.

Example 12-28 i4gl subscriber code. wsstate.4gl

informix@irk:/work/publish$ cat wsstate.4gl

MAIN

DEFINE sname CHAR(15)

WHENEVER ERROR STOP

CALL statename("CA") RETURNING sname

DISPLAY "State name: ",sname

END MAIN informix@irk:/work/publish$ c4gl wsstate.4gl statename.c -o wsstate

$INFORMIXDIR/lib/tools/w4glutil.a -I$AXIS2C_HOME/include/axis2-1.5.0

-L$AXIS2C_HOME/lib -laxis2_engine informix@irk:/work/publish$ ./wsstate

State name: California

informix@irk:/work/publish$

For more information about Informix 4GL, refer to the 4GL Reference Manual at http://publib.boulder.ibm.com/infocenter/ifxhelp/v0/index.jsp?topic=/com.ibm.to

ols.doc/4gl.html.

12.6 Troubleshooting

In this section we discuss typical problems seen when developing a Web Service using the Informix 4GL Web Services tools and how to obtain diagnostic information through the use of tracing or log files.

12.6.1 Typical problems

Here we discuss a few frequently seen problems.

Connection

The connection errors normally appears when there is something wrong in the configuration details for the development environment or the Web Service.

Any Web Service developed in I4GL requires the use of the Informix 4GL communication libraries for the database connection. I4GL tools like w4gl

keep the details about the environment in the Design database, therefore, it is critical

Chapter 12. Informix 4GL Web Services

417

7884ch12.fm

Draft Document for Review August 23, 2010 10:53 am that the communication with the IBM Informix database was configure correctly before starting any project.

Environment variables such as INFORMIXDIR and INFORMIXSQLHOSTS must contain valid details for the Informix database server to use during development.

Other things to check if there are problems related to connection include:

򐂰

Informix database server details. Informix Web Services tools and Web

Services running on the Axis2 server uses the database information defined in the Design database.

򐂰 Connection information about the Axis2 server such as host name or port number is stored as part of an Application Server definition. Check if these values are valid.

򐂰

Consuming Web Services with an 4GL application requires a TCP connection from the I4GL program to the application server running the Web Service.

Make sure that the location of the Web Service is correct and the Application

Server can be reached from the I4GL process.

Compilation errors

A common reason for having this type of errors is due to an incorrect setup or incorrect use of the Informix 4GL Web Services utilities.

Environment variables such as PATH and LD_LIBRARY_PATH (or the suitable variable for the platform) may cause compilation and runtime errors while developing a Web Service with Informix 4GL. When a compile problem appears while using one of the I4GL Web Service tools, the information about the error is written into the W4GL log file. The default name and location of this file is

/tmp/w4glerr.log

.

Example 12-29 shows an error message generated by the

w4gl tool during the

Deploy process.

Example 12-29 w4gl error.

The file "state_name.err" has been written.

-CDCAK0012: The web service not deployed. Check error log '/tmp/w4glerr.log'

The Deploy menu option performs several operations automatically including the generation of the wrapper code, compiling, and moving the Web Services files into the Axis2 server. To know which specific task is failing, use the Web compiler tool (w4glc) to manually perform each individual task.

By default, the w4glc script deletes the temporary files used to perform a task, so use the -keep flag to avoid files deletion.

418

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch12.fm

Example 12-30 shows how to run the Generate process using the w4glc tool.

Example 12-30 w4glc generate keeping the files

informix@irk:/work$ w4glc -generate -keep ws_state_name_irk.4cf

Begin environment check ...

Environment check is completed.

Generating code. Please wait ...

Generating Wrapper code ....

The wrapper file is /tmp/w4gl_informix/state_name_wrap.c

Generating WSDL ....

Generating headers ....

Generating skeletal code ....

Code generation completed.

With the wrapper files in the temporary directory, you can execute the Compile process from the command line using w4glc and examine the output for any

errors. Example 12-31 shows the output of the Compile process when an

compilation error occurs.

Example 12-31 Compilation output

informix@irk:/work$ w4glc -compile -keep ws_state_name_irk.4cf

Begin environment check ...

Environment check is completed.

Generating shared object for service ws_state_name ...

Compiling code. Please wait...

Executing: c4gl -keep --shared -o /tmp/w4gl_informix/libws_state_name.so

-I/usr3/4gl750/AXIS2C/include/axis2-1.5.0 -L/usr3/4gl750/AXIS2C/lib

-laxis2_engine -laxutil -laxis2_axiom...

The compilation was not successful. Errors found: 1.

The file "state_name.err" has been written.

Error executing: c4gl -keep --shared -o /tmp/w4gl_informix/libws_state_name.so

-I/usr3/4gl750/AXIS2C/include/axis2-1.5.0 ...

/usr3/4gl750/lib/tools/w4glutil.a /usr3/4gl750/lib/tools/lib4gl.a at

/usr3/4gl750/lib/globals.pm line 583.

Error executing: c4gl -keep --shared -o /tmp/w4gl_informix/libws_state_name.so

-I/usr3/4gl750/AXIS2C/include/axis2-1.5.0 -L/usr3/4gl750/AXIS2C/lib

-laxis2_engine -laxutil ...

informix@irk:/work$

Similar to any I4GL program, if the error was inside the Informix 4GL code, a .err

file is created containing the error message. Example 12-32 shows the content of

the state_name.err file.

Example 12-32 state_name.err

informix@irk:/work$ cat state_name.err

FUNCTION state_name(code)

Chapter 12. Informix 4GL Web Services

419

7884ch12.fm

Draft Document for Review August 23, 2010 10:53 am

DEFINE state_rec RECORD

code CHAR(2),

sname CHAR(15)

END RECORD,

code CHAR(2),

sel_stmt CHAR(100);

LET sel_stmt= "SELECT code, sname FROM state WHERE code = ?";

PEPARE st_id FROM sel_stmt;

|________^

|

| A grammatical error has been found on line 11, character 10.

| The construct is not understandable in its context.

| See error number -4373.

DECLARE cur_id CURSOR FOR st_id;

OPEN cur_id USING code;

FETCH cur_id INTO state_rec.*;

...

Keeping the wrapper C files in the temporary directory might be useful when the compilation error appears inside the Axis2 functions.

Example 12-33 shows the temporary files created with the Generate option for

the ws_state_name Web Service.

Example 12-33 temporary files

informix@irk:/work$ ls /tmp/w4gl_informix/

axis2_skel_ws_state_name.c services.xml tmpXMLReqFile

axis2_skel_ws_state_name.h state_name_wrap.c ws_state_name.tar

axis2_svc_skel_ws_state_name.c state_name.wsdl

informix@irk:/work$

While compiling any Web Service, during creation or consume, make sure all the required libraries and include files are correctly passed to the compiler. These requirement may vary from platform to platform, so, always check the release notes.

The release and documentation files for Informix 4GL are located in the release/en_us/0333 directory inside INFORMIXDIR. These files contain additional information relevant to the version of I4GL installed such as known issues or compiler requirements which may help diagnosing the problem.

420

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch12.fm

Consuming the Web Service

This types of errors may be caused by an invalid Web Service definition, items such as function name or parameters type are defined in the configuration file and used to create the WSDL file the Application Server would use to define the

Web Service.

You can retrieve the WSDL information for a Web Service using the location of the service and the

?wsdl

suffix from any Web browser.

Figure 12-4 shows the WSDL information for the ws_state_name Web Service.

Figure 12-4 WSDL for ws_state_name service.

Make sure the operations, parameters, and data types are correct for the I4GL code the function uses.

Testing a Web Service

Informix I4GL does not provide any specific tool for testing Web Services. While you can create a simple 4GL code to consume the Web Service, depending on the complexity of the Web Service it could be useful to perform a more complete testing.

You can use open source tools such as soapUI to test your Web Service before publish it on the production environment. For more information about soapUI refer to the soapUI at http://www.soapui.org/

Chapter 12. Informix 4GL Web Services

421

7884ch12.fm

Draft Document for Review August 23, 2010 10:53 am

Figure 12-5 on page 422 shows the soapUI program testing the ws_state_name

Web Service.

Figure 12-5 soapUI test

12.6.2 Tracing

There are two types of tracing a developer can use when diagnosing an Informix

4GL Web Service problem:

򐂰

Application server trace, can be used to diagnose problems between a client application and the Axis2 application server.

򐂰 Database trace, used when diagnostic problems specific to operations with the database server such as SQL errors or incorrect data being returned.

Application server trace

The Axis2c application server provides a method to trace all the exchanged messages between the application server and a client consuming a web service.

You can set this trace using the

-l log_level option when the Axis2 server is started. To launch the Axis2 server with trace enable, run the following command:

422

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch12.fm

axis2_http_server -p 9876 -l 6 -f /tmp/w4gl_informix/axis_trace.log

The option

-l is

used to specify the logging level for the application server. The maximum value is 6 that enables full tracing.

You can specify the location of the trace file using the

-f log_file

option.

Example 12-34 shows the contents of a typical trace file.

Example 12-34 application_trace sample

[debug] phase_resolver.c(139) Service name is : ws_zipcode

[debug] phase_resolver.c(1123) Operation name is : zipcode_details

[debug] phase_holder.c(139) Add handler AddressingOutHandler to phase

[debug] phase_holder.c(139) Add handler AddressingOutHandler to phase

[debug] phase_resolver.c(222) svc name is:ws_state_name

[debug] phase_resolver.c(139) Service name is : ws_state_name

[debug] phase_resolver.c(1123) Operation name is : state_name

[debug] phase_holder.c(139) Add handler AddressingOutHandler to phase

...

For more information about the logging options with the Axis2c application server, refer to the Apache Axis2/C Manual at http://ws.apache.org/axis2/c/docs/axis2c_manual.html#simple_axis_server

Database trace

IBM Informix 4GL uses the SQLI protocol to exchange data with the Informix server. This means that any Web Service developed using Informix 4GL also uses the SQLI protocol for any communication with the database server.

The environment variable SQLIDEBUG can be used to collect all the messages between the Application server and the Informix database server.

To enable this trace, create the SQLIDEBUG environment variable before starting the Axis2 Application server.

Example 12-35. demonstrates how to set SQLIDEBUG and run sqliprint to

un-encode the SQLI file.

Example 12-35 sqlidebug client side

informix@irk:/usr3/4gl750/AXIS2C/bin$ export SQLIDEBUG=2:/tmp/sqlitrace informix@irk:/usr3/4gl750/AXIS2C/bin$ ./axis2_http_server -p 9876

Started Simple Axis2 HTTP Server ...

...

...

informix@irk:/work$ ls /tmp/sqlitrace*

Chapter 12. Informix 4GL Web Services

423

7884ch12.fm

Draft Document for Review August 23, 2010 10:53 am

/tmp/sqlitrace_17008_0_8c819d0

informix@irk:/works$ sqliprint -o tracefile.txt /tmp/sqlitrace_17008_0_8c819d0 informix@irk:/works$

Note: The sqliprint tool is included in the Informix Client SDK package.

The SQLIDEBUG trace can also be used at the server side. For more

information, refer to 3.3.6, “Troubleshooting” on page 113.

424

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch13.fm

13

Chapter 13.

Application development considerations

In this chapter we examine some of the considerations a developer may need to address in a multi-user environment. A single user workstation which connects to an exclusive-use database does not have to worry about the issue of two or more independent uses of the same data at the same time. However, in a multi-user environment, concurrency is a challenge.

IBM Informix database servers are designed to provide features to help in handling concurrency and sorting facilities. The application developer should design applications to take advantage of these built-in features, rather than attempt to implement their own facilities in the application. In this chapter we examine the factors that cause concurrency problems, and focus on ways to keep the scope and duration of locks to a minimum. To do this, we consider isolation levels, sharing data, and data contention issues that can occur when two or more attempts are made to access or change the same row of data.

In the last two sections, we focus on configuration parameters that effect the application development, and how to monitor issues when the applicaiton developers work with the database administrator to tune the engine and the application to work effectively.

425

© Copyright IBM Corp. 2010. All rights reserved.

7884ch13.fm

Draft Document for Review August 23, 2010 10:53 am

13.1 Concurrency and locking

Concurrency involves two or more independent uses of the same data at the same time. In a database system with many users, each user needs to be able to access and modify data. Unless the developer and database system impose controls, there can be negative consequences. Programs might access old data that is in the process of being changed by another user, and changes may seem to disappear even though it seems like the change was performed successfully.

To take advantage of database server controls, tables in a multiple user environment should be logging tables. At a minimum, if you must use a nonlogging table within a transaction, either set Repeatable Read isolation level or lock the table in exclusive mode.

To avoid concurrency problems, the database server imposes a system of locks.

A lock is a claim, or reservation, that a program can place on a piece of data. The database server assures that no other program can modify it, as long as the lock is in place. When another application requests the data, the database server either makes the program wait or turns it back with an error.

The application developer can control the effect of lock access using a combination of SQL statements and with the buffering mode selected for the database. The most used SQL statements are SET LOCK MODE, SET

ISOLATION, and SET TRANSACTION. These are discussed in more detail later.

For now, we need a better understanding of the types of locks that we can encounter.

IBM Informix offers several server edition. IBM Informix Extended Parallel Server,

Informix Online, and Standard Engine will have different syntax for concurrency related commands. The command syntax for the discussion in this chapter follows is found in the IBM Informix Guide to SQL: Syntax, v11.50,

SC27-3611-00.

13.1.1 Types of locks

A lock is implemented as a variable associated with a data item. It can be explicitly placed by an application, or, more frequently, it is implicitly handled by the database management system. The lock is used to mark a data item as reserved; the type of lock designation determines what actions are permitted by users in regard to the data item.

In an IBM Informix instance, there are several types of locks:

򐂰 Shared lock

426

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch13.fm

A shared lock reserves its object for reading only. It prevents the object from changing while the lock remains. More than one program can place a shared lock on the same object. More than one object can read the record while it is locked in shared mode. In the lock list output visible from onstat -k , a thread with a shared lock is be designated with an “S”. If an object is currently locked in exclusive mode and the user thread wants to acquire a shared lock, the designation is “IS” (intent-shared).

When a session first connects to a database, IBM Informix Servers place a shared lock on the database, to prevent another session from acquiring an exclusive lock on the same database. SELECT queries place a shared lock at the the table level, since it is faster for the engine to find a table level lock than it is to search through potentially thousands of row locks.

򐂰 Intent-exclusive lock

Intent locks are automatically set by Informix. If a row in a table is updated, an exclusive lock is placed on the row and an intent-exclusive lock is placed on the table. This assures that no other session can place a shared or exclusive lock on the table as long as an individual row is locked exclusively. In the lock list output visible from

onstat -k

, a thread with an intent exclusive lock is designated with an “IX”. A related designation that is sometimes visible is

“SIX”. This designation indicates the object is currently shared, with

Intent-exclusive when the chance arrives.

򐂰 Exclusive lock

An exclusive lock reserves its object for the use of a single application. This lock type is used when the application needs to change the object. You cannot place an exclusive lock where any other kind of lock exists. After you place an exclusive lock, you cannot place another lock on the same object. In the lock list output visible from

onstat -k

, a thread with an exclusive lock is designated with an “X”.

򐂰 Update lock

A promotable (or update) lock establishes an intent to update. You can only place it where no other updatable or exclusive lock exists. You can place an updatable lock on records that already have shared locks. When the application is about to change the locked object, you can promote the update lock to an exclusive lock, but only if no other locks, including shared locks, are on the record at the time the lock would change from update to exclusive. If a shared lock was on the record when the update lock was set, you must drop the shared lock before the update lock can be promoted to an exclusive lock.

In the lock list output visible from onstat -k

, a thread with an update lock is designated with an “U”.

Chapter 13. Application development considerations

427

7884ch13.fm

Draft Document for Review August 23, 2010 10:53 am

13.1.2 Lock duration

The length of time a lock remains in effect is known as

lock duration

. The duration of a lock is determined by the application, the closing of a database, and the type of transaction method used by the application and database

If the database does not use transactions (no transaction log exists and you do not use a COMMIT WORK statement), an explicit table lock remains until it is removed by the execution of the UNLOCK TABLE statement.

If database transactions are in use, the end-of-lock-duration event occurs when the transaction ends or a COMMIT WORK is issued in the application. The ending transaction causes a release of all table, row, page, and index locks that were on hand during the transaction.

13.1.3 Lock granularity

With IBM Informix Servers, the developer can apply locks to databases, tables, disk pages, data rows, or index-key values. At a database level, an exclusive lock is simple to enforce for a developer, but it has a big impact on users. No one gets access until the database lock processing is completed. Concurrency drops to zero, and performance is maximized for the exclusive use of a single user running an application.

At the other end of the granularity scope for locks, a transaction can exclusively lock a row, and have no impact on other users in their work efforts (if they are not trying to access the same row, and the lock mode is row). Concurrency is maximized, but performance will tend to slide as the number of users for a database or table increases.

Table locks

It is the responsibility of both database administrator and developer to select and enable the best level of lock granularity for users and for their database system.

At the database level, administrative activities such as imports and exports are usually the task of the database administrator. For such activity, the database administrator would use a command such as

DATABASE database_name EXCLUSIVE;

Another task, principally for the database administrator, is to enable a change for a table or an index structure. The task of enabling work on an entire table can be done with a command similar to the following:

LOCK TABLE table_name IN EXCLUSIVE MODE; or

428

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch13.fm

LOCK TABLE table_name in SHARE MODE;

When the task is finished (end of statement or transaction reached), the table is implicitly unlocked. It could be unlocked explicitly with:

UNLOCK TABLE table_name;

Note: A table lock on a table can decrease update concurrency radically. Only

one update transaction can access that table at any given time, and that update transaction locks out all other transactions. However, multiple read-only transactions can simultaneously access the table. This behavior is useful in a data warehouse environment where the data is loaded and then queried by multiple users.

Page locks

Lock mode PAGE is the default for Informix tables, and it is considered the optimal level in lock efficiency when rows are being accessed and modified in physical order. If your tables are large in row count and small in row size, a page level lock can be severely limiting, since it will lock a large number of rows on a page, and discourage user access.

In this case, it would be more efficient to change the default lock mode. For all new tables, this can be done by way of the Informix onconfig file, using the parameter DEF_TABLE_LOCKMODE. For example:

DEF_TABLE_LOCKMODE ROW;

Note:

򐂰 Use a small (or default) page size if your application contains small sized rows. Increasing the page size for an application that randomly accesses small rows can decrease performance. In addition, a page lock on a larger page will lock more rows, which is likely to reduce concurrency in some situations.

򐂰

Tables that use page locks cannot support the USELASTCOMMITTED concurrency feature.

Row and key locks

Row and key locks generally provide the best overall performance when you are updating a relatively small number of rows, because they increase concurrency.

However, the database server incurs some overhead in obtaining a lock. For an operation that changes a large number of rows, obtaining one lock per row may not be cost effective. For operations that consistently change a large number of rows, page locks may be a better option.

Chapter 13. Application development considerations

429

7884ch13.fm

Draft Document for Review August 23, 2010 10:53 am

If a table is not created with row locking and you want row or key locks, you must alter the table. Here is an example to show how to create a table with row locking on:

CREATE TABLE table_namer(field1 serial,field2 char(20)...)

LOCK MODE ROW;

The ALTER TABLE statement can also change the lock mode. An example for this command syntax is:

ALTER TABLE table_name LOCK MODE (ROW);

When the lock mode is ROW and you insert or update a row, the database server creates a row lock. In some cases, you place a row lock by simply reading the row with a SELECT statement.

When the lock mode is ROW and you insert, update, or delete a key (performed automatically when you insert, update, or delete a row), the database server also creates a lock on the key in the index.

Key-value locks

When a user deletes a row within a transaction, the row cannot be locked because it becomes a non-existent row. However, the database server must somehow record that a row existed until the end of the transaction. The database server uses key-value locking to lock the deleted row. Key locks are used identically to row locks. When the table uses row locking, key locks are implemented as locks on imaginary rows.

When the table uses page locking, a key lock is placed on the entire index page that contains the key or that would contain the key if it existed. A page lock on an index page can decrease concurrency more substantially than a page lock on a data page. Index pages are dense and hold a large number of keys. By locking an index page, you make a potentially large number of keys unavailable to other users until you release the lock.

Note: To determine the current lock mode for a table:

򐂰

On UNIX, try “ oncheck -pt dbname:tablename | grep Locking”

򐂰

On Windows, examine the output of “ oncheck -pt dbname:tablename”

Database locks

The act of opening a database places a shared lock on the database name. The statements which open a database are CONNECT, DATABASE, or CREATE

DATABASE. As long as a database is open, the shared lock on the database will prevent any other program from dropping the database or putting an exclusive lock on it.

430

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch13.fm

Locking a database for exclusive use are not needed very often, since this would prevent other users and programs from accessing it for the duration of the lock.

The usual reason for a database lock would be the need for a major structure change across several tables, when implementing a series of related indexes on several tables, or when you have an application that needs uninterrupted access to the database for a period of time. To lock a database in exclusive mode, the syntax is DATABASE database_name EXCLUSIVE ;

Tasks that run from the sysadmin database (dbscheduler tasks, such as Auto

Update Statistics), occasionally may prevent exclusive database access. In this case, you must temporarily disable the dbscheduler. In the sysadmin database, stop the scheduler API with: execute function task(scheduler shutdown) and restart the scheduler API with: execute function task(scheduler start)

Smart-Large-Object locks

Smart large objects are quite different in the way they work from the rest of the structures and processes in IBM Informix databases. The locking and locking granularity for smart large objects is also different. The database server uses one of the following granularity levels for locking smart large objects:

򐂰 The sbspace chunk header partition

򐂰 The smart large object

򐂰 A byte range of the smart large object

The default locking granularity for a smart BLOB is at the level of the smart large object. When you update a smart large object, the database server locks the smart large object that is being updated. Concurrently, there is an update lock placed on the sbspace chunk header partition while the object is being updated.

Byte locks

Byte locks, also known as byte-range locks, are used to lock a specific byte range of a smart large object. Byte-range locking is advantageous because it allows multiple users to update the same smart large object simultaneously, as long as they are updating different parts of it. Also, users can read a part of a smart large object while another user is updating or reading a different part of the same smart large object.

How the database server manages byte-range locks

The database server manages byte-range locks in the lock table in a similar fashion to other locks placed on rows, pages, and tables. However, the lock table must store the byte range as well. If a user places additional locks on a byte

Chapter 13. Application development considerations

431

7884ch13.fm

Draft Document for Review August 23, 2010 10:53 am range, any new byte locks in the range that are contiguous are consolidated into one lock range.

Likewise, if a user unlocks a portion of the bytes included within a byte-range lock, the database server will split into multiple byte-range locks.

To enable use of byte-range locks

By default, the database server places a lock on the entire smart large object. At the time of sbspace creation, there is an option to use byte-range locking.

When the DBA sets the default locking mode for the sbspace to byte-range locking, the database server locks only the necessary bytes when it updates any smart large objects stored in the sbspace. To set byte-range locking for the sbspace that stores the smart large object, the database administrator must use the onspaces utility. The following example sets byte-range locking for a new sbspace: onspaces -c -S sblob -g 2 -p /ifmx/sblob1 -o 0 -s 1000 -Df LOCK_MODE=RANGE

When byte-range locking is set for the individual smart large object, the database server implicitly locks only the necessary bytes when it selects or updates the smart large object. The application developer can set byte-range locking for the smart large object when it is opened, using one of the following methods:

򐂰

Set the

MI_LO_LOCKRANGE

flag in the

mi_lo_open() DataBlade

API function.

򐂰

Set the

LO_LOCKRANGE

flag in the ifx_lo_open() ESQL/C

function.

To lock a byte range explicitly, use one of the following functions:

򐂰 mi_lo_lock()

򐂰 ifx_lo_lock()

These functions lock the range of bytes that is specified for the smart large object. If the developer specifies an exclusive lock with either function, UPDATE statements do not place locks on the smart large object if they update the locked bytes.

The database server releases exclusive byte-range locks placed with mi_lo_lock() or ifx_lo_lock() at the end of the transaction. The database server releases shared byte-range locks placed with mi_lo_lock() or ifx_lo_lock() based on the same rules as locks placed with SELECT statements, depending upon the isolation level. The application can also release shared byte-range locks with mi_lo_unlock() or ifx_lo_unlock() .

For more information about these DataBlade API functions, see the IBM Informix:

DataBlade API Programmer's Guide at

432

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch13.fm

http://publib.boulder.ibm.com/infocenter/idshelp/v10/index.jsp?topic=/com.ibm.d

apip.doc/dapip.htm

You can fine additional details about the ESQL/C functions in the IBM Informix:

ESQL/C Programmer's Manual, located at http://publib.boulder.ibm.com/infocenter/idshelp/v10/index.jsp?topic=/com.ibm.e

sqlc.doc/esqlc.htm

13.2 Locking issues and performance

Row and key locks generally provide the best performance whenever a database system only needs to update a small number of rows at a time. However, the database incurs additional overhead in obtaining a lock as the granularity gets smaller. The developer should help decide the granularity based on the character of the trnasactions.The following are guidelines for your decision making:

򐂰 For low row count transactions, use row level locking.

򐂰

For large processes that update an entire table, set locking to page or lock the table in exclusive mode before processing.

򐂰 For massive updates to many tables or the whole database, lock the database in exclusive mode before processing.

The type of isolation can affect overall performance because it affects concurrency. Before you execute a SELECT statement, you can set the isolation level with one of these options:

򐂰

The SET ISOLATION statement (an extension to ANSI SQL-92 standard)

– Can be executed more than once in a transaction.

– Can change the enduring isolation level for a session

– Has an additional isolation level - Cursor Stability.

򐂰

SET TRANSACTION (ANSI/ISO-compliant)

– Can only be executed once in a transaction.

򐂰

Dirty Read isolation (or ANSI Read Uncommitted) level does not place any locks on any rows fetched during a SELECT statement. Dirty Read isolation is appropriate for static tables that are used for queries. Use Dirty Read isolation with care if update activity occurs at the same time. With Dirty Read, the reader can read a row that has not been committed to the database and might be eliminated or changed during a rollback.

Chapter 13. Application development considerations

433

7884ch13.fm

Draft Document for Review August 23, 2010 10:53 am

13.2.1 Deadlocks

A deadlock is a situation in which a pair of programs blocks the progress of each other. Each program has a lock on some object that the other program wants to access. In a database with local database queries only, a deadlock arises only when all programs concerned set their lock modes to wait for locks.

An Informix database server detects deadlocks immediately when they only involve data at a single network server. Before a lock is granted, the database server examines the lock list for each user. If a user holds a lock on the resource that the requestor wants to lock, the database server traverses the lock wait list for the user to see if the user is waiting for any locks that the requestor holds. If so, the requestor receives a deadlock error. It prevents the deadlock from occurring by returning an error code (error -143 ISAM error: deadlock detected) to the second program to request a lock. The error code is the one the program receives if it sets its lock mode to not wait for locks. If your program receives an error code related to locks even after it sets lock mode to wait, you know the cause is an impending deadlock.

The best way to avoid deadlocks is to set lock mode to wait for a specific number of seconds (N), where N is the number of seconds it is reasonable for your applications to wait on a lock. Example syntax:

SET LOCK MODE TO WAIT 30;

Deadlock errors can be unavoidable when applications update the same rows frequently. However, certain applications might always be in contention with each other. Examine applications that are producing a large number of deadlocks and try to run them at different times. To monitor the number of deadlocks, monitor the deadlks field in the output of onstat -p .

Distributed transactions

Deadlock handling is more challenging when you are using a distributed query, which involves more than one database server. In this case, the server cannot monitor the locks of the other database, so deadlocks cannot be detected before they occur. Occasionally, there may be a need for each database to wait on a lock from another local transaction. When the wait occurs, the entire distributed transaction may need to wait until the action is cleared up. If both servers get into a wait-for-the-other-server to complete mode, you have a multi-server deadlock which neither server can easily get out of. In order to avoid this as much as possible, set the onconfig parameter DEADLOCK_TIMEOUT. This parameter tells the server how much time to wait before returning an error code (error -143

ISAM error: deadlock detected). For more information on using this configuration parameter, see your IBM Informix Dynamic Server Administrator's Guide,

v11.50, SC27-3606-00.

434

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch13.fm

Distributed transactions, also known as global transactions, can have additional problems beyond concurrency and locking. In a distributed transaction, we can have queries that include multiple, separate databases spanning multiple host machines across a network. With the added task of reaching out to different servers, we are confronted with delays caused by network traffic, connectivity issues, additional user authentication, and user activity on the other database server that can slow or temporarily prevent quick access to the remote database server. In the context of a query that is doing an update, insert, select, or delete, this new group of interfering factors can occasionally present problems.

Developers should include coding conventions to accommodate distributed (XA) transactions and include code to avoid certain problems. We have included an

ESQL/C routine ( xa_tool.ec

) in Appendix B, “Accommodating distributed transactions” on page 455, designed to help provide a start for handling XA

problems.

13.3 Isolation levels

The number and duration of locks placed on data during a SELECT statement depends on the level of isolation that the user sets. The type of isolation can affect overall performance because it affects concurrency.

You can set the isolation level with the “SET ISOLATION” or the ANSI “SET

TRANSACTION” statement before you execute the SELECT statement. The main differences between the two statements are that SET ISOLATION has an additional isolation level, Cursor Stability, and SET TRANSACTION cannot be executed more than once in a transaction as SET ISOLATION can.

Dirty Read Isolation

Dirty Read isolation (or ANSI Read Uncommitted) does not place any locks on any rows fetched during a SELECT statement. Dirty Read isolation is appropriate for static tables that are used for queries. It offers the best performance of all isolation levels, because the database server does not check or place any locks for queries.

If update activity can occur at the same time as a dirty read, there is a chance that a rollback may need to occur during the dirty read. The reader could read a row that has not been committed (this is known as a phantom read) to the database and the data would be lost during a subsequent rollback. Because of potential problems with uncommitted data that is rolled back, use Dirty Read isolation with care.

Chapter 13. Application development considerations

435

7884ch13.fm

Draft Document for Review August 23, 2010 10:53 am

Databases that do not have logging turned on (and hence do not allow transactions) use Dirty Read as a default isolation level. In fact, Dirty Read is the only isolation level allowed for databases that do not have logging turned on.

Committed Read isolation

Committed Read isolation (or ANSI Read Committed) removes the problem of phantom reads. A reader with this isolation level checks for locks before it returns a row. By checking for locks, the reader cannot return any uncommitted rows.

The database server does not actually place any locks for rows read during

Committed Read. It simply checks for any existing rows in the internal lock table.

Committed Read is the default isolation level for databases with logging, and it is an appropriate isolation level for most activities.

Cursor Stability isolation

A reader with Cursor Stability isolation acquires a shared lock on the row that is currently fetched. This action assures that no other user can update the row until the user fetches a new row.

If you do not use a cursor to fetch data, Cursor Stability isolation behaves in the same way as Committed Read. No locks are actually placed.

Repeatable Read isolation

Repeatable Read isolation (also known as ANSI Serializable and ANSI

Repeatable Read) is the strictest isolation level. With Repeatable Read, the database server locks all rows examined (not just fetched) for the duration of the transaction.

Repeatable Read is useful during any processing in which multiple rows are examined, but nothing will change during the transaction. The original application holds a read lock on each account that it examines until the end of the transaction, so the attempt by the second application to change the first account fails (or waits, depending upon SET LOCK MODE).

Note: With Repeatable Read, since even examined rows are locked, if the

database server reads the table sequentially, a large number of rows unrelated to the query result can be locked.

Use Repeatable Read isolation for tables when the database server can use an index to access a table. If an index exists and the optimizer chooses a sequential scan instead, you can use directives to force use of the index. However, forcing a change in the query path might negatively affect query performance.

436

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

13.4 Configuration options

7884ch13.fm

We have brought configuration parameters into our discussion several times. In this section we examine IBM Informix server configuration options that directly affect application development. We point out what the developers should know, and how these parameters affect the application and transactions. For more information on any of the onconfig parameters or environment variables relating to configuration, see the IBM Informix Dynamic Server Administrator's

Reference, v11.50, SC27-3607-00.

13.4.1 Server identification

When the Informix server needs to resolve a database instance name, the oninit process uses the contents of a file known as the sqlhosts file. Each line in the sqlhosts file provides a database server naming reference, called the dbservername , along with a protocol, a host machine reference, and a listening protocol service reference. On Windows, this information is stored in the registry, and is updated and accessed using the setnet32.exe

utility. Multiple dbservername references allow for an evenly distributed connection distribution over a variety of protocols

In addition to the sqlhosts information, the dbservername crosses reference to the onconfig file, which holds the configuration information describing how the database server is to operate. When a client application connects to a database server, it will specifiy a dbservername, which helps the server to know which protocol will be used for the connectivity.

The dbservername used in the application connection must be consistent with a name specified in sqlhosts and a dbservername defined in the onconfig file.

In the onconfig file there is a default (main instance) dbservername, and one or more alternate dbservernames available. The DBA specifies the default name to be used with the onconfig parameter DBSERVERNAME. For alternative application processing, the DBA can allow for or specify alternative protocols, referenced by an a different dbservername. The alternate dbservername or names are specified by the onconfig parameter DBSERVERALIASES. An application developer should check with the DBA to determine whether to use the

DBSERVERNAME or one of the DBSERVERALIASES for connecting with his applcation. Example SQL statements include CONNECT, DATABASE, CREATE

TABLE, and ALTER TABLE, which can specify the database server instance.

Chapter 13. Application development considerations

437

7884ch13.fm

Draft Document for Review August 23, 2010 10:53 am

13.4.2 Storage space identifiers

When tables are created, the database creator has syntax options available to define where tables and indexes are physically to be placed in a disk structure.

Typically the database administrator defines the disk structure layout. The disk layout is assigned by way of dbspaces, and each dbspace is further broken down into allocations of chunks. The dbspace is the parent structure unit, used to hold storage information for tables and indexes, with low level definitions to describe where the actual data pointers for row data resides, as well as information about indexes, fragments, and table scope. The dbspace area that tracks pointer locations for data is known as the table space.

When a database administrator defines the table and index schema, he can specify a dbspace location to hold the table and/or the index. There are other space specifications for default storage if none is specified at creation time.

These default locations define where to store binary large objects (BLOBs) and character large objects (CLOBs), and temporary storage locations.

The default location for the location of temp tables and sorting space, if not predefined, is the dbspace where a table is accessed, or the root dbspace

(rootdbs). If a default onconfig definition for the location of temp dbspace is defined, we have more control over the location used

DBSPACETEMP

The DBSPACETEMP parameter specifies a list of dbspaces that the database server uses to globally manage the storage of temporary tables. When a temporary space is available, it improves performance by enabling the database server to spread out I/O for temporary tables across multiple disks efficiently. The database server also uses temporary dbspaces during backups to store the before-images of data that are overwritten while the backup is occurring. More than one dbspace can be specified for this parameter. Simply list them as comma separated values.

DBSPACETEMP can contain dbspaces with a non-default page size, but all of the dbspaces in the DBSPACETEMP list must have the same page size.

When using a logged database, file activity in temporary dbspaces is not logged.

If the developer writes a query that requires tempspace, it is useful to include the phrase WITH NO LOG, so that you can force the query to use the designated temporary dbspace.

SBSPACENAME

The SBSPACENAME parameter specifies the name of the default sbspace. If your database tables include smart-large-object columns that do not explicitly

438

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch13.fm

specify a storage space, that data is stored in the sbspace that SBSPACENAME specifies. The default sbspace is also used by the built-in encryption and decryption functions to store BLOB or CLOB values.

An sbspace is a specialized type of dbspace, used for storing smartblobs, binary large object dbspaces. (Binary data or some type of multidimensional data is common to any datablade which uses R-tree indexing).

When a create table statement includes a column that defines a CLOB or BLOB object, the column information will be stored in an sbspace. If the PUT clause is not specified in the create table statement when the defined CLOB or BLOB is created, the default location where the column data will be stored is the sbspace designated by SBSPACENAME.

If you are using IBM Informix with J/Foundation, you must provide a smart large object where the database server can store the Java archive (JAR) files. These

JAR files contain the Java user-defined routines (UDRs). If you use Java UDRs, you will want to create additional, separate sbspaces for storing smart large objects.

SBSPACETEMP

The SBSPACETEMP parameter specifies the name of the default temporary sbspace for storing temporary smart large objects without metadata or user-data logging. If you store temporary smart large objects in a standard sbspace, the metadata is logged. For more information on using temporary smart large objects, see the IBM Informix DataBlade API Programmer's Guide, V11.50,

SC23-9429-03.

SYSSBSPACENAME

The SYSSBSPACENAME parameter specifies the name of the sbspace in which the database server stores statistics that the UPDATE STATISTICS statement collects for certain user-defined data types. Normally, the database server places statistics in the sysdistrib system catalog table.

Note: For information on writing user-defined statistics, see the performance

chapter in IIBM Informix User-Defined Routines and Data Types Developer's

Guide, V11.5, SC23-9438-00.

For information on providing statistics data for a smart BLOB column, see the

IBM Informix DataBlade API Programmer's Guide, V11.50, SC23-9429-03.

Chapter 13. Application development considerations

439

7884ch13.fm

Draft Document for Review August 23, 2010 10:53 am

13.4.3 Limiters and limits

In addition to the storage location identifiers mentioned in 13.4.2, “Storage space identifiers” on page 438, a number of onconfig parameters impose resource

limits. Limits help the engine and machine to utilize appropriate resources rather than consume all the resources on the machine and end up in a crash. When the resources are no longer needed, they are released to be used by other processes. These configuration limits can be adjusted in cooperation with the database administrator, to accommodate for application concerns that may need them.

MULTIPROCESSOR

The MULTIPROCESSOR parameter is used to determine the type of processing method the engine will use. If it is set to 0, locking is done in a way that is suitable for a single- processor computer, and processor affinity is ignored.

If the nearby onconfig parameter SINGLECPU_VP is non-zero (On),

MULTIPROCESSOR and user defined VPCLASSes (of any kind) will not work.

VPCLASS

The VPCLASS parameter allows you to designate a class of virtual processors

(VPs), create a user-defined VP, and specify the following information for it:

򐂰

The number of virtual processors that the database server should start initially.

򐂰 The maximum number of virtual processors allowed for this class.

򐂰

The assignment of virtual processors to CPUs if processor affinity is available.

򐂰 The disabling of priority aging by the operating system if the operating system implements priority aging.

You can have multiple VPCLASS parameter definitions. Use one VPLCLASS reference for each class of virtual processor, one per line. Basic guidelines for defining a VPLCASS are in the IBM Informix Dynamic Server Administrator's

Reference, V11.50, SC27-3607-00.

For information on creating a user-defined virtual process, see the IBM Informix

User-Defined Routines and Data Types Developer's Guide, V11.5,

SC23-9438-00 or the J/Foundation Developer's Guide, V11.5, SC23-9434-00.

NETTYPE

The NETTYPE parameter provides tuning options for the protocols that dbservername entries define in the sqlhosts file or registry. Each dbservername entry in the sqlhosts file or registry is defined in relation to either the

440

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch13.fm

DBSERVERNAME parameter or the DBSERVERALIASES parameter in the

ONCONFIG file. The NETTYPE configuration parameter describes a network connection as follows:

򐂰

The protocol (or type of connection).

򐂰 The number of poll threads assigned to manage the connection.

򐂰

The expected number of concurrent connections.

򐂰 The class of virtual processor that will run the poll threads.

򐂰

You can specify a NETTYPE parameter for each protocol that you want the database server to use.

򐂰 There is a special NETTYPE setting available if you want to enable the database server to use multiplexed connections on UNIX. To do this, you designate a NETTYPE with the value sqlmux, as in the following example.

NETTYPE sqlmux

LOCKS

The LOCKS parameter specifies the initial size of the lock table. Every SQL session that connects to a database, and accesses tables and rows, generates a lock. If the lock is non-exclusive, it is shared; if something needs to change, it is exclusive. If there is an intent to change an object, it is an intent-exclusive lock.

The lock table holds an entry for each type of lock entry, and each of these lock entries will have a small allocation in resident memory.

When the number of locks exceeds the lock table value, on 32-bit servers, the database server will increase the size of the lock table by doubling the lock table value, up to 99 times, or to the maximum value for the server allowance

(whichever comes first). On 32 bit servers, the maximum limit is 8,000,000 locks.

On 64 bit servers, the lock table limit is based on the maximum starting locks value (500,000)+ 99 allowed increments of 1,000,000 locks for a total of

599,000,000 locks

The amount of memory storage per lock will range from 100 to 200 bytes, depending on the byte-word size and the platform.

Note: All lock table increments are kept in virtual memory. If the server engine

has limited shared memory, locks can become a memory resource drain.

Chapter 13. Application development considerations

441

7884ch13.fm

Draft Document for Review August 23, 2010 10:53 am

STACKSIZE

The STACKSIZE parameter specifies the stack size for database server user threads. Setting a value for STACKSIZE that is too large wastes virtual memory space and can cause swap-space problems.

For 32-bit platforms, the default STACKSIZE value of 32 kilobytes is sufficient for non-recursive database activity. For 64-bit platforms, the recommended

STACKSIZE value is 64 kilobytes.

In recursive SQL routines, the server checks for the possibility of stack-size overflow and automatically expands the stack.

User-defined routines should increase the stack size for a routine as needed, using the stack modifier in the CREATE FUNCTION statement

USELASTCOMMITTED

This parameter specifies the isolation level whenever the LAST COMMITTED feature of the COMMITTED READ isolation level is implicitly in effect. The LAST

COMMITTED feature can reduce the risk of locking conflicts between concurrent transactions on tables that have exclusive row locks.

Important: USELASTCOMMITTED only works with tables that have been

created or altered to have ROW as their locking granularity.

In order for USELASTCOMMITTED to work as expected, and given that a table has been created or altered to have ROW as their locking granularity, the following considerations also apply:

򐂰 If SET TRANSACTION is enabled with READ COMMITTED or READ

UNCOMMITTED, USELASTCOMMITTED will work.

򐂰

Tables created without any explicit lock mode setting will use the default setting in DEF_TABLE_LOCKMODE.

DEF_TABLE_LOCKMODE

The DEF_TABLE_LOCKMODE parameter sets the lock mode for every newly created table for all sessions connected to a logging or nonlogging database, and has no effect on existing tables in the database.

The specified value can be ROW, which sets the lock mode to ROW for every new table connected to a database. If the specified value is PAGE (default), any exclusive locked table remains inaccessable.

There is also an environment variable on the client side,

DEF_TABLE_LOCKMODE, which can be set with a lock mode value (PAGE or

442

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch13.fm

ROW). The environment variable has rules of precedence involved if the onconfig value is also set. For more information, see the IBM Informix Dynamic Server

Administrator's Reference, V11.50, SC27-3607-00.

DEADLOCK_TIMEOUT

The DEADLOCK_TIMEOUT parameter specifies the maximum number of seconds that a database server thread can wait to acquire a lock. Use this parameter only for distributed queries that involve a remote database server.

Note: This parameter is applies only to distributed queries. There is a

separate, automated mechanism for deadlocks internal to a local database.

OPTCOMPIND

The OPTCOMPIND parameter determines the method used by the engine to process a query. All queries will be optimized to run based on the guideline recommended by this parameter, unless the developer forces a different guideline using a directive.

When OPTCOMPIND is set to one of the three values which follow, a given query is optimized using the guideline assigned:

򐂰 0: When appropriate indexes exist for tables in the query, the optimizer chooses index scans, without consideration of the cost, over table scans.

򐂰

1: As long as the isolation is not Repeatable Read, the optimizer will use cost based decisions. If Repeatable Read is in use, it behaves as though

OPTCOMPIND =0. Setting 1 is recommended for optimal performance.

򐂰 2: The optimizer uses cost to determine an execution path regardless of isolation level. Index scans are not given preference; the optimizer decision is purely based on cost. Setting 2 is the default if the parameter is not set.

Warning: The same OPTCOMPIND value should be used in development

and in the production environment. Performance and query behavior may have variations if OPTCOMIND is different in development and production environments.

DIRECTIVES

The DIRECTIVES parameter enables or disables the use of SQL directives. SQL directives allow you to specify behavior for the query optimizer in developing query plans for SELECT, UPDATE, and DELETE statements.

Set DIRECTIVES to 1, which is the default value, to enable the database server to process directives.

Chapter 13. Application development considerations

443

7884ch13.fm

Draft Document for Review August 23, 2010 10:53 am

Set DIRECTIVES to 0 to disable the database server from processing directives.

Note: Client programs have the option to set the IFX_DIRECTIVES

environment variable to ON or OFF to enable or disable processing of directives by the database server. The setting of the IFX_DIRECTIVES environment variable overrides the setting of the DIRECTIVES configuration parameter. If you do not set the IFX_DIRECTIVES environment variable, all sessions for a client inherit the database server configuration for processing

SQL directives.

MAX_PDQPRIORITY

The MAX_PDQPRIORITY parameter limits the PDQ resources that the database server can allocate to a given DSS query. MAX_PDQPRIORITY is a factor that is used to scale the value of PDQ priority set by users. For example, if the database administrator sets MAX_PDQPRIORITY to 80, and a user sets the

PDQPRIORITY environment variable to 50 and issues a query, the database server silently processes the query with a PDQ priority of 40. The database administrator can use the onmode utility to change the value of

MAX_PDQPRIORITY while the database server is online.

In Informix database server, PDQ resources include memory, CPU, disk I/O, and scan threads. MAX_PDQPRIORITY lets the database administrator run decision support concurrently with OLTP, without a deterioration of OLTP performance.

However, if MAX_PDQPRIORITY is too low, the performance of decision- support queries can degrade.

Table 13-1 lists the MAX_PDQPRIORITY value that you can set.

Table 13-1 MAX_PDQPRIORITY value

Value Database Server Action

0

1

Turns off PDQ. DSS queries use no parallelism.

Fetches data from fragmented tables in parallel (parallel scans) but uses no other form of parallelism.

Uses all available resources for processing queries in parallel. 100

An integer between 1-100

Sets the percentage of the user-requested PDQ resources to be allocated to the query.

13.4.4 Java configuration parameters

The configuration parameters listed Table 13-2 on page 445 allow you to use

J/Foundation, which incorporates an embedded Java virtual machine on the

444

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch13.fm

database server. For more information on these parameters, see the

J/Foundation Developer's Guide, V11.5, SC23-9434-00.

Table 13-2 Java configuration parameters

Parameter name Description

AFCRASH 0x10 When the 0x10 bit is on for AFCRASH, all the messages that the

Java Virtual Machine generates are logged into the JVM_vpid file, where vpid is the process ID of the Java virtual processor.

This file is stored in the directory where the JVPLOG file is stored.

JVPDEBUG

JVPHOME

When set to 1, tracing messages are written to the JVPLOG file.

Directory where the classes of the IBM Informix JDBC Driver are installed.

Absolute pathname for your Java VP log files. JVPLOGFILE

JVPPROPFILE

JVPJAVAVM

JVPJAVAHOME

Absolute pathname for the Java VP properties file.

Libraries to use for the Java Virtual Machine (JVM).

Directory where the Java Runtime Environment (JRE) for the database server is installed.

JVMTHREAD

JVPVJAVALIB

JVPCLASSPATH

VPCLASS jvp=n

Thread package (green or native) to use for the JVM.

Path from JVPJAVAHOME to the location of the Java VM libraries.

Initial Java class path setting.

Number of Java virtual processors that the database server should start.

For additional onconfig parameters and how they relate to development, see

Appendix A, “Onconfig parameters” on page 453.

13.5 Working with your database administrator

There is an assumption throughout this handbook that our main audience is the developer, with a distinctive separate role from the database administrator (DBA).

The database server administrator has the task of allocating and handling resources effectively in the server side of a client -server environment. When a performance issue occurs, or a transaction process is not working as it should, it becomes necessary to work with your database administrator to find a solution.

Present the problem to your database administrator. He or she may have a good

Chapter 13. Application development considerations

445

7884ch13.fm

Draft Document for Review August 23, 2010 10:53 am idea about a particular configuration area that may relate to the problem you are seeing. There are a few areas we can discuss here, which may help target the common problems that developers experience.

Configuration parameters that affect logging

Checkpoints, logging, and page cleaning are necessary to maintain database consistency. A direct trade-off exists between the frequency of checkpoints or the size of the logical logs and the time that it takes to recover the database in the event of a failure. A database administrator has to consider ways to reduce the overhead for these activities based on the acceptable delay during recovery.

Sometimes these decisions are influenced by the behavior of the application.

Here we discuss the configuration parameters that effect logging.

LOGBUFF and PHYSBUFF

The LOGBUFF and PHYSBUFF configuration parameters effect logging I/O activity because they specify the respective sizes of the logical-log and physical-log buffers that are in shared memory. The size of these buffers determines how quickly they fill and therefore how often they need to be flushed to disk. If checkpoints tend to have long duration, you can seek further information related to buffer tuning and checkpoint tuning information in the IBM

Informix Dynamic Server Performance Guide, V11.50, SC27-3618-00.

LOGFILES

The LOGFILES parameter specifies the number of logical-log files. This parameter only becomes important with respect to the long transaction high water mark (LTXHWM and LTXEHWM), if we are having trouble with transactions that need to be rolled back. See the sections on DYNAMIC_LOGS, LTXHWM and LTXEHWM, later in this chapter for more details.

LOGSIZE

Choose a log size based on how much logging activity occurs and the amount of risk in case of catastrophic failure. If you cannot afford to lose more than an hour's worth of data, create many small log files that each hold an hour's worth of transactions. If your system is stable with high logging activity, choose larger logs to improve performance.

Note: A backup process can hinder transaction processing if data is located

on the same disk as the logical-log files. It is better to keep logical logs on separate disks from data, if possible. If extra disks are not an option for separate logical log space, however, you can wait for periods of low user activity before you back up the logical-log files.

446

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch13.fm

You need to adjust the size of the logical log when your transactions include simple large objects or smart large objects, as the following sections describe.

Estimating logical-log size when logging simple large objects

To obtain better overall performance for applications that perform frequent updates of TEXT or BYTE data in blobspaces, reduce the size of the logical log.

Blobpages cannot be reused until the logical log to which they are allocated is backed up. When TEXT or BYTE data activity is high, the performance impact of more frequent checkpoints is balanced by the higher availability of free blobpages.

When you use volatile blobpages in blobspaces, smaller logs can improve access to simple large objects that must be reused. Simple large objects cannot be reused until the log in which they are allocated is flushed to disk. In this case, you can justify the cost in performance because those smaller log files are backed up more frequently.

Estimating logical-log size when logging smart large objects

If you plan to log smart-large-object user data, you must ensure that the log size is considerably larger than the amount of data being written. Smart-large-object metadata is always logged even if the smart large objects are not logged.

Use the following guidelines when you log smart large objects:

򐂰

If you are appending data to a smart large object, the increased logging activity is roughly equal to the amount of data written to the smart large object.

򐂰 If you are updating a smart large object (overwriting data), the increased logging activity is roughly twice the amount of data written to the smart large object. The database server logs both the before-image and after-image of a smart large object for update transactions. When updating the smart large objects, the database server logs only the updated parts of the before and after image.

򐂰

Metadata updates affect logging less. Even though metadata is always logged, the number of bytes logged is usually much smaller than the smart large objects.

DYNAMIC_LOGS

The default value for the DYNAMIC_LOGS configuration parameter is 2, which means that the database server automatically allocates a new logical log file after the current log file when it detects that the next log file contains an open transaction. The database server automatically checks if the log after the current log still contains an open transaction at the following times:

Chapter 13. Application development considerations

447

7884ch13.fm

Draft Document for Review August 23, 2010 10:53 am

򐂰 Immediately after it switches to a new log file while writing log records (not while reading and applying log records)

򐂰

At the beginning of the transaction cleanup phase which occurs as the last phase of logical recovery

Logical recovery happens at the end of fast recovery and at the end of a cold restore or roll forward. For more information on the phases of fast recovery, see

IBM Informix Dynamic Server Administrator's Guide, Version 11.50,

SC27-3606-00.

If you set DYNAMIC_LOGS to 0, the database server still checks whether the next active log contains an open transaction when it switches log files. If it finds an open transaction in the next log to be active, it issues the following warning:

WARNING: The oldest logical log file (%d) contains records from an open transaction (0x%p), but the Dynamic Log Files feature is turned off.

LTXHWM and LTXEHWM

The LTXHWM parameter indicates how full the logical log is when the database server starts to check for a possible long transaction and to roll it back.

LTXEHWM indicates the point at which the database server suspends new transaction activity to locate and roll back a long transaction. With the dynamic log file feature, long transaction high watermarks are no longer as critical because the database server does not run out of log space unless you use up the physical disk space available on the system. Under normal conditions, you should keep the default values for LTXHWM and LTXEHWM. If a rollback is ever needed, it can indicate a serious problem within an application.

After Version 9.4, LTXHWM and LTXEHWM are not in the onconfig.std file and default to the following values, depending on the value of the DYNAMIC_LOGS configuration parameter:

򐂰 With DYNAMIC_LOGS set to 1 or 2, the long transaction high watermark default values are 80 for LTXHWM and 90 for LTXEHWM. Because the database server does not run out of logs, other users can still access the log during the rollback of a long transaction.

򐂰

With DYNAMIC_LOGS to 0, the default values are 50 for LTXHWM and 60 for

LTXEHWM.

You might want to change these default values for one of the following reasons:

򐂰 To allow other transactions to continue update activity (which requires access to the log) during the rollback of a long transaction. In this case, you increase the value of LTXEHWM to raise the point at which the long transaction rollback has exclusive access to the log.

448

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch13.fm

򐂰 To perform scheduled transactions of unknown length, such as large loads that are logged. In this case, you increase the value of LTXHWM so that the transaction has a chance to complete before reaching the high watermark.

13.5.1 Parameters for negotiation

While the database administrator should make final decisions for server parameters, there are several parameters for which you need agreement to achieve the most effective results.

VPCLASS

If you decide to use user-defined routines (UDRs), a UDR can use the processing power in the CPU class that users currently have at their disposal, or you can define the UDR with its own processor class when you create the function. You define a new class of virtual processors to isolate UDR execution from other transactions that execute on the CPU virtual processors. This is typically used when you write UDRs to support user-defined data types.The class name that you specify in the VPCLASS parameter must match the name specified in the CLASS modifier of the CREATE FUNCTION statement.

Note: Since a user defined CPU class is treated as a virtual processor, the

onconfig parameter SINGLE_CPU_VP must be off (0) and

MULTIPROCESSOR must be on (1).

Guidelines for setting VPCLASS

򐂰

For uniprocessor computers, it is recommended that you use one CPU virtual processor.

򐂰 VPCLASS cpu,num=1.

򐂰

For multiprocessor systems with four or more CPUs that are primarily used as database servers, it is recommended that you set the VPCLASS num option to one less than the total number of processors. For example, if you have four

CPUs, use the following specification:

VPCLASS cpu,num=3

Process priority aging

On some operating systems, priority aging occurs when the operating system lowers the priority of long-running processes as they accumulate processing time. You should always disable the priority aging parameter of VPCLASS because it can cause the performance of the database server processes to decline over time. For further information, check the machine notes for your database server.

Chapter 13. Application development considerations

449

7884ch13.fm

Draft Document for Review August 23, 2010 10:53 am

Processor affinity

Processor affinity distributes the computation impact of CPU virtual processors and other processes. On computers that are dedicated to the database server, assigning CPU virtual processors to all but one of the CPUs achieves maximum

CPU utilization. On computers that support both database server and client applications, you can bind applications to certain CPUs through the operating system. By doing so, you effectively reserve the remaining CPUs for use by database server CPU virtual processors, which you bind to the remaining CPUs with the VPCLASS configuration parameter. Set the

aff

option of the VPCLASS

parameter to the numbers of the CPUs on which to bind CPU virtual processors.

For example, on an 8 CPU machine, the following VPCLASS setting assigns

CPU virtual processors to processors 4 to 7, and CPU’s 0,1,2,and 3 would be most available to the application:

VPCLASS cpu,num=4,aff=4-7

For additional methods that can be used with the VPCLASS, see your IIBM

Informix Dynamic Server Administrator's Guide, V11.50, SC27-3606-00.

13.5.2 Monitoring isolation levels

As a general discovery tool, the onstat -g sql

command can be used for determining the isolation levels and lock modes for SQL statements actively running against the server, their associated databases and any SQL errors that might have occurred. The onstat -g sql

command can also be run with an optional session ID. The output contains the most recent and the current SQL statements being run by the session.

13.5.3 Monitoring locks

The onstat -k

command displays the current database locks held within the system. The type of lock is determined by the logging mode, isolation levels, and

application design. Example 13-1shows the output of a sample

onstat -k command.

Example 13-1 onstak -k output

IBM Informix Dynamic Server Version 11.50.UC6 -- On-Line -- Up 03:55:17 --

15360 Kbytes

Locks address wtlist owner lklist type tblsnum rowid key#/bsiz a095f78 0 a4d9e68 0 HDR+S 100002 203 0

1 active, 2000 total, 2048 hash buckets, 0 lock table overflows

450

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ch13.fm

The information in this output explains lock aspects. The type column explains the lock types associated with each open lock. The abbreviations in the Type column defines lock types as follows:

X

U

IX

IS

HDR

B

I

S

Header

Byte lock

Shared

Intent

Exclusive

Update

Intent exclusive

Intent-shared

The lock level is determined by the value of the tblsnum

(tblspace ID) and the row

ID as show in Table 13-3 and Table 13-4.

Table 13-3 Determining lock level from Row ID

If RowID Lock level is

Equals 0 Table

Ends in 00

<6 digits & non zero

Page

Row

Table 13-4 Determining lock level from tblsnum

If tblsnum ID Lock level is

Equals 100002 Database

<10000 ER Pseudo lock

13.5.4 Monitoring user threads

The onstat -u command output reveals all of the current user threads running on a server, though the output can be cryptic. In a highly active system it is normal to see user threads waiting on various conditions. These wait conditions change rapidly as resources are engaged and released. To identify a problem when a particular session is having a problem, monitor the primary user threads by watching the flags over a few minutes. If the user thread remains and the thread and wait conditions are unchanging, it provides a sign that the time has come to focus in on a problem user thread. Watch the flag values, then narrow down the problem by zeroing in the details of the problem with additional onstat commands. The steps to do this are:

Chapter 13. Application development considerations

451

7884ch13.fm

Draft Document for Review August 23, 2010 10:53 am

1. Look at flag position 5: Primary threads (P) are the only ones of interest

(Ignore other user threads).

2. Look at flag position 1 (Wait conditions): B =buffer, C =checkpoint, G=write of the Logical Log buffer, L = lock, S = mutex, T =transaction, X=transaction cleanup, Y=condition. (Watch for persistent L,S,T, or Y).

3. Look at flag position 3 (thread activity): A=DBSpace backup, B= Begin work,

P=Preparing/prepared, X=XA prepare, C=Commiting/committed,

R=Aborting/aborted, H=Heuristic aborting/aborted. (Watch for P, X,C,R,H).

For more information on onstat commands and the meanings of the columns check out the onstat portal, located at http://publib.boulder.ibm.com/infocenter/idshelp/v115/index.jsp?topic=/com.ibm.

adref.doc/ids_adr_0608.htm

452

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ax01.fm

A

Appendix A.

Onconfig parameters

13.4, “Configuration options” on page 437 discusses several parameters that

have a direct impact on developer methods and understandings. The list provided was limited to the direct-impact related parameters. It is likely that application developers will not have much use for the remaining onconfig parameters most of the time. Normally, this remaining configuration information is only a concern for the database administrators. Occasionally, there will come a time when performance of an application may come into question. Sometimes slow performance is caused by the application, and is under control of the developer. At other times it may be an onconfig setting in the IBM Informix server

that requires adjustment. The parameters listed in Table A-1 on page 454 may

help the developer and the database administrators to narrow the target area for further investigation. It is not an exhaustive list; parameters that do not apply or which have already been discussed in this book are not mentioned. For further information on any of these parameters, see IBM Informix Dynamic Server

Administrator's Reference, v11.50, SC27-3607-00.

From the developer’s point of view, it makes sense to categorize the configuration parameters from a functional perspective, rather than a strict listing by name.

Toward this objective, the parameter names are listed by function groupings to help narrow down the parameter list that can be considered for an area of specific interest. The functional groupings do not reflect specific naming conventions used in the onconfig file.

453

© Copyright IBM Corp. 2010. All rights reserved.

7884ax01.fm

Draft Document for Review August 23, 2010 10:53 am

Table A-1 Onconfig parameters

Related function area Onconfig parameters

Storage Space

Path locations

ROOTNAME, ROOTOFFSET, ROOTSIZE, MIRROR,

MIRROROFFSET, LOGFILES, LOGSIZE,

DBSPACETEMP, SBSPACETEMP, SBSPACENAME,

SYSSBSPACENAME, CLEANERS, STAGEBLOB,

TBLTBLFIRST, TBLTBLNEXT, DATASKIP

ROOTPATH, JVPJAVALIB, JVPJAVAVM, MSGPATH,

PLOG_OVERFLOW_PATH

BUFFERPOOL,PHYSBUFF, PHYSFILE Buffer Movement

Memory Cache

Memory control

Virtual processor and connection

SQL Control

DD_HASHSIZE, DD_HASHMAX, DS_HASHSIZE,

DS_POOLSIZE, PC_HASHSIZE, PC_POOLSIZE,

STMT_CACHE, STMT_CACHE_HITS,

STMT_CACHE_SIZE, STMT_CACHE_NOLIMIT,

STMT_CACHE_NUMPOOL, PLCY_POOLSIZE,

PLCY_HASHSIZE, USRC_POOLSIZE,

USRC_HASHSIZE

RESIDENT, SHMVIRTSIZE, SHMADD, EXTSHMADD,

SHMTOTAL, SHMVIRT_ALLOCSEG,

SHMNOACCESS,VP_MEMORY_CACHE_KB,

ONLIDX_MAXMEM

NETTYPE, LISTEN_TIMEOUT,

MAX_INCOMPLETE_CONNECTIONS, FASTPOLL,

MULTIPROCESSOR, VPCLASS, SINGLE_CPU_VP,

AUTO_AIOVPS, DIRECT_IO

LOCKS, OPTCOMPIND, DIRECTIVES,

EXT_DIRECTIVES, OPT_GOAL, IFX_FOLDVIEW,

RA_PAGES, RA_THRESHOLD

Transaction control

Decision support

DEF_TABLE_LOCKMODE, BLOCKTIMEOUT,

TXTIMEOUT, HETERO_COMMIT,

DEADLOCK_TIMEOUT, DYNAMIC_LOGS, LOGBUFF,

LTXHWM, LTXEHWM, TEMPTAB_NOLOG,

AUTO_REPREPARE

DS_MAX_QUERIES, DS_TOTAL_MEMORY,

DS_MAX_SCANS, DS_NONPDQ_QUERY_MEM

454

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ax02.fm

B

Appendix B.

Accommodating distributed transactions

This appendix discusses the use of distributed transactions with an IBM Informix database server.

© Copyright IBM Corp. 2010. All rights reserved.

455

7884ax02.fm

B.1 Distributed transactions

Draft Document for Review August 23, 2010 10:53 am

A transaction is a series of actions performed as a single logical unit of work in which either all of the actions are performed or none of them are.

A distributed transaction is a transaction that runs in multiple processes, usually on several machines, and normally involves actions against two or more databases. Each participant of a distributed transaction must agree to commit the changes before the distributed transaction can be committed.

There are three core components on a distributed transaction:

򐂰

Application program (AP)

Application program implements the desired business function. It specifies a sequence of operations that involve resources such as databases. An application program participates in one or more units of work, and might decide to commit or roll back each unit of work independently.

򐂰

Resource manager (RM)

Resource manager manages access to shared resources such as databases.

The resource manager provides the services to manage the data involved in the distributed transaction.

򐂰

Transaction manager (TM)

Transaction manager manages global transactions and coordinates the decision to commit them or roll them back ensuring their atomicity. The transaction manager also coordinates recovery activities of the resource managers when necessary, such as after a component failure.

The XA standards, set forth by the Open Group's X/Open Distributed Transaction

Processing (DTP) model, define the interfaces between the transaction manager, the application program, and the resource manager in a DTP environment.

These interfaces are implemented in the Informix TP/XA Interface Library.

B.2 TP/XA Transaction Manager XA Interface Library

TP/XA is a library of functions that allows the IBM Informix database server act as a resource manager in the X/Open DTP environment.The TP/XA library facilitates communication between a third-party transaction manager and the database server.

TP/XA is supplied with IBM Informix ESQL/C included on the IBM Informix Client

SDK package.

456

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ax02.fm

In addition to the TP/XA library, a header file xa.h, is supplied containing the definition for the functions and common structures such as XID or xa_switch_t used by the transaction manager and resource manager.

Table 13-5 describes the functions used to work with XA transactions.

Table 13-5 TP/XA Macro definitions

Function Description

xa_open() Initializes the resource manager (database server) for a XA transaction xa_close() xa_start() xa_end() xa_rollback()

Close a currently open resource manager

Starts a XA transaction

Dissociates from a XA transaction

Tells the resource manager to roll back a XA transaction xa_prepare() xa_commit() xa_recover() xa_forget() xa_complete()

Asks the resource manager to prepare to commit a XA transaction

Tells the resource manager to commit a XA transaction

Obtains a list of XIDs that are currently in a prepared or heuristically completed state

Tells the resource manager to forget a heuristically completed transaction

Test Completion of asynchronous XA Request. This function is provided only for compliance with the X/Open XA Specification

B.3 XA_TOOL ESQL/C sample

Example B-1is a basic ESQL/C application which demonstrates how to use some of the TP/XA functions such as xa_prepare()

and xa_rollback()

to perform operations with a distributed transaction.

Example B-1 xa_tool.ec

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

*

* WARNING: USE OF THIS PROGRAM MAY HAVE UNDESIRABLE AFFECTS

* TO THE DATABASE SERVER, INCLUDING DATA CORRUPTION!!

*

* TITLE: xa_tool.ec

*

* Compile with:

Appendix B. Accommodating distributed transactions

457

7884ax02.fm

Draft Document for Review August 23, 2010 10:53 am

* on UNIX systems:

* esql -o xa_tool xa_tool.ec -lifxa

* on Windows systems

* esql xa_tool.ec

*

* This program will connect to a global transaction branch

* and let the user manipulate the transaction.

*

* Usage:

* xa_tool <fID> <gtl> <bql> <hex data>

*

* The fID, gtl, bql, and hex data should be provided from the

* transaction desired to be manipulated. The information is

* found by execution of the onstat -G command. Example output

* of the onstat -G command:

*

* Global Transaction Identifiers

* address flags fID gtl bql data

* cb2a964 0x8442a 0 2 4 4D4E4F000000

* 1 active, 128 total

*

* If transaction cb2a964 is the transaction that is desired

* to be manipulated, then this program should be executed

* with the following command:

*

* xa_tool 0 2 4 4D4E4F000000

*

*

*************************************************************

*/

#include <stdio.h>

#include <stdlib.h>

#include <ctype.h>

#include "xa.h" extern struct xa_switch_t infx_xa_switch;

#define xa_open(info, rmid, flags) \

((*infx_xa_switch.xa_open_entry)(info,rmid,flags))

#define xa_start(gtrid,rmid, flags) \

((*infx_xa_switch.xa_start_entry)(gtrid,rmid,flags))

#define xa_rollback(gtrid,rmid, flags) \

((*infx_xa_switch.xa_rollback_entry)(gtrid,rmid,flags))

#define xa_commit(gtrid,rmid, flags) \

((*infx_xa_switch.xa_commit_entry)(gtrid,rmid,flags))

#define xa_rollback(gtrid,rmid, flags) \

((*infx_xa_switch.xa_rollback_entry)(gtrid,rmid,flags))

#define xa_end(gtrid,rmid, flags) \

((*infx_xa_switch.xa_end_entry)(gtrid,rmid,flags))

#define xa_prepare(gtrid,rmid, flags)\

((*infx_xa_switch.xa_prepare_entry)(gtrid,rmid,flags))

#define xa_close(info,rmid, flags)\

458

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

((*infx_xa_switch.xa_close_entry)(info,rmid,flags))

#define xa_forget(gtrid,rmid, flags)\

((*infx_xa_switch.xa_forget_entry)(gtrid,rmid,flags))

#define xa_recover(gtrid, count, rmid, flags)\

((*infx_xa_switch.xa_recover_entry)(gtrid,count,rmid,flags))

/* Doesn't matter what database is opened... */

#define OPEN_DATABASE "sysmaster"

7884ax02.fm

/* Initialize the xid */ void setup_myxid (XID *xid, int x_fID, int x_gtl, int x_bql, char* x_data)

{

int ii, c;

xid->formatID = x_fID;

xid->gtrid_length = x_gtl;

xid->bqual_length = x_bql;

for(ii=0; ii<x_gtl+x_bql; ii++)

if (sscanf( &x_data[ii*2], "%02x", &c) != 1)

{

printf("Invalid GTRID data!\n");

exit(1);

}

else

xid->data[ii] = (char) c;

} void xa_tool(XID *xid)

{

int choice = 0;

int cc;

while( choice != 'Q')

{

printf("\tP -- XA_PREPARE\n");

printf("\tC -- XA_COMMIT\n");

printf("\tR -- XA_ROLLBACK\n");

printf("\tF -- XA_FORGET\n");

printf("\tQ -- terminate program\n");

printf("Enter Choice: ");

choice = getchar();

choice = toupper(choice);

printf("%c\n\n", choice);

switch(choice)

{

case 'P':

printf("Executing XA_PREAPRE\n");

if ((cc = xa_prepare(xid, 0, TMNOFLAGS)) != XA_OK)

{

Appendix B. Accommodating distributed transactions

459

7884ax02.fm

Draft Document for Review August 23, 2010 10:53 am

printf("XA_PREPARE failed with %d\n", cc);

}

else

printf("... XA_PREPARE finished\n\n");

break;

case 'C':

printf("Executing XA_COMMIT\n");

if ((cc = xa_commit(xid, 0, TMNOFLAGS)) != XA_OK)

{

printf("XA_COMMIT failed with %d\n", cc);

}

else

printf("... XA_COMMIT finished\n\n");

break;

case 'R':

printf("Executing XA_ROLLBACK\n");

if ((cc = xa_rollback(xid, 0, TMNOFLAGS)) != XA_OK)

{

printf("XA_ROLLBACK failed with %d\n", cc);

}

else

printf("... XA_ROLLBACK finished\n\n");

break;

case 'F':

printf("Executing XA_FORGET\n");

if ((cc = xa_forget(xid, 0, TMNOFLAGS)) != XA_OK)

{

printf("XA_FORGET failed with %d\n", cc);

}

else

printf("... XA_FORGET finished\n\n");

break;

case 'Q':

break;

default:

printf("%c is not a valid option!\n\n", choice);

choice = 0;

} if (choice != 'Q') {

choice = getchar();

}

}

choice = 0;

} int main(int arc, char *argv[])

{

$int cc;

XID xid;

int xid_fID, xid_gtl, xid_bql;

char xid_data[300];

if (arc != 5)

460

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

{

printf("Error: Incorrect number of parameters.\n");

printf("Usage: %s <fID> <gtl> <bql> <data>\n", argv[0]);

exit(2);

}

printf("\n\n");

xid_fID = atoi(argv[1]);

xid_gtl = atoi(argv[2]);

xid_bql = atoi(argv[3]);

strcpy(xid_data, argv[4]);

/* setup the XID which is used to identify the transaction */

setup_myxid(&xid, xid_fID, xid_gtl, xid_bql, xid_data);

/* establish connection to the database */

printf("Calling xa_open ... \n");

if ((cc = xa_open(OPEN_DATABASE, 0, TMNOFLAGS)) != XA_OK)

{

printf("xa_open failed with %d, sqlcode = %d\n", cc, SQLCODE);

exit(1);

}

else

printf("... xa_open finished\n\n");

/** This is for xa_tool... **/

xa_tool(&xid);

7884ax02.fm

/* close the connection */

printf("Calling xa_close...\n");

if ((cc = xa_close("", 0, TMNOFLAGS)) != XA_OK)

{

printf("xa_close failed with %d\n", cc);

exit(1);

}

else

printf("... xa_close finished\n\n");

}

You also can use the xa_tool

example to complete unresolved transactions left in the database server. Local transactions are automatically roll back by the

Informix database server if the connection between the client application and the database server was lost. This happens because the database server is in direct control of the transaction.

When using distributed transactions the database server can not automatically resolved a transaction, the Transaction Manager is the only process in charge of committing or aborting the global transaction. This means that if there is an

Appendix B. Accommodating distributed transactions

461

7884ax02.fm

Draft Document for Review August 23, 2010 10:53 am communication error or a failure within the resource manager, there is a chance of leaving unresolved transactions in the database server.

These transactions can be resolved using the xa_commit() , xa_rollback() , and xa_forget() functions. Example B-2 shows how to compile and use the xa_tool.ec

program to rollback an XA transaction left in the Informix database server.

Example B-2 xa_tool.ec output

D:\Infx\ids1150>onstat -G

IBM Informix Dynamic Server Version 11.50.FC6 -- On-Line -- Up 05:04:17

Global Transaction Identifiers address flags isol timeout fID gtl bql data

83246d88 -L--G COMMIT 0 0 2 4 4D4E4F000000

1 active, 128 total

D:\Infx\ids1150>

C:\work>esql -nologo xa_tool.ec

IBM Informix CSDK Version 3.50, IBM Informix-ESQL Version 3.50.TC7

xa_tool.c ...

C:\work>xa_tool 0 2 4 4D4E4F000000

Calling xa_open ...

... xa_open finished

P -- XA_PREPARE

C -- XA_COMMIT

R -- XA_ROLLBACK

F -- XA_FORGET

Q -- terminate program

Enter Choice: R

R

Executing XA_ROLLBACK

... XA_ROLLBACK finished

P -- XA_PREPARE

C -- XA_COMMIT

R -- XA_ROLLBACK

F -- XA_FORGET

Q -- terminate program

Enter Choice: q

Q

Calling xa_close...

... xa_close finished

C:\work>

462

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884ax02.fm

For more information related to the TP/XA library refer to the TP/XA Transaction

Manager XA Interface Library User Manual at: http://publibfp.boulder.ibm.com/epubs/pdf/5193.pdf

Appendix B. Accommodating distributed transactions

463

7884ax02.fm

Draft Document for Review August 23, 2010 10:53 am

464

IBM Informix Developer’s Handbook

7884bibl.fm

Draft Document for Review August 23, 2010 10:53 am

Related publications

The publications listed in this section are considered particularly suitable for a more detailed discussion of the topics covered in this book.

IBM Redbooks

For information about ordering these publications, see “How to get Redbooks” on page 466. Note that some of the documents referenced here may be available in

softcopy only.

򐂰 Embedding Informix Dynamic Server: An Introduction, SG24-7666

Other publications

These publications are also relevant as further information sources:

򐂰 IBM Informix Dynamic Server Administrator’s Guide, v11.50, SC23-7748

򐂰 IBM Informix Guide to SQL: Reference, v11.50, SC23-7750

򐂰 Embedded SQLJ User’s Guide, Version 2.90, G251-2278

򐂰 IBM Informix Storage Manager Administrator’s Guide, v2.2, G229-6388

򐂰 IBM Informix Security Guide, v11.50, SC23-7754

򐂰 IBM Informix GLS User’s Guide, G229-6373

򐂰 IBM Informix Dynamic Server Administrator’s Reference, SC23-7749

򐂰 IBM Informix Guide to SQL: Syntax, v11.50, SC23-7751

򐂰 IBM Informix Guide to SQL: Tutorial, G229-6427

򐂰 IBM Informix Dynamic Server Performance Guide, v11.50, SC23-7757

򐂰 IBM Informix High-Performance Loader User’s Guide, v11.50, SC23-9433

򐂰 IBM Informix Migration Guide, SC23-7758

򐂰 IBM Informix JDBC Driver Programmer’s Guide, SC23-9421

򐂰 IBM Informix ESQL/C Programmer’s Manual, v3.50, SC23-9420

򐂰 IBM Data Server Provider for .NET Programmer’s Guide, SC23-9848

465

© Copyright IBM Corp. 2010. All rights reserved.

7884bibl.fm

Draft Document for Review August 23, 2010 10:53 am

򐂰

IBM Informix Dynamic Server Installation Guide for UNIX, Linux, and Mac OS

X, GC23-7752

򐂰

IBM Informix DB-Access User’s Guide, SC23-9430

򐂰 IBM Informix ODBC Driver Programmer’s Manual, SC23-9423

򐂰

IBM Informix Dynamic Server Installation Guide for Windows, GC23-7753

򐂰 Guide to Informix MaxConnect, Version 1.1, G251-0577

򐂰

IBM Informix Backup and Restore Guide, v11.50, SC23-7756

򐂰 IBM Informix Dynamic Server Enterprise Replication Guide, v11.50,

SC23-7755

򐂰

“Expand transaction capabilities with savepoints in Informix Dynamic Server” by Uday B. Kale in IBM developerWorks, 26 March 2009: http://www.ibm.com/developerworks/data/library/techarticle/dm-0903idssavepo ints/index.html

Online resources

These websites are also relevant as further information sources:

򐂰

IBM Informix Dynamic Server v11.50 Information Center: http://publib.boulder.ibm.com/infocenter/idshelp/v115/index.jsp

How to get Redbooks

You can search for, view, or download Redbooks, Redpapers, Technotes, draft publications and Additional materials, as well as order hardcopy Redbooks publications, at this website:

ibm.com/redbooks

Help from IBM

IBM Support and downloads

ibm.com/support

IBM Global Services

ibm.com/services

466

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

7884bibl.fm

Related publications

467

7884bibl.fm

Draft Document for Review August 23, 2010 10:53 am

468

IBM Informix Developer’s Handbook

7884IX.fm

Draft Document for Review August 23, 2010 10:53 am

Index

Symbols

.4cf extension 406

.ec 124

.ecp 124

.NET connection string attributes

Client_Locale 253

Connection Lifetime 253

DB_LOCALE 253

DELIMIDENT 253

Enlist 253

Fetch Buffer Size 254

Host 253

Max Pool Size 253

OPTOFC 254

Packet Size 254

Pooling 254

PWD 254

Skip Parsing 254

UserDefinedTypeFormat 254

XCL 253

Numerics

4GL 13

A

access method 327

ACE Report Writer 7

ActiveRecord 357

ad hoc queries 6

adapter script 363

ADO interface

IAccessor 215

IColumnsInfo 215

ICommand 215

IDBCreateCommand 215

IDBCreateSession 215

IDBDataSourceAdmin 215

IDBProperties 215

IErrorLookup 215

IGetDataSource 215

IRowsetIdentity 215

ISessionProperties 215

© Copyright IBM Corp. 2010. All rights reserved.

ITransaction 215

ADO object 212

adOpenDynamic cursor 219 adOpenForwardOnly cursor 219 adOpenKeyset cursor 219 adOpenStatic cursor 219

advanced access control feature 21

annotation 205

ANSI serializable 436

antlr-2.7.6.jar 187

application programming interface 13

application-programming interface 32

attribute 184

authorized user 4

AutoCommit mode 166

AXIS2C_HOME 393

B

backup 324

backup server 20

begin work 135

BeginTransaction method 267

BeginTransaction() 258

bigint data type 77 bigserial data type 77

binary import routine 327

binary large object 438

binary receive routine 327 binary send routine 327

bind parameter 302

bladelet 352

BLOB 77, 438

BOOLEAN 77

Boolean UDR 326

buffered logging 18

built-in data type 324

bulk load 7

byte 77

byte column 6

byte-range lock 431

byte-range locking 432

469

7884IX.fm

C

call level interface 14

CallableStatement object 167

cast function 326

cast support function 341

certified file 177

character large object 343, 438

checkpoint 21

chunk 438

CLASSPATH environment variable 153

classpath environment variable 47, 188

CLI 14

CLI parameters

database 69 hostname 69 port 69 protocol 69

client connectivity 6

client locale 58

Client SDK 14

client_locale environment variable 145

CLOB 77, 438

collection 9

collection data type 140, 341

collection variable 141

column-level encryption 21

commit work 135

committed read 436

compiler 126

complex data type 328

component object model 210

concentrator 4

concurrency 21, 426

concurrent query 18

concurrent session 4

connection management 186

connection object 166

connection pooling 151

connection string 251

connection string attribute 216

connection_adapters directory 363

connectionstring property 258

constraint 184

continuity 20

controller 357

convention over configuration 376

cost factor 326 cost function 326

cursor behavior 58

470

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

cursor stability 435–436

customer object 184

customized routine 324

D

data access layer 184

Data accessibility 138

data consistency 7

data consumer 12

data definition language 192

data logging 138

data management 6

data manipulation language 192

data mart 6

data provider 12, 248

data query language 184

data source name 57

data type extension 324

data warehouse 6

database driver 41

database extension 324

database instance name 437

database locale 58

database lock 430

database operation 72

datasource 151

datetime 77

db_locale 59

db_locale environment variable 145

db2cli.ini 69

db2jcc.jar 47, 188 db2jcc4.jar 47

db2sdriver.cfg configuration file 255

DbDataReader method 263

dbschema utility 386

dbspace 438 dbspacetemp parameter 438

DDL 192

deadlock 434

deadlock_timeout parameter 443

def_table_lockmode parameter 429, 442

delete 72

dependency list 330

directives parameter 443

dirty read isolation 433

discarded-logging 188

display environment variable 35

distinct 9, 77

Draft Document for Review August 23, 2010 10:53 am

distinct data type 324, 328

distributed transaction 18, 90, 435, 456

distributed transactions 150

distribution statistic 327

dmg format 24

DML 192

dom4j-1.6.1.jar 187

DRDA protocol 151

DRDADEBUG trace 182

driver manager 9

driver package 41

drsoctcp 28

dyld_library_path environment variable 127

dynamic link library 343

dynamic sql 132

dynamic_logs configuration parameter 447

E

editions 2

element type 140

encryption 177

end-user routine 326

environment variable

ld_library_path 127, 347, 359

lib 127 libpath 127 shlib_path 127, 359

esql command 13

exception 199

exclusive lock 427 exclusive mode 426–427

execute into command 130

executeQuery() 163 executeUpdate() 163

export routine routine 327

F

failover 20

fast data loading 6

fetch buffer size 58

filetoblob 139

finderr 33

finderr utility 13

flat file 7

flow-control extension 324

functional test file 14

I

G

gem utility 363

generator element 194

get diagnostics statement 144

get() method 199

GetIfxMonthSpan 263

global transaction 456

global transactions 435

i4gl_func 397

IBM.Data.DB2 249

IBM.Data.Informix 249

ICommand interface 220

idssecuritylabel 77

ifx_lo_lock() 432

ifx_lo_open 78

ifx_lo_t 137

ifx_lo_write 78

IfxBlob GetIfxBlob() 258, 263

IfxClob GetIfxClob() 258, 263

IfxCommand 262

IfxCommand class 259

IfxCommand CreateCommand() 258

IfxCommand method 265

IfxConnection class 258

IfxConnection object 267

IfxDataReader 262

IfxDataReader ExecuteReader() 260

IfxDateTime class 276

7884IX.fm

H

header file 14, 457

Hibernate dialect 190

Hibernate service 189

Hibernate session instance 197

hibernate.cfg.xml 189 hibernate.property 189

hibernate3.jar 187 hibernate-jpa-2.0-api-1.0.0.Final.jar 187

HibernateUtil class 196

high availability clustering 3

high availabiliy replication 17

host name 57

host variable 141

HQL criteria 202

HQL restriction 202

HTTP link 411

Index

471

7884IX.fm

IfxDateTime GetIfxDateTime() 263

IfxDateTime public method 277

IfxDecimal GetIfxDecimal 263

IfxDecimal object 280

IfxDecimal public method 281

ifxdotnettrace variable 286

IfxError 265

IfxException class 265

ifxjdbc.jar 188

IfxMonthSpan 263

ifxoledbc COM class ID 210

ifxoledbctrace environment variable 243

IfxParameter 266

IfxParameter CreateParameter() 260

IfxParameterCollection object 265

IfxTimeSpan GetIfxTimeSpan 263

IfxTransaction 258

IfxTransaction object 267

iifxoledbc.dll 210

ILogin utility 33

Implict invocation 327

incoming parameter 331

Informix classes 11

Informix OLE DB Provider 34

informixc.so 359

informixdir environment variable 19, 55, 123

informixserver 347

informixserver environment variable 129, 359

informix-sqli 159

inheritance 184

insert 72

installation directory 19

installation ini file 24

installIDSDriver command 41

int8 77

intent locks 427 intent-exclusive lock 427 intent-shared 427

interval day 77 interval day to hour 77 interval day to minute 77 interval day to second 77 interval hour 77 interval hour to minute 77 interval hour to second 77 interval minute 77 interval minute to second 77 interval month 77 interval second 77

Draft Document for Review August 23, 2010 10:53 am

interval year 77 interval year to month 77

Isolation Level 58, 66

isolation level 18, 426, 435, 450

ISupportErrorInfo interface 229

Iterator function 326

J

jar file 334

Java annotation 185

Java archive file 334

Java class file 188

Java compiler 188

Java interface 11

Java library 187–188

Java Naming and Directory 161

java property 189

Java runtime 161

Java Virtual Machine 34, 188

java_bindir environment variable 335 java_home environment variable 335 java_root environment variable 335

java.io.Serializable 11

java.lang.object 12

java.sql.ParameterMetaData 11

javassist-3.9.0.GA.jar 187

javax.sql extensions 158

javax.sql.ConnectionEventListener 11 javax.sql.ConnectionPoolDataSource 11 javax.sql.DataSource 11 javax.sql.PooledConnection 11 javax.sql.XADataSource 11

JDBC API interfaces 151

JDBC class 151

JDBC method 151

JDBC standard 7

jjdk_home environment variable 335

JNDI 161

jre_home environment variable 335

jta-1.1.jar 187

jvp.log 341

K

key 429

Key lock 430

keystore file 178

key-value locking 430

472

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

L

label-based access control 21

library file 122

licensing metric 4

limited use socket 4–5

list 140

load() 199 load() method 199

loc_t 137

lock 426

lock duration 428

lock list 434

lock mode page 429

locks parameter 441

logbuff 446 logfiles parameter 446

logging mode 450

logical device 7 logical volume manager 7

logical-log buffer 18, 446 logical-log record 18

long identifier 9

loopback connection 7

LPAR 4

ltxehwm parameter 448 ltxhwm parameter 448

LU socket 5

lvarchar 78

M

make file 14

max_pdqpriority parameter 444

MaxBytes 270

memory addressability 2

messages files 14

method 184

method properties

position 270

ReferenceCount 270

mi_lo_lock() 432

migration 385

model 356–357

module 14

money 78

msgpath file 341

multimedia capability 7

multiplexed connection 16–17

multiplexer 4

multiprocessor parameter 440

multiset 140

mutexes 16 mutually exclusive 16

N

native-protocol 49

nchar 78

negator function 326

nettype parameter 440

network connection 16

nvarchar 78

7884IX.fm

O

OAT 7, 15

object ExecuteScalar() 260

object file 122

object processing 185

object-orientated programming 184

object-relational mapper 357

object-relational mapping technology 184

ODBC data source 56

ODBC driver 55

ODBC driver configuration files

odbc 62 odbcinst.ini 62 sqlhosts 62

ODBC libraries

libifcli.a or libcli.a 62 libifcli.so or iclis09b.so 62 libifdrm.so or idmrs09a.so 62 libthcli.a 62 libthcli.so or iclit09b.so 62

ODBC/CLI driver 41

OLE DB consumer 210

OLE DB provider 210

OLE DB providers

DBTYPE_DBDATE 218

DBTYPE_DBTIME 218

DBTYPE_DBTIMESTAMP 218

olsoctcp 28

onconfig 335, 347

onconfig parameter

dbservername 437

jvpclasspath 335 jvphome 335 jvpjavahome 335 jvpjavalib 335

Index

473

7884IX.fm

jvpjavavm 335

jvplog 341

jvplogfile 335 jvppropfile 335

oninit 16

opaque 9

opaque data type 324, 326, 329

open administration tool 7

operator 327

operator function 326 operator-class function 326

optcompind parameter 17, 443

OUT parameter 167

outgoing parameter 331 outgoing parameters 331

P

packaging file 14

page level lock 429

page locking 430

parallel subquery 18 parallelism 18

parallelizable UDR 326

parsing 134

partition 4

password-based authentication 21

path environment variable 123

path variable 55

persistence 357

persistence data 184 persistence framework 184

persistence object 192

persistent connectivity layer 4

phantom read 435

physbuff configuration parameter 446

physical log image 18

physical-log buffer 446

pipe connection 16

placeholder 85, 302

plain old java objects 192

pluggable authentication modules 21

POJO 192

polymorphism 184

precedence heirarchy 331

prepare statement 18

prepared statement 169

PreparedStatement object 163

preprocessor 9

474

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

primary key 194

priority aging 449

process memory 341

processor affinity 450

processor value unit 3 processor-based pricing 3

program_design_dbs 394

public method 258

publish 392

pure-Java driver 49

pure-Java drivers 150

Q

query optimization 134

query plan 327

query-intensive analytical application 6

R

rails command 383

rake 357

recovery 324

Redbooks Web site 466

Contact us xiii

regsvr32 tool 240

repeatable read 426, 436

resource manager 456

result set 167

role 21

rollback 19, 324, 435

rollback method 267

rollback work statement 135

row and collection functions

ifx_rc_count 103 ifx_rc_create 103 ifx_rc_delete 103 ifx_rc_describe 103 ifx_rc_fetch 103 ifx_rc_free 103 ifx_rc_insert 103 ifx_rc_isnull 103 ifx_rc_setnull 103 ifx_rc_typespec 103 ifx_rc_update 103

rowset 223

R-tree 351

Ruby/Informix Adapter 376

runtime 8

runtime library 32

Draft Document for Review August 23, 2010 10:53 am

S

SBS 92

sbspacename parameter 438

sbspacetemp parameter 439

scaffold command 384

scalability 5, 324

scalable data warehousing 6

schema authorizations 21

sdk_home environment variable 335

secure sockets layer 17 secured connection method 17

security mechanism 21

select 72

selectivity function 326

serial8 78

server definition 28

server instance 16

server name 57

server_locale environment variable 145

service oriented architecture 390

Session.createCiteria() 199

Session.createQuery() 199

Session.delete() method 203

Session.get() 199

Session.load() 199

Session.save() 199

SessionFactory class 196

set 140

set isolation 426 set lock mode 426 set transaction 426

setnet32 utility 27, 39

shared library 63

shared lock 427

shared memory 16, 18

simple logging facade for Java 188

simple object access protocol 411

simple-logging 188

single install 4

single password CSM 17

single-user product version 7

slf4j-api-1.5.8.jar 187

SLFJ 188

SLFJ logger 188

slob method 370

smart blob space 92, 139

smart large object 9

smart large object functions

ifx_lo_alter 93 ifx_lo_close 93 ifx_lo_col_info 93 ifx_lo_create 93 ifx_lo_def_create_spec 93 ifx_lo_open 93

ifx_lo_read 94 ifx_lo_readwithseek 94 ifx_lo_seek 94 ifx_lo_specget_estbytes 94 ifx_lo_specget_extsz 94 ifx_lo_specget_flags 94 ifx_lo_specget_maxbytes 94 ifx_lo_specget_sbspace 94 ifx_lo_specset_estbytes 94 ifx_lo_specset_extsz 94 ifx_lo_specset_flags 94 ifx_lo_specset_maxbytes 94 ifx_lo_specset_sbspace 94 ifx_lo_stat 94 ifx_lo_stat_atime 94 ifx_lo_stat_cspec 94 ifx_lo_stat_ctime 94 ifx_lo_stat_refcnt 94 ifx_lo_stat_size 94 ifx_lo_tell 94 ifx_lo_truncate 94 ifx_lo_write 94

ifx_lo_writewithseek 95

soa_err_log log file 394

SOAP 411

socket connection 16

software deployment 22

source file 122

source files 14

SQL communications area 144

SQL dialect 190

SQL optimization 190

sql_autocommit_off 87

sql_bigint 77–78

sql_bit 77

sql_c_binary 76

sql_ifmx_udt_blob 77 sql_ifmx_udt_clob 77

sql_infx_attr_lo_automatic 101

sql_infx_bigint 77

sql_infx_udt_fixed 76, 78

sql_infx_udt_varying 78 sql_integer 78

sql_interval_day 77

7884IX.fm

Index

475

7884IX.fm

sql_interval_hour 77 sql_interval_month 77 sql_interval_second 77 sql_interval_year 77

sql_longbinary 101

sql_longvarbinary 77, 93

sql_longvarchar 78, 93, 101

sql_timestamp 77

sqlca 144

sqlexec 27

SQLExecDirect() 79

SQLExecDirect() function 79

SQLGetDiagRec() 81

sqlhosts configuration file 25

sqlhosts file 19

sqlidebug trace 116, 146 sqliprt tool 116

sqlj.zip 47 sqlj4.zip 47

SQLSetConnectAttr() 87

SQLSTATE 144

stacksize parameter 442

standard data type 324

startup cost 330

Statement object 162

static SQL statement 132

statistics function 326

stored procedure 128

structured query language 150

subscribe 392

sysdistrib system catalog table 439

syslangauth table 325

syspgm4gl 396

sysprocauth table 325 sysprocbody table 325 sysprocedures table 325 sysroutinelangs table 325

syssbspacename parameter 439

system catalog table 325

T

table space 438

tar file 24

target_dir 397 target_file 397

temporary space 438 temporary table 438

text export routine 327

476

IBM Informix Developer’s Handbook

Draft Document for Review August 23, 2010 10:53 am

text import routine 327

Text input routine 327 text output routine 327

third-party vendor 9

thread 427

TimeSpan GetTimeSpan() 263

transaction 456

transaction control 324

transaction management 186

transient 203 transient object 203

translation library 58 translation option 58

Type 4 150

type constructor 140

U

UDRManager 12

UDRMetaData 12

UDTManager 12

UDTMetaData 12

uncommitted data 435

unit of work 456

unresolved transaction 461

updatable lock 427

update 72

uselastcommitted 429, 442

user defined data type 328

user thread 451

user-defined aggregate 326

V

validity checking 134

version numbering convention 2

virtual processor 16

virtual server 4

virtual-processor process 345

VMB character 58

void Prepare() 260

vpclass parameter 440, 449

W

w4glc 407

w4glc parameters

check 394

compile 395 deploy 395

Draft Document for Review August 23, 2010 10:53 am

force 395 generate 395 help 395 keep 395 package 395 silent 395 version 395

web 381

web 4GL compiler 407

web server 357

web service description language 397

web service function 414

WEBrick 357

workload 3

workload balancing 20

ws_func 397

WSDL Path 414

wsdl_path 397

X

xa.h 457

XML configuration file 184

XML formatted file 189

XML mapping file 191

XML-based protocol 411

7884IX.fm

Index

477

7884IX.fm

Draft Document for Review August 23, 2010 10:53 am

478

IBM Informix Developer’s Handbook

Back cover

Draft Document for Review August 23, 2010 10:53 am

IBM Informix Developer’s

Handbook

Learn application development with supported APIs, drivers, and interfaces

Understand Informix supported programming environments

Practical examples

IBM Informix is a low-administration, easy-to-use, and embeddable database that is idea for application development. It supports a wide range of development platforms, such as Java, .NET, PHP, and Web services, enabling developers to build database applications in their language of choice. Informix is designed to handle RDBMS data and XML out of the box, and can easily be extended to handle new data sets.

.

This IBM Redbooks publication provides fundamentals of

Informix application development. It covers the Informix

Clients installation and configuration for application development environments. It discusses the skills and techniques for building Informix applications with Java,

ESQL/C, OLE DB, .NET, PHP, Ruby on Rails, DataBlade, and

Hibernate. Code examples are used to demonstrate how to develop an Informix application with various drivers, APIs, and interfaces. This book also provides application development trouble-shooting and considerations for performance.

®

®

INTERNATIONAL

TECHNICAL

SUPPORT

ORGANIZATION

BUILDING TECHNICAL

INFORMATION BASED ON

PRACTICAL EXPERIENCE

IBM Redbooks are developed by the IBM International Technical

Support Organization. Experts from IBM, Customers and

Partners from around the world create timely technical information based on realistic scenarios. Specific recommendations are provided to help you implement IT solutions more effectively in your environment.

For more information:

ibm.com/redbooks

SG24-7884-00 ISBN

advertisement

Was this manual useful for you? Yes No
Thank you for your participation!

* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project

advertisement

Table of contents