Informix Handbook
Informix Handbook
Informix Handbook
SG24-7884-00
IBM Informix
Developers 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
7884edno.fm
SG24-7884-00
7884edno.fm
Note: Before using this information and the product it supports, read the information in
Notices on page ix.
7884TOC.fm
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
iii
7884TOC.fm
iv
7884TOC.fm
Contents
7884TOC.fm
vi
7884TOC.fm
Contents
vii
7884TOC.fm
viii
7884spec.fm
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
7884spec.fm
Trademarks
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
Rational
Redbooks
Redpaper
Redbooks (logo)
UC2
WebSphere
7884pref.fm
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.
xi
7884pref.fm
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
7884pref.fm
Emma Jacobs
International Technical Support Organization, Rochester Center
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:
redbooks@us.ibm.com
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
xiv
7884ch01.fm
Chapter 1.
7884ch01.fm
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):
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
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
7884ch01.fm
Licensing term
Defined
Authorized User
Single Install
Concurrent Session
Install
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.
7884ch01.fm
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
7884ch01.fm
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.
7884ch01.fm
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.
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.
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:
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
7884ch01.fm
10
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 class
java.io.Serializable
com.informix.jdbcx.IfxCoreDataSource
java.sql.Connection
com.informix.jdbc.IfmxConnection
javax.sql.ConnectionEventListener
com.informix.jdbcx.IfxConnectionEventListener
javax.sql.ConnectionPoolDataSource
com.informix.jdbcx.IfxConnectionPoolDataSource
javax.sql.DataSource
com.informix.jdbcx.IfxDataSource
javax.sql.PooledConnection
com.informix.jdbcx.IfxPooledConnection
javax.sql.XADataSource
com.informix.jdbcx.IfxXADataSource
java.sql.ParameterMetaData
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.
11
7884ch01.fm
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
java.lang.object
UDTManager
java.lang.object
UDTMetaData
java.lang.object
UDRManager
java.lang.object
UDRMetaData
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
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.
13
7884ch01.fm
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/.
14
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.
15
7884ch01.fm
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.
16
7884ch01.fm
17
7884ch01.fm
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:
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
7884ch01.fm
19
7884ch01.fm
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.
20
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 engines 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.
21
7884ch01.fm
22
7884ch02.fm
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.
23
7884ch02.fm
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
7884ch02.fm
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.
25
7884ch02.fm
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
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.
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.
27
7884ch02.fm
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.
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
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 ...
...
29
7884ch02.fm
30
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
31
7884ch02.fm
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
7884ch02.fm
33
7884ch02.fm
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
Versions
IBM Informix
7.25
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
7884ch02.fm
Remember to set the DISPLAY environment variable to the window which you
want to project the Installation. Figure 2-5 shows the Welcome panel.
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.
35
7884ch02.fm
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
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.
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.
37
7884ch02.fm
7. Figure 2-10 shows that the Installation is 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
7884ch02.fm
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.
39
7884ch02.fm
40
7884ch02.fm
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
41
7884ch02.fm
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:
The PHP driver path and file names in the IBM Data Server Driver
Packages are
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
7884ch02.fm
http://www.php.net/manual/en/install.pecl.phpize.php
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
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.
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.
43
7884ch02.fm
44
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
45
7884ch02.fm
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.
46
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.
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
47
7884ch02.fm
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
48
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
49
7884ch02.fm
4. Review the information on the summary panel (Figure 2-18 on page 51) and
continue to complete the installation.
50
7884ch02.fm
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
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%
At this stage you are ready to develop a Java application using JDBC.
51
7884ch02.fm
52
7884ch03.fm
Chapter 3.
53
7884ch03.fm
Versions
IBM Informix
10.0,11.10,11.50
7.25
Windows configuration
On a Windows machine the ODBC drivers is automatically registered within the
system during the Informix installation process.
54
7884ch03.fm
IBM INFORMIX ODBC DRIVER (64-bit): for the Windows 64-bit driver. See
Figure 3-2 on page 56.
55
7884ch03.fm
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
7884ch03.fm
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
Server name
Host name
Service
Protocol
Database
You can set optional configuration parameters in the Environment and Advanced
tabs (Figure 3-4 on page 58).
57
7884ch03.fm
58
Parameter
Description
Client Locale
Database Locale
Translation Library
Translation Option
Cursor Behavior
VMB Character
Isolation Level
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.
Description
Open-Fetch-Close Optimization
59
7884ch03.fm
Parameter
Description
Insert Cursors
Scrollable Cursors
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
7884ch03.fm
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.
61
7884ch03.fm
Description
libifcli.a or libcli.a
libifcli.so or iclis09b.so
libthcli.a
libthcli.so or iclit09b.so
libifdrm.so or idmrs09a.so
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.
For more information about the sqlhosts file, refer to the Client/Server
Communications manual at:
62
7884ch03.fm
http://publib.boulder.ibm.com/infocenter/idshelp/v115/topic/com.ibm.admin.doc/i
ds_admin_0158.htm
Description
Driver
Setup
APILevel
ConnectFunctions
DriverODBCVer
63
7884ch03.fm
Keyword
Description
FileUsage
SQLLevel
64
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
Description
Driver
Description
DSN description
Database
Database name
LogonID
User Id
pwd
Password
Server
Database server
CLIENT_LOCALE
DB_LOCALE
TRANSLATIONDLL
CURSORBEHAVIOR
DefaultUDTFetchType
ENABLESCROLLABLECURSORS
ENABLEINSERTCURSORS
OPTIMIZEAUTOCOMMIT
NEEDODBCTYPESONLY
OPTOFC
REPORTKEYSETCURSORS
FETCHBUFFERSIZE
DESCRIBEDECIMALFLOATPOINT
USESERVERDBLOCALE
DONOTUSELVARCHAR
65
7884ch03.fm
Keyword
Description
REPORTCHARCOLASWIDECHARCOL
ISOLATIONLEVEL
UNICODE
TRACE
TRACEFILE
TRACEDLL
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
7884ch03.fm
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.
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.
67
7884ch03.fm
68
7884ch03.fm
Description
Hostname
Port
Protocol
Database
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
69
7884ch03.fm
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
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
7884ch03.fm
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)
>
71
7884ch03.fm
72
7884ch03.fm
73
7884ch03.fm
hdbc;
henv;
SQLRETURN
SQLCHAR
SQLCHAR
SQLSMALLINT
rc = 0;
connStrIn[1000];
connStrOut[1000];
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
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
75
7884ch03.fm
StatementHandle,
ParameterNumber,
InputOutputType,
ValueType,
ParameterType,
ColumnSize,
DecimalDigits,
ParameterValuePtr,
BufferLength,
*StrLen_or_IndPtr);
/*
/*
/*
/*
/*
/*
/*
/*
/*
/*
hstmt */
ipar */
fParamType */
fCType */
fSqlType */
cbColDef */
ibScale */
rgbValue */
cbValueMax */
pcbValue */
76
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
BIGINT
SQL_INFX_BIGINT
BIGSERIAL
SQL_INFX_BIGINT
BLOB
SQL_IFMX_UDT_BLOB
BOOLEAN
SQL_BIT
BYTE
SQL_LONGVARBINARY
CLOB
SQL_IFMX_UDT_CLOB
DATETIME
SQL_TIMESTAMP
DISTINCT
Any
IDSSECURITYLABEL
INT8
SQL_BIGINT
INTERVAL DAY
SQL_INTERVAL_DAY
SQL_INTERVAL_DAY_TO_HOUR
SQL_INTERVAL_DAY_TO_MINUTE
SQL_INTERVAL_DAY_TO_SECOND
INTERVAL HOUR
SQL_INTERVAL_HOUR
SQL_INTERVAL_HOUR_TO_MINUTE
SQL_INTERVAL_HOUR_TO_SECOND
INTERVAL MINUTE
SQL_INTERVAL_MINUTE
SQL_INTERVAL_MINUTE _TO_SECOND
INTERVAL MONTH
SQL_INTERVAL_MONTH
INTERVAL SECOND
SQL_INTERVAL_SECOND
INTERVAL YEAR
SQL_INTERVAL_YEAR
SQL_INTERVAL_YEAR_TO_MONTH
77
7884ch03.fm
Informix SQL
Any
LVARCHAR
SQL_VARCHAR
MONEY
SQL_DECIMAL
NCHAR
SQL_CHAR
NVARCHAR
SQL_VARCHAR
OPAQUE (fixed)
SQL_INFX_UDT_FIXED
OPAQUE (varying)
SQL_INFX_UDT_VARYING
ROW
Any
SERIAL
SQL_INTEGER
SERIAL8
SQL_BIGINT
TEXT
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
7884ch03.fm
rc = 0;
connStrIn[1000];
connStrOut[1000];
connStrOutLen;
int
SQLCHAR
sqllen;
*sqlstmt;
79
7884ch03.fm
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]);
80
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!
81
7884ch03.fm
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
SQLCHAR
SQLCHAR
SQLSMALLINT
SQLCHAR
SQLCHAR
SQLCHAR
SQLLEN
SQLLEN
rc = 0;
connStrIn[1000];
connStrOut[1000];
connStrOutLen;
sqlstmt[100];
code[2+1];
sname[15+1];
lcode=0;
lsname=0;
82
7884ch03.fm
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>
83
7884ch03.fm
rc = 0;
connStrIn[1000];
connStrOut[1000];
connStrOutLen;
sqlstmt[100];
inputcode[2+1];
code[2+1];
sname[15+1];
lcode = 0;
lsname = 0;
datatype, decimaldigits, nullable;
paramsize;
84
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>
The 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.
85
7884ch03.fm
rc = 0;
connStrIn[1000];
connStrOut[1000];
connStrOutLen;
sqlstmt[100];
errorn[20+1];
result[100+1];
lresult = 0;
86
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.
87
7884ch03.fm
rc = 0;
connStrIn[1000];
connStrOut[1000];
connStrOutLen;
sqlstmt[100];
cnum = 101;
datatype, decimaldigits, nullable;
paramsize;
88
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)
Using: '101'
Executed SQL Statement:
INSERT INTO orders(order_num,order_date,customer_num)
Using: '102'
Executed SQL Statement:
INSERT INTO orders(order_num,order_date,customer_num)
Using: '103'
Executed SQL Statement:
INSERT INTO orders(order_num,order_date,customer_num)
Using: '104'
Transaction Rolled back
VALUES (0,current,?)
VALUES (0,current,?)
VALUES (0,current,?)
VALUES (0,current,?)
C:\work>
Distributed transactions
On Windows you can run a distributed transaction using the Microsoft
Distributed Transaction Coordinator (MSDTC) service.
89
7884ch03.fm
rc = 0;
connStrIn[100],connStrIn2[100];
connStrOut[1000];
connStrOutLen;
sqlstmt[100];
cnum = 101;
datatype, decimaldigits, nullable;
paramsize;
90
7884ch03.fm
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
91
7884ch03.fm
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 test_2 are both created as
System-DSN.
92
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.
Name
Description
lofd
file descriptor
loptr
pointer structure
lospec
specification structure
lostat
status structure
Description
ifx_lo_alter(loptr, lospec)
ifx_lo_close(lofd)
ifx_lo_col_info(colname, lospec)
ifx_lo_def_create_spec(lospec)
93
7884ch03.fm
94
Function
Description
ifx_lo_read(lofd, buf)
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)
Writes data
7884ch03.fm
Function
Description
95
7884ch03.fm
96
7884ch03.fm
*/
97
7884ch03.fm
98
7884ch03.fm
99
7884ch03.fm
100
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);
}
hdbc;
henv;
hstmt;
dsn="demo_on";
sqlstmt[128];
str[128];
str_len = SQL_NTS;
101
7884ch03.fm
BufferLength = 128;
int_val;
rc = 0;
102
7884ch03.fm
Description
ifx_rc_count()
ifx_rc_create()
ifx_rc_delete()
ifx_rc_describe()
ifx_rc_fetch()
ifx_rc_free()
ifx_rc_insert()
ifx_rc_isnull()
ifx_rc_setnull()
ifx_rc_typespec()
ifx_rc_update()
103
7884ch03.fm
104
7884ch03.fm
105
7884ch03.fm
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.
>
106
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);
107
7884ch03.fm
108
7884ch03.fm
109
7884ch03.fm
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
7884ch03.fm
rc = 0;
connStrIn[1000];
connStrOut[1000];
connStrOutLen;
int
SQLCHAR
sqllen;
*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);
111
7884ch03.fm
112
7884ch03.fm
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.
113
7884ch03.fm
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.
114
7884ch03.fm
99c-db8 EXIT
HSTMT
UWORD
SWORD
SWORD
SWORD
SQLULEN
SWORD
PTR
SQLLEN
SQLLEN *
rccreate
SQLBindParameter
01D51DC0
2
1 <SQL_PARAM_INPUT>
1 <SQL_C_CHAR>
1 <SQL_CHAR>
25
0
0x002CFEC8
0
0x002CFF50 (-3)
...
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.
115
7884ch03.fm
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
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
7884ch03.fm
C->S (14)
SQ_PROTOCOLS
SQ_EOT
S->C (14)
SQ_PROTOCOLS
SQ_EOT
C->S (90)
SQ_INFO
SQ_EOT
S->C (2)
C->S (4)
S->C (10)
SQ_XACTSTAT
SQ_EOT
C->S (4)
S->C (10)
SQ_XACTSTAT
SQ_EOT
C->S (22)
SQ_PREPARE
# values: 0
117
7884ch03.fm
-201
0
1
"" [0]
SQ_EOT
C:\work>
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
22/06/2010
22/06/2010
18:50
<DIR>
.
18:50
<DIR>
..
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
7884ch03.fm
0000
0010
0020
0030
0040
0050
0060
0070
0080
0090
00A0
00B0
00C0
EXCSAT RQSDSS
0 1 2 3 4 5 6 7 8 9 A B C D E F
00C3D041000100BD 10410080115EA289
949793856DA29893 6DA685999996994B
85A7F0F6F1F4F0C4 F9F4F0F0F0000000
0000000000000000 0000000000000000
0000000000000000 000000000060F0F0
F0F1C1C4D4C9D5C9 E2E3D9C1E3D6D940
4040404040404040 4040404040404040
E2E3D6D9C5E26DC4 F0C4C2F240404040
4040404040404040 40F0001814041403
000A2407000A1474 0005240F00081440
0009000B1147D8C4 C2F261D5E3000A11
6DC4E4C2C9E3D600 0C115AE2D8D3F0F9
F0F7F0
(ASCII)
0123456789ABCDEF
...A.....A...^..
....m...m......K
................
................
.............`..
...............@
@@@@@@@@@@@@@@@@
......m.....@@@@
@@@@@@@@@.......
..$....t..$....@
.....G....a.....
m.........Z.....
...
(EBCDIC)
0123456789ABCDEF
.C}..........;si
mple_sql_werror.
ex06140D94000...
................
.............-00
01ADMINISTRATOR
STORES_D0DB2
0......
...............
......QDB2/NT...
_DUBITO...]SQL09
070
119
7884ch03.fm
120
7884ch04.fm
Chapter 4.
121
7884ch04.fm
122
7884ch04.fm
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:
123
7884ch04.fm
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
7884ch04.fm
125
7884ch04.fm
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
CC
HP
aC++
Windows
AIX
xlc
Open Source
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
7884ch04.fm
Environment variable
AIX
LIBPATH
Solaris
LD_LIBRARY_PATH
HP-UX
SHLIB_PATH
Mac OS X
DYLD_LIBRARY_PATH
Linux
LD_LIBRARY_PATH
Windows
LIB
C shell:
setenv LD_LIBRARY_PATH $INFORMIXDIR/lib:$LD_LIBRARY_PATH
127
7884ch04.fm
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
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
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;
129
7884ch04.fm
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;
<stdio.h>
<string.h>
include sqlca;
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]
float ship_charge[5]
char *ship_duration[5]
= {"08/01/77","08/02/77","08/03/77","08/04/77","08/05/77"};
= {10000.59,590000.32,345577.12,987098.32,876893.22};
= {"10:10:10","11:11:11","22:22:22","33:33:33","44:44:44"};
130
7884ch04.fm
bigserial,
char(15),
char(15),
char(30),
boolean,
lvarchar
131
7884ch04.fm
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
132
7884ch04.fm
OUTPUT:
Enter the customer number [101-128] to see the names:102
SQLCODE=0
Data found
Last Name
Carole
First Name
Sadle
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)
{
133
7884ch04.fm
OUTPUT:
Enter customer number [103 - 128] : 108
Ludwig Pauli
Carole Sadler
Philip Currie
Anthony Higgins
Raymond Vector
George Watson
Charles Ream
134
7884ch04.fm
OUTPUT:
250.000000
960.000000
240.000000
20.000000
840.000000
255.000000
979.200012
244.800003
20.400000
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.
135
7884ch04.fm
<stdio.h>
"sqlca.h";
"sqlhdr.h";
"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
EXEC
EXEC
EXEC
EXEC
EXEC
EXEC
EXEC
EXEC
EXEC
SQL
SQL
SQL
SQL
SQL
SQL
SQL
SQL
SQL
SQL
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
7884ch04.fm
ESQL/C
BOOLEAN
boolean
BYTE
loc_t
LVARCHAR
lvarchar
NCHAR(n)
NVARCHAR(m)
SERIAL8
int8 or ifx_int8_t
TEXT
loc_t
BLOB
ifx_lo_t
CLOB
ifx_lo_t
LIST(e)
collection
MULTISET(e)
collection
ROW(...)
row
SET(e)
collection
For a complete list of all the Informix SQL to ESQL/C data type mapping refer to
the IBM Informix ESQL/C Programmers Manual at
http://publib.boulder.ibm.com/infocenter/idshelp/v115/index.jsp?topic=/com.ibm.
esqlc.doc/sii03147680.htm
137
7884ch04.fm
2 gigabytes
4 terabytes
Data accessibility
No random access to
data
Library functions
provide access that is
similar to accessing an
operating-system file.
You can access
specified portions of the
smart large object.
Data logging
138
7884ch04.fm
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
$include
$include
$include
<stdio.h>
"sqlca.h";
"sqlhdr.h";
"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;
139
7884ch04.fm
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
140
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
EXEC
EXEC
EXEC
EXEC
EXEC
SQL
SQL
SQL
SQL
SQL
SQL
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)
141
7884ch04.fm
142
7884ch04.fm
143
7884ch04.fm
144
7884ch04.fm
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
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.
145
7884ch04.fm
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.
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
C->S (16)
SQ_DBOPEN
7884ch04.fm
"stores7" [7]
NOT EXCLUSIVE
SQ_EOT
S->C (28)
SQ_DONE
0x15
0
0
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
...
147
7884ch04.fm
148
7884ch05.fm
Chapter 5.
149
7884ch05.fm
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
7884ch05.fm
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
151
7884ch05.fm
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.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
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
demo_on_tcp
demo_on_drda
onipcshm
onsoctcp
drsoctcp
kefka
kefka
kefka
demo_on
9088
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.
153
7884ch05.fm
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
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!
The name of the Data Server JDBC driver in the connection string should be
jdbc:ids.
155
7884ch05.fm
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-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
7884ch05.fm
JDBC Type
Informix Type
long
BIGINT
byte[]
BINARY, VARBINARY
BYTE
boolean
BIT
BOOLEAN
java.sql.Date
DATE
DATE
java.math.BigDecimal
DECIMAL
DECIMAL
byte[]
LONGVARBINARY
BYTE or BLOB
java.lang.String
LONGVARCHAR
TEXT or CLOB
java.math.BigDecimal
NUMERIC
MONEY
float, java.lang.Float
REAL
SMALLFLOAT
java.sql.Time
TIME
DATETIME HOUR TO
SECOND
java.sql.Timestamp
TIMESTAMP
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 Programmers Guide at
http://publib.boulder.ibm.com/infocenter/idshelp/v115/topic/com.ibm.jdbc_pg.doc
/sii-xc-21122.htm#sii-xc-21122
157
7884ch05.fm
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
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.
158
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]
Description
DB_LOCALE
CLIENT_LOCALE
INFORMIXCONTIME
SQLIDEBUG
STMT_CACHE
IFX_ISOLATION_LEVEL
159
7884ch05.fm
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
160
7884ch05.fm
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.
161
7884ch05.fm
Method
CLIENT_LOCALE
DB_LOCALE
IFX_ISOLATION_LEVEL
IFX_LOCK_MODE_WAIT
SQLIDEBUG
STMT_CACHE
USEV5SERVER
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
Programmers 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
162
7884ch05.fm
163
7884ch05.fm
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.*;
164
7884ch05.fm
165
7884ch05.fm
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.*;
166
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>
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,
167
7884ch05.fm
168
7884ch05.fm
Batch Inserts
Resultset Metadata
Informix BIGSERIAL data type
Informix Smart Large Objects
Secure Socket Layer
169
7884ch05.fm
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)
170
7884ch05.fm
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();
}
}
171
7884ch05.fm
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
7884ch05.fm
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
173
7884ch05.fm
174
7884ch05.fm
175
7884ch05.fm
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
176
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.
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
177
7884ch05.fm
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
7884ch05.fm
179
7884ch05.fm
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)
...
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
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.
You can run the trace through the sqliprint utility to render it to text form.
181
7884ch05.fm
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
7884ch06.fm
Chapter 6.
183
7884ch06.fm
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
7884ch06.fm
185
7884ch06.fm
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
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
187
7884ch06.fm
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
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
7884ch06.fm
CLASSPATH=$CLASSPATH:/work/lib/commons-collections-3.1.jar
CLASSPATH=$CLASSPATH:/work/lib/dom4j-1.6.1.jar
CLASSPATH=$CLASSPATH:/work/lib/hibernate-jpa-2.0-api-1.0.0.Final.jar
CLASSPATH=$CLASSPATH:/work/lib/hibernate3.jar
CLASSPATH=$CLASSPATH:/work/lib/javassist-3.9.0.GA.jar
CLASSPATH=$CLASSPATH:/work/lib/jta-1.1.jar
CLASSPATH=$CLASSPATH:/work/lib/slf4j-api-1.6.1.jar
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
189
7884ch06.fm
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"/>
190
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
191
7884ch06.fm
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
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
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>
193
7884ch06.fm
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
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.
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.
195
7884ch06.fm
196
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.
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]);
197
7884ch06.fm
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>
Column name
Type
id
int8
code
varchar(255)
sname
varchar(255)
> SELECT * FROM states;
198
Nulls
no
yes
yes
7884ch06.fm
1
AZ
Arizona
1 row(s) retrieved.
>
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
import
import
import
import
java.util.List;
org.hibernate.HibernateException;
org.hibernate.Session;
org.hibernate.Transaction;
org.hibernate.criterion.*;
199
7884ch06.fm
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
7884ch06.fm
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
import
import
import
java.util.List;
org.hibernate.HibernateException;
org.hibernate.Session;
org.hibernate.Transaction;
201
7884ch06.fm
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
import
import
import
java.util.*;
org.hibernate.*;
javax.persistence.*;
org.hibernate.criterion.*;
202
7884ch06.fm
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;
203
7884ch06.fm
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
7884ch06.fm
205
7884ch06.fm
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
7884ch06.fm
getSessionFactory().close();
}
}
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
207
7884ch06.fm
208
7884ch07.fm
Chapter 7.
209
7884ch07.fm
DLL
CLSID
ifxoledbc
iifxoledbc.dll
{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
Versions
IBM Informix
10.0,11.10,11.50
210
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.
211
7884ch07.fm
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
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.
213
7884ch07.fm
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 select * from
state.
214
7884ch07.fm
Description
IAccessor
IColumnsInfo
ICommand
Execute commands
IDBCreateCommand
IDBCreateSession
IDBDataSourceAdmin
IDBProperties
IErrorLookup
IGetDataSource
IRowsetIdentity
ISessionProperties
ITransaction
215
7884ch07.fm
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
Password
Client_locale
Db_locale
UNICODE
decasr8
RSASWS or
REPORTSTRINGASWSTRING
FBS or FETCHBUFFERSIZE
A typical connection string for the IBM Informix OLE DB Provider looks like:
216
7884ch07.fm
The connection details about the Informix server must be stored in the registry
using the Setnet32 tool included in Informix Client SDK.
BIGINT
DBTYPE_I8
BIGSERIAL
DBTYPE_I8
BLOB
DBTYPE_BYTES
BOOLEAN
DBTYPE_BOOL
BYTE
DBTYPE_BYTES
CLOB
DBTYPE_STR
DATETIME
DBTYPE_DBDATE, DBTYPE_DBTIME,
DBTYPE_DBTIMESTAMP
DECIMAL
DBTYPE_NUMERIC
DISTINCT
FLOAT
DBTYPE_R8
INT8
DBTYPE_I8
INTERVAL
LIST
DBTYPE_VARIANT
LVARCHAR
DBTYPE_STR
DBTYPE_CY
DBTYPE_NUMERIC
217
7884ch07.fm
Informix SQL
MULTISET
DBTYPE_VARIANT
Named ROW
DBTYPE_VARIANT
NCHAR
DBTYPE_STR
OPAQUE
DBTYPE_BYTES
SERIAL
DBTYPE_I4
SERIAL8
DBTYPE_I8
SET
DBTYPE_VARIANT
TEXT
DBTYPE_STR
Unnamed ROW
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
DBTYPE_DBDATE
DBTYPE_DBTIME
DBTYPE_DBTIMESTAMP
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
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
219
7884ch07.fm
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()
Clean up.
220
7884ch07.fm
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;
221
7884ch07.fm
222
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()
223
7884ch07.fm
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
IUnknown
ITransactionJoin
ICommandText
IOpenRowset
IColumnsInfo
*pIDBInitialize;
*pSession;
*pITransactionJoin;
*pCommandText;
*pIOpenRowset;
*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
_bstr_t
_bstr_t
bstrDsnName = "stores_demo@demo_on";
bstrUserName = "informix";
bstrPassWord = "password";
_bstr_t
TableName = L"customer";
CoInitialize( NULL );
// Instantiate a data source object
224
7884ch07.fm
225
7884ch07.fm
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
226
Length
3
129
129
3
129
131
129
7884ch07.fm
4
1
32767
4
32767
19
1
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
_ConnectionPtr
_variant_t
long
int
spRS;
spCON;
varBLOB;
lDataLength = 0;
nrows=3;
227
7884ch07.fm
228
7884ch07.fm
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;
229
7884ch07.fm
*pSession;
IDBProperties*
DBPROP
DBPROPSET
IDBCreateSession
pIDBProperties;
InitProperties[4];
rgInitPropSet;
*pCreateSession = NULL;
IErrorInfo
IErrorInfo
IErrorRecords
ISupportErrorInfo
*pErrorInfo = NULL;
*pErrorInfoRec = NULL;
*pErrorRecords = NULL;
*pSupportErrorInfo = NULL;
ULONG
BSTR
BSTR
i,ulNumErrorRecs;
bstrDescriptionOfError = NULL;
bstrSourceOfError = NULL;
_bstr_t
_bstr_t
_bstr_t
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
7884ch07.fm
//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
231
7884ch07.fm
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
7884ch07.fm
WScript.Echo cr.fields("sname")
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>
233
7884ch07.fm
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>
234
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.
235
7884ch07.fm
236
7884ch07.fm
237
7884ch07.fm
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
7884ch07.fm
Figure 7-5 shows the output for the previous SQL script.
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
239
7884ch07.fm
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
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>
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.
Reason
Most common reason for these errors is due to the invalid parameters in the
connection string or the invalid connectivity information.
241
7884ch07.fm
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
UserID, UID
Password
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.
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
7884ch07.fm
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
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
243
7884ch07.fm
53C Exit
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:
A44:
A44:
A44:
A44:
A44:
A44:
A44:
A44:
A44:
A44:
A44:
A44:
A44:
A44:
A44:
A44:
A44:
A44:
A44:
53C
53C
53C
53C
53C
53C
53C
53C
53C
53C
53C
53C
53C
53C
53C
53C
53C
53C
53C
53C
Enter
Enter
Enter
Exit
Enter
Exit
Enter
Enter
Exit
Enter
Enter
Exit
Enter
Enter
Exit
Enter
Enter
Exit
Enter
Enter
Datasrc::QueryInterface
Datasrc::QueryInterface
Datasrc::AddRef
Object Address: 0x032CC370 hr=2
Datasrc::Release
Object Address: 0x032CC370 hr=1
Datasrc::QueryInterface
Datasrc::XIDBProperties::SetProperties
Object Address: 0x032CC38C hr=0
Datasrc::QueryInterface
Datasrc::XIDBProperties::SetProperties
Object Address: 0x032CC38C hr=0
Datasrc::QueryInterface
Datasrc::XIDBInitialize::Initialize
Object Address: 0x032CC384 hr=0
Datasrc::QueryInterface
Datasrc::XIDBProperties::GetProperties
Object Address: 0x032CC38C hr=0
Datasrc::QueryInterface
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
7884ch07.fm
245
7884ch07.fm
Number
Number
Number
Number
of non-blob put
of non-blob fetch
of
blob put
of
blob fetch
=
=
=
=
0,
1,
0,
0,
averge
averge
averge
averge
size
size
size
size
of
of
of
of
each
put is 0.000000
each fetch is 25.000000
each
put is 0.000000
each fetch is 0.000000
246
7884ch08.fm
Chapter 8.
247
7884ch08.fm
248
7884ch08.fm
Assembly version
1.1
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.
249
7884ch08.fm
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
9.0.0.2
IBM.Data.Informix
9.0.0.2
250
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
251
7884ch08.fm
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
7884ch08.fm
C:\work>
Description
Default
Client Locale,
Client_Locale
en_us.1252
Connection Lifetime
Database, DB
Database to connect to
Database Locale,
DB_LOCALE
en_US.819
DELIMIDENT
Enlist
true
Exclusive, XCL
No
Host
localhost
100
253
7884ch08.fm
Attribute
Description
Default
Optimize OpenFetchClose,
OPTOFC
32767
Password, PWD
false
Pooling
true
Protocol, PRO
Communication protocol
Server
Service
Skip Parsing
UserDefinedTypeFormat
Login account.
false
false
254
Attribute
Description
Default Value
ConnectTimeout,
Connect Timeout
Connection Lifetime
60
7884ch08.fm
Attribute
Description
Default Value
Database, DB
Enlist
true
Password, PWD
false
Pooling
true
Query Timeout
Server
Login account
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.
255
7884ch08.fm
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>
256
For DataReader
For DataSet
BIGINT
Int64
Int64
BIGSERIAL
Int64
Int64
BLOB
IfxBlob
Byte[]
BOOLEAN
Boolean
Boolean
BYTE
Byte[]
Byte[]
CLOB
IfxClob
Byte[]
String
String
7884ch08.fm
For DataReader
For DataSet
IfxDecimal
Decimal
IfxDecimal
Double
DECIMAL (p>28)
IfxDecimal
String
IDSSECURITYLABEL
Int64[]
Int64[]
INT8
Int64
Int64
INTERVAL, year-month
IfxMonthSpan
String
INTERVAL, day-fraction
IfxTimeSpan
TimeSpan
LVARCHAR
String
String
MONEY
IfxDecimal
NCHAR
String
String
SERIAL
nt32
Int32
SERIAL8
Int64
Int64
TEXT
String
String
LVARCHAR
IfxString
String
BLOB, BYTE
IfxBlob
Byte[]
CLOB, TEXT
IfxClob
String
BOOLEAN, SMALLINT
IfxInt16
Int16
IfxInt64
Int64
IfxDecimal
Decimal
IfxDouble
Double
DECIMAL (p>28)
IfxDouble
Double
257
7884ch08.fm
MONEY
IfxDecimal
Decimal
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()
void ChangeDatabase(String)
void EnlistTransaction()
IfxTransaction
BeginTransaction()
BeginTransaction(IsolationLevel)
IfxCommand CreateCommand()
IfxBlob GetIfxBlob()
IfxClob GetIfxClob()
258
7884ch08.fm
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.
259
7884ch08.fm
Description
Int32 ExecuteNonQuery()
IfxDataReader ExecuteReader()
ExecuteReader(DataCommandBehavior
behavior)
Object ExecuteScalar()
void Cancel()
IfxParameter CreateParameter()
void Prepare()
260
7884ch08.fm
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)
IDataParameter GetFillParameters()
Int32 Update(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;
261
7884ch08.fm
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
7884ch08.fm
Description
Boolean GetBoolean()
TimeSpan GetTimeSpan()
IfxBlob GetIfxBlob()
IfxClob GetIfxClob()
IfxDateTime GetIfxDateTime()
IfxDecimal GetIfxDecimal
IfxMonthSpan
GetIfxMonthSpan
IfxTimeSpan GetIfxTimeSpan
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) {
263
7884ch08.fm
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
264
Property
Type
Description
Message
String
Text message
7884ch08.fm
Property
Type
Description
NativeError
Int32
SQLState
String
IfxParameter
The IfxParameter class is used to pass parameters to the IfxCommand method.
IfxParameters are stored as a collection in a IfxParameterCollection object.
265
7884ch08.fm
Type
Description
DbType
DbType
Direction
ParameterDirection
IfxType
IfxType
IsNullable
Boolean
ParameterName
String
SourceColumn
String
SourceVersion
DataRowVersion
Value
Object
266
7884ch08.fm
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);
}
}
}
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 {
267
7884ch08.fm
You can specify the following Isolation levels with the BeginTransaction()
method:
ReadUncommitted
ReadCommitted
RepeatableRead
Serializable
System;
System.Data;
IBM.Data.Informix;
System.Transactions;
class sample {
static void Main(string[] args) {
IfxConnection conn;
268
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);
}
}
}
269
7884ch08.fm
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.
Type
Description
EstimatedSize
Int64
ExtentSize
Int32
Flags
Int32
IsNull
Boolean
IsOpen
Boolean
LastAccessTime
Int32
LastChangeTime
Int32
LastModificationTime
Int32
MaxBytes
Int64
Position
Int64
ReferenceCount
Int32
SBSpace
String
Size
Int64
Table 8-14 lists the available public methods from IfxClob and IfxBlob classes.
Table 8-14 Public methods of lfxClob and lfxBlob
270
Method
Description
void Open(mode)
IfxSmartLOBLocator GetLocator()
7884ch08.fm
Method
Description
void Truncate(offset)
void Release()
void Close()
System;
System.IO;
System.Data;
IBM.Data.Informix;
class sample {
271
7884ch08.fm
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
7884ch08.fm
Execute the SQL Statement and retrieve the large object column.
Open the large object.
Read from the large object into an application buffer.
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();
273
7884ch08.fm
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);
...
274
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());
275
7884ch08.fm
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
276
Property
Type
Description
Date
IfxDateTime
Day
Int32
EndTimeUnit
IfxTimeUnit
Hour
Int32
MaxValue
IfxDateTime
7884ch08.fm
Property
Type
Description
Millisecond
Int32
MinValue
IfxDateTime
Minute
Int32
Month
Int32
Now
IfxDateTime
Second
Int32
StartTimeUnit
IfxTimeUnit
Ticks
Int64
Today
IfxDateTime
Year
Int32
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)
AddDays(days)
AddMilliseconds(milliseconds)
AddMinutes(minutes)
AddMonths(months)
AddSeconds(seconds)
AddYears(years)
Compare(ifxDT1, ifxDT1)
CompareTo(obj)
DaysInMonth(year, month)
Equals(ifxDT1, ifxDT2)
GreaterThan(ifxDT1, ifxDT2)
GreaterThanOrEqual(ifxDT1, ifxDT2)
LessThan(ifxDT1, ifxDT2)
277
7884ch08.fm
Method
Description
LessThanOrEqual(ifxDT1, ifxDT2)
NotEquals(ifxDT1, ifxDT2)
Parse(dateTimeStr)
Parse(dateTimeStr, start, end)
Parse(dateTimeStr, format, start, end)
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
7884ch08.fm
Console.WriteLine(e.Message);
}
}
}
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
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();
279
7884ch08.fm
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
280
Property
Type
Description
IfxDecimal
Irrational number e.
IsFloating
Boolean
IsNull
Boolean
Whether is NULL.
IsPositive
Boolean
Whether is positive
MaxPrecision
Byte
MaxValue
IfxDecimal
MinusOne
IfxDecimal
-1.
MinValue
IfxDecimal
Null
IfxDecimal
Null.
One
IfxDecimal
1.
7884ch08.fm
Property
Type
Description
Pi
IfxDecimal
Zero
IfxDecimal
0.
Table 8-18 contains the description for the IfxDecimal public methods.
Table 8-18 Public methods of IfxDecimal
Method
Description
Abs(IfxDec)
Add(IfxDec1, IfxDec2)
Ceiling(IfxDec)
Clone()
Compare(IfxDec1, IfxDec2)
CompareTo(obj)
Divide(Dividend, Divisor)
Equals(obj)
Equal
Equals(IfxDec1, IfxDec2)
Floor(IfxDec)
GreaterThan(IfxDec1, IfxDec2)
GreaterThanOrEqual(IfxDec1,IfxDec
2)
LessThan(IfxDec1, IfxDec2)
LessThanOrEqual(IfxDec1, IfxDec2)
Max(IfxDec1, IfxDec2)
Min(IfxDec1, IfxDec2)
Modulo(a, b)
Multiply(IfxDec1, IfxDec2)
Negate(IfxDec)
NotEquals(IfxDec1, IfxDec2)
True if IfxDec1<>IfxDec2
Parse(DecString)
281
7884ch08.fm
Method
Description
Remainder(a, b)
Round(IfxDec1, FractionDigits)
Subtract(IfxDec1, IfxDec2)
Truncate(IfxDec1, FractionDigits)
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
7884ch08.fm
}
}
}
0.0825
1.0
-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.
283
7884ch08.fm
Reason
Solution
System.BadImageFormat
Exception: An attempt was
made to load a program
with an incorrect format
A 32-bit application
loading a 64-bit
IBM.Data.Informix
assembly.
Unhandled Exception:
System.EntryPointNotFou
ndException: Unable to
find an entry point named
'InterlockedIncrement' in
DLL 'kernel32.dll'.
A 64-bit application
loading a 32-bit
IBM.Data.Inforimx.dll
assembly.
Unhandled Exception:
System.DllNotFoundExce
ption: Unable to load DLL
'IfxDotNetIntrinsicModule.
dll': The specified module
could not be found.
Failed to load
IfxDotNetIntrinsicModu
le assembly required by
the 64-bit version of the
Informix .NET provider
Tracing
Your application can set two types of tracing when using the Informix .NET
provider:
Informix .NET Trace
SQLIDEBUG
IBM.Data.Trace.dll.
Register the assembly in the GAC and enable the trace by setting the
environment variables IFXDOTNETTRACE and IFXDOTNETTRACEFILE.
284
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 :
Ceiling Sales Tax :
Negative Sales Tax :
0.0825
1.0
-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
285
7884ch08.fm
IfxConnection.Close
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
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-2 shows the Connection details dialog for a new server
Figure 8-3 shows two of the stores7 database tables dragged into a .NET
DataSet component.
287
7884ch08.fm
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
7884ch09.fm
Chapter 9.
Database connections
Basic database operations like Insert, Delete, Update.
Handling special data types (BLOB, CLOB, TEXT and BYTE)
Exception handling
Troubleshooting
289
7884ch09.fm
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.
290
7884ch09.fm
then there is no problem using the Informix driver. You can also use both drivers
simultaneously if such need arises.
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:
291
7884ch09.fm
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
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.
293
7884ch09.fm
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.
294
7884ch09.fm
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.
295
7884ch09.fm
296
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.
297
7884ch09.fm
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
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";
299
7884ch09.fm
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
7884ch09.fm
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();
301
7884ch09.fm
302
7884ch09.fm
303
7884ch09.fm
304
7884ch09.fm
address_rtype,
char(18)
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 ---*/
305
7884ch09.fm
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 ]
Array ( [CUSTOMER_NUM] => 2 [FNAME] => jones [] => ROW(1234 ,'Almeda blvd ','Fremont
','CA ','12345 ') )
[ DELETE ]
306
7884ch09.fm
307
7884ch09.fm
308
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"]);
309
7884ch09.fm
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
7884ch09.fm
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.
311
7884ch09.fm
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
7884ch09.fm
Description
ifx_connect()
ifx_fieldproperties()
ifxus_open_slob()
ifx_create_blob()
ifx_fetch_row()
ifx_query()
db2_connect()
db2_client_info()
db2_primary_keys()
db2_special_columns()
db2_bind_param()
db2_commit()
Commits a transaction
313
7884ch09.fm
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>
The application can select data from an Informix database using the
ifx_prepare() and ifx_fetch_row() functions.
314
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>
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.
315
7884ch09.fm
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
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>
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.
317
7884ch09.fm
<?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
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);
?>
319
7884ch09.fm
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
7884ch09.fm
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
321
7884ch09.fm
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
7884ch10.fm
10
Chapter 10.
323
7884ch10.fm
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.
324
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 Programmers 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.
325
7884ch10.fm
SPL routines
C routines
Java routines
Cast function
Yes
Yes
Yes
Cost function
No
Yes
No
End-user routine
Yes
Yes
Yes
Iterator function
No
Yes
Yes
Negator function
Yes
Yes
Yes
No
Yes
Yes
Parallelizable UDR
No
Yes
Yes
Statistics function
No
Yes
Yes
Selectivity function
No
Yes
No
User-defined aggregate
Yes
Yes
Some
Operator function
Yes
Yes
Yes
Operator-Class function
Yes
Yes
Yes
326
7884ch10.fm
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.
327
7884ch10.fm
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
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.
329
7884ch10.fm
Tip: Although not required, use the DataBlade Developers 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
Programmers 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.
330
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.
331
7884ch10.fm
backorders
1
332
7884ch10.fm
ord_num----1
2
3
4
5
6
7
1001
1002
1003
1004
1005
1006
1007
333
7884ch10.fm
Anthony
Anthony
Margaret
George
Jean
Ludwig
Arnold
ord_lname
Higgins
Higgins
Lawson
Watson
Parmelee
Pauli
Sipes
amt
$250.00
$1355.00
$1904.00
$1416.00
$4864.00
$1200.00
$1696.00
334
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
$INFORMIXDIR/extend/krakatoa/jre
$INFORMIXDIR/extend/krakatoa
$INFORMIXDIR/extend/krakatoa/.jvpprops
/bin
jvm
$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.
335
7884ch10.fm
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;
}
}
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;
336
7884ch10.fm
337
7884ch10.fm
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;
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;
338
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
339
7884ch10.fm
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
7884ch10.fm
341
7884ch10.fm
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.
342
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
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).
343
7884ch10.fm
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
#include
#include
#include
#include
#include
<ifxgls.h>
<mi.h>
<milib.h>
<fcntl.h>
<stdio.h>
<stdlib.h>
344
7884ch10.fm
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
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'));
c2 FROM tclob;
CONTAINS(c2,'pattern') FROM tclob;
CONTAINS(c2,'nopattern') FROM tclob;
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
345
7884ch10.fm
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.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
7884ch10.fm
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
bts.2.00
ifxbuiltins.1.1
ifxmngr
LLD.1.20.UC2
ifxrltree.2.00
mqblade.2.0
krakatoa
Node.2.0
spatial.8.21.UC3
web.4.13.UC4
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.
347
7884ch10.fm
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');
348
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
349
7884ch10.fm
350
Description
Special notes
Large Object
Locator
Available on
standard install
(LLD.1.20.UC2)
MQ DataBlade
Available on
standard install
(mqblade.2.0)
Binary DataBlade
Available on
standard install.
(binaryudt.1.0)
Available on
standard install.
(bts.2.00)
Node DataBlade
Available on
standard install.
(Node.2.0)
Web Feature
Service
Available on
standard install.
(wfs.1.00.UC1)
J/Foundation
krakatoa
Available as a part
of Informix Server
with J/Foundation
ifxbuilt-ins
Available on
standard install
(ifxbuiltins.1.1)
ifxmngr.2.00
Available on
standard UNIX
install
7884ch10.fm
IBM Informix
DataBlade
module name
Description
Special notes
ifxrltree.2.00
Available on
standard install
Image Foundation
No charge
download
Excalibur Text
Search
Geodetic
Spatial
No charge
download
351
7884ch10.fm
IBM Informix
DataBlade
module name
Description
Special notes
TimeSeries
License fee
applies.
Video Foundation
License fee
applies.
Web
352
7884ch10.fm
What is generated
Source
All source code in the coding languages you use for your
DataBlade module objects
Client
Server
Individual language
353
7884ch10.fm
354
7884ch11.fm
11
Chapter 11.
355
7884ch11.fm
356
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.
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):
357
7884ch11.fm
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.
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
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
03/07/2010
03/07/2010
03/07/2010
03/07/2010
03/07/2010
03/07/2010
03/07/2010
19:34
<DIR>
.
19:34
<DIR>
..
19:19
8,383 Changelog
19:19
1,470 COPYRIGHT
19:29
<DIR>
ext
19:35
<DIR>
lib
19:19
4,500 README
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.
359
7884ch11.fm
Numeric
String
DATE
Date
DATETIME
TIME
INTERVAL
Informix::IntervalYTM, Informix::IntervalDTS
DECIMAL, MONEY
BigDecimal
BOOL
TrueClass, FalseClass
BYTE, TEXT
StringIO, String
CLOB, BLOB
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
7884ch11.fm
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
03/07/2010
03/07/2010
03/07/2010
03/07/2010
03/07/2010
03/07/2010
03/07/2010
03/07/2010
03/07/2010
17:30
<DIR>
.
17:30
<DIR>
..
17:30
6,063 CHANGES
17:30
<DIR>
ext
17:30
1,656 init.rb
18:06
<DIR>
lib
17:30
1,088 LICENSE
17:30
299 MANIFEST
17:30
13,402 README
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.
361
7884ch11.fm
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
17/05/2010
30/05/2009
02:16
<DIR>
.
02:16
<DIR>
..
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
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;', '', ''
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:
363
7884ch11.fm
18:02
<DIR>
.
18:02
<DIR>
..
17:01
<DIR>
abstract
17:01
5,235 abstract_adapter.rb
17:01
6,957 db2_adapter.rb
17:01
27,749 firebird_adapter.rb
17:01
30,751 frontbase_adapter.rb
17:30
70,854 ibm_db_adapter.rb
20:06
9,916 informix_adapter.rb
17:01
13,774 mysql_adapter.rb
17:01
11,531 openbase_adapter.rb
17:01
25,897 oracle_adapter.rb
17:01
21,513 postgresql_adapter.rb
17:01
13,162 sqlite_adapter.rb
17:01
22,087 sqlserver_adapter.rb
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
7884ch11.fm
365
7884ch11.fm
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
7884ch11.fm
367
7884ch11.fm
368
7884ch11.fm
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>
369
7884ch11.fm
370
7884ch11.fm
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
371
7884ch11.fm
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/
372
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>
373
7884ch11.fm
Selecting data
The Data Server Ruby driver has several methods that allow retrieving data from
the database, such as fetch_array(), fetch_assoc(), and fetch_row().
374
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
375
7884ch11.fm
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/
376
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/
377
7884ch11.fm
stores
app/controllers
app/helpers
app/models
app/views/layouts
config/environments
components
db
doc
lib
lib/tasks
log
public/images
public/javascripts
public/stylesheets
378
7884ch11.fm
script\generate
script\generate
script\generate
script\generate
model Order
controller Order
model Item
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
379
7884ch11.fm
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
7884ch11.fm
For more information about the changes in Rails 2.x refer to Rails documentation
at
http://rubyonrails.org/documentation
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).
381
7884ch11.fm
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.
382
7884ch11.fm
383
7884ch11.fm
app/controllers
app/helpers
app/models
app/views/layouts
config/environments
config/initializers
384
7884ch11.fm
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
385
7884ch11.fm
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
grant dba to "informix";
...
386
7884ch11.fm
Figure 11-4 on page 388 shows the initial screen of our application brought up
with http://localhost:3000/phonedirs.
387
7884ch11.fm
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
7884ch12.fm
12
Chapter 12.
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
389
7884ch12.fm
390
7884ch12.fm
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:
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.
391
7884ch12.fm
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
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
Description
AXIS2C_HOME
CLASSPATH
DBPATH
INFORMIXDIR
INFORMIXSERVER
INFORMIXSQLHOSTS
JAVA_HOME
PATH
SOA_ERR_LOG
PROGRAM_DESIGN_DBS
393
7884ch12.fm
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.
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
394
Option
Description
check
7884ch12.fm
Option
Description
compile
deploy
force
generate
help
keep
package
silent
version
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
395
7884ch12.fm
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
7884ch12.fm
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
wsdl_path
ws_func
i4gl_func
target_dir
The path where files are stored while the Web service is being
consumed.
target_file
397
7884ch12.fm
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$
398
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.
399
7884ch12.fm
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$
400
7884ch12.fm
+------------------------------------------------------------------------------+
The App serv option is also used to stored specific environment information for
the application server. This information is required because the Axis2 server
401
7884ch12.fm
binary loads the I4GL libraries that might need additional resource files located in
the $INFORMIXDIR directory.
402
7884ch12.fm
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
] |
|
[
] |
|
[
] |
|
[
] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
403
7884ch12.fm
404
7884ch12.fm
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.
405
7884ch12.fm
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
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 ....
407
7884ch12.fm
/tmp/w4gl_informix/state_name_wrap.c ...
/tmp/w4gl_informix/state_name.wsdl ...
/tmp/w4gl_informix/axis2_skel_ws_state_name.h ...
/tmp/w4gl_informix/axis2_svc_skel_ws_state_name.c ...
/tmp/w4gl_informix/services.xml ...
/tmp/w4gl_informix/axis2_skel_ws_state_name.c ...
/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
7884ch12.fm
process, running each individual step with the w4glc may help to diagnose the
reason for the problem.
409
7884ch12.fm
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$
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
7884ch12.fm
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
Figure 12-2 on page 412 shows the Web Services available in our example.
411
7884ch12.fm
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.
412
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());
}
}
}
413
7884ch12.fm
414
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]
415
7884ch12.fm
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
informix@irk:/work/publish$
statename.c_statename.4cf
statename.o
416
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.
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
417
7884ch12.fm
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
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)
419
7884ch12.fm
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
axis2_skel_ws_state_name.h
state_name_wrap.c
axis2_svc_skel_ws_state_name.c state_name.wsdl
informix@irk:/work$
tmpXMLReqFile
ws_state_name.tar
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
7884ch12.fm
Make sure the operations, parameters, and data types are correct for the I4GL
code the function uses.
421
7884ch12.fm
Figure 12-5 on page 422 shows the soapUI program testing the ws_state_name
Web Service.
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.
422
7884ch12.fm
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]
[debug]
[debug]
[debug]
[debug]
[debug]
[debug]
[debug]
...
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*
423
7884ch12.fm
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
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
7884ch13.fm
426
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.
427
7884ch13.fm
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
7884ch13.fm
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.
429
7884ch13.fm
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
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)
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.
431
7884ch13.fm
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.
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
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
433
7884ch13.fm
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
7884ch13.fm
435
7884ch13.fm
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.
436
7884ch13.fm
437
7884ch13.fm
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
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.
439
7884ch13.fm
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
7884ch13.fm
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.
441
7884ch13.fm
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
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.
443
7884ch13.fm
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 decisionsupport queries can degrade.
Table 13-1 lists the MAX_PDQPRIORITY value that you can set.
Table 13-1 MAX_PDQPRIORITY value
Value
100
An integer
between 1-100
444
7884ch13.fm
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
Directory where the classes of the IBM Informix JDBC Driver are
installed.
JVPLOGFILE
JVPPROPFILE
JVPJAVAVM
JVPJAVAHOME
JVMTHREAD
JVPVJAVALIB
JVPCLASSPATH
VPCLASS jvp=n
For additional onconfig parameters and how they relate to development, see
Appendix A, Onconfig parameters on page 453.
445
7884ch13.fm
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.
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
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.
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:
447
7884ch13.fm
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.
448
7884ch13.fm
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
449
7884ch13.fm
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 CPUs 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.
450
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:
HDR
B
S
I
X
U
IX
IS
SIX
Header
Byte lock
Shared
Intent
Exclusive
Update
Intent exclusive
Intent-shared
Shared, Intent exclusive
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
Page
Row
Lock level is
Equals 100002
Database
<10000
ER Pseudo lock
451
7884ch13.fm
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
7884ax01.fm
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 developers 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
7884ax01.fm
454
Onconfig parameters
Storage Space
Path locations
Buffer Movement
BUFFERPOOL,PHYSBUFF, PHYSFILE
Memory Cache
Memory control
NETTYPE, LISTEN_TIMEOUT,
MAX_INCOMPLETE_CONNECTIONS, FASTPOLL,
MULTIPROCESSOR, VPCLASS, SINGLE_CPU_VP,
AUTO_AIOVPS, DIRECT_IO
SQL Control
Transaction control
DEF_TABLE_LOCKMODE, BLOCKTIMEOUT,
TXTIMEOUT, HETERO_COMMIT,
DEADLOCK_TIMEOUT, DYNAMIC_LOGS, LOGBUFF,
LTXHWM, LTXEHWM, TEMPTAB_NOLOG,
AUTO_REPREPARE
Decision support
DS_MAX_QUERIES, DS_TOTAL_MEMORY,
DS_MAX_SCANS, DS_NONPDQ_QUERY_MEM
7884ax02.fm
Appendix B.
Accommodating distributed
transactions
This appendix discusses the use of distributed transactions with an IBM Informix
database server.
455
7884ax02.fm
456
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()
xa_close()
xa_start()
Starts a XA transaction
xa_end()
xa_rollback()
xa_prepare()
xa_commit()
xa_recover()
xa_forget()
xa_complete()
457
7884ax02.fm
#include
#include
#include
#include
<stdio.h>
<stdlib.h>
<ctype.h>
"xa.h"
458
7884ax02.fm
((*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"
459
7884ax02.fm
460
7884ax02.fm
{
printf("Error:
printf("Usage:
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);
**/
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
461
7884ax02.fm
timeout fID
0
0
-- On-Line -- Up 05:04:17
gtl
2
bql
4
data
4D4E4F000000
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
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
463
7884ax02.fm
464
7884bibl.fm
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 Administrators Guide, v11.50, SC23-7748
IBM Informix Guide to SQL: Reference, v11.50, SC23-7750
Embedded SQLJ Users Guide, Version 2.90, G251-2278
IBM Informix Storage Manager Administrators Guide, v2.2, G229-6388
IBM Informix Security Guide, v11.50, SC23-7754
IBM Informix GLS Users Guide, G229-6373
IBM Informix Dynamic Server Administrators 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 Users Guide, v11.50, SC23-9433
IBM Informix Migration Guide, SC23-7758
IBM Informix JDBC Driver Programmers Guide, SC23-9421
IBM Informix ESQL/C Programmers Manual, v3.50, SC23-9420
IBM Data Server Provider for .NET Programmers Guide, SC23-9848
465
7884bibl.fm
IBM Informix Dynamic Server Installation Guide for UNIX, Linux, and Mac OS
X, GC23-7752
IBM Informix DB-Access Users Guide, SC23-9430
IBM Informix ODBC Driver Programmers 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
466
7884bibl.fm
Related publications
467
7884bibl.fm
468
7884IX.fm
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
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
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
7884IX.fm
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 426427
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
G
gem utility 363
generator element 194
get diagnostics statement 144
get() method 199
GetIfxMonthSpan 263
global transaction 456
global transactions 435
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
I
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
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
472
J
jar file 334
Java annotation 185
Java archive file 334
Java class file 188
Java compiler 188
Java interface 11
Java library 187188
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
7884IX.fm
L
label-based access control 21
library file 122
licensing metric 4
limited use socket 45
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 356357
module 14
money 78
msgpath file 341
multimedia capability 7
multiplexed connection 1617
multiplexer 4
N
native-protocol 49
nchar 78
negator function 326
nettype parameter 440
network connection 16
nvarchar 78
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
Q
query optimization 134
query plan 327
query-intensive analytical application 6
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
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
7884IX.fm
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 7778
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
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
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
7884IX.fm
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
Index
477
7884IX.fm
478
7884spine.fm
479
To determine the spine width of a book, you divide the paper PPI into the number of pages in the book. An example is a 250 page book using Plainfield opaque 50#
smooth which has a PPI of 526. Divided 250 by 526 which equals a spine width of .4752". In this case, you would use the .5 spine. Now select the Spine width for
the book and hide the others: Special>Conditional Text>Show/Hide>SpineSize(-->Hide:)>Set . Move the changed Conditional text settings to all files in your
book by opening the book file with the spine.fm still open and File>Import>Formats the Conditional Text Settings (ONLY!) to the book files.
(1.0 spine)
0.875<->1.498
460 <-> 788 pages
7884spine.fm
480
To determine the spine width of a book, you divide the paper PPI into the number of pages in the book. An example is a 250 page book using Plainfield opaque 50#
smooth which has a PPI of 526. Divided 250 by 526 which equals a spine width of .4752". In this case, you would use the .5 spine. Now select the Spine width for
the book and hide the others: Special>Conditional Text>Show/Hide>SpineSize(-->Hide:)>Set . Move the changed Conditional text settings to all files in your
book by opening the book file with the spine.fm still open and File>Import>Formats the Conditional Text Settings (ONLY!) to the book files.
Back cover
Learn application
development with
supported APIs,
drivers, and
interfaces
Understand Informix
supported
programming
environments
Practical examples
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.
ISBN